001package org.apache.maven.wagon.providers.http;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *   http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import org.apache.maven.wagon.Wagon;
023import org.apache.maven.wagon.observers.Debug;
024import org.apache.maven.wagon.repository.Repository;
025import org.codehaus.plexus.PlexusTestCase;
026import org.codehaus.plexus.util.IOUtil;
027import org.eclipse.jetty.server.HttpConfiguration;
028import org.eclipse.jetty.server.HttpConnectionFactory;
029import org.eclipse.jetty.server.Server;
030import org.eclipse.jetty.server.ServerConnector;
031import org.eclipse.jetty.servlet.ServletContextHandler;
032import org.eclipse.jetty.servlet.ServletHolder;
033import org.slf4j.Logger;
034import org.slf4j.LoggerFactory;
035
036import javax.servlet.ServletException;
037import javax.servlet.http.HttpServlet;
038import javax.servlet.http.HttpServletRequest;
039import javax.servlet.http.HttpServletResponse;
040import java.io.File;
041import java.io.FileInputStream;
042import java.io.IOException;
043import java.nio.ByteBuffer;
044import java.nio.channels.SeekableByteChannel;
045import java.nio.file.Files;
046import java.nio.file.OpenOption;
047import java.nio.file.StandardOpenOption;
048
049/**
050 * @author Olivier Lamy
051 */
052public class HugeFileDownloadTest
053    extends PlexusTestCase
054{
055
056    private static final Logger LOGGER = LoggerFactory.getLogger( HugeFileDownloadTest.class );
057
058    private static long HUGE_FILE_SIZE =
059        Integer.valueOf( Integer.MAX_VALUE ).longValue() + Integer.valueOf( Integer.MAX_VALUE ).longValue();
060
061    private Server server;
062    private ServerConnector connector;
063
064    public void testDownloadHugeFileWithContentLength()
065        throws Exception
066    {
067        final File hugeFile = new File( getBasedir(), "target/hugefile.txt" );
068        if ( !hugeFile.exists() || hugeFile.length() < HUGE_FILE_SIZE )
069        {
070            makeHugeFile( hugeFile );
071        }
072
073        server = new Server(  );
074        connector = new ServerConnector( server, new HttpConnectionFactory( new HttpConfiguration() ) );
075        server.addConnector( connector );
076
077        ServletContextHandler root = new ServletContextHandler( ServletContextHandler.SESSIONS );
078        root.setResourceBase( new File( getBasedir(), "target" ).getAbsolutePath() );
079        ServletHolder servletHolder = new ServletHolder( new HttpServlet()
080        {
081            @Override
082            protected void doGet( HttpServletRequest req, HttpServletResponse resp )
083                throws ServletException, IOException
084            {
085                FileInputStream fis = new FileInputStream( hugeFile );
086
087                resp.addHeader( "Content-Length", String.valueOf( hugeFile.length() ) );
088                IOUtil.copy( fis, resp.getOutputStream() );
089                fis.close();
090            }
091        } );
092        root.addServlet( servletHolder, "/*" );
093        server.setHandler( root );
094
095        server.start();
096
097        File dest = null;
098        try
099        {
100            Wagon wagon = getWagon();
101            wagon.connect( new Repository( "id", "http://localhost:" + connector.getLocalPort() ) );
102
103            dest = File.createTempFile( "huge", "txt" );
104
105            LOGGER.info( "Fetching 'hugefile.txt' with content length" );
106            wagon.get( "hugefile.txt", dest );
107
108            assertTrue( dest.length() >= HUGE_FILE_SIZE );
109            LOGGER.info( "The file was successfully fetched" );
110
111            wagon.disconnect();
112        }
113        finally
114        {
115            server.stop();
116            dest.delete();
117            hugeFile.delete();
118        }
119
120    }
121
122    public void testDownloadHugeFileWithChunked()
123        throws Exception
124    {
125        final File hugeFile = new File( getBasedir(), "target/hugefile.txt" );
126        if ( !hugeFile.exists() || hugeFile.length() < HUGE_FILE_SIZE )
127        {
128            makeHugeFile( hugeFile );
129        }
130
131        server = new Server(  );
132        connector = new ServerConnector( server, new HttpConnectionFactory( new HttpConfiguration() ) );
133        server.addConnector( connector );
134
135        ServletContextHandler root = new ServletContextHandler( ServletContextHandler.SESSIONS );
136        root.setResourceBase( new File( getBasedir(), "target" ).getAbsolutePath() );
137        ServletHolder servletHolder = new ServletHolder( new HttpServlet()
138        {
139            @Override
140            protected void doGet( HttpServletRequest req, HttpServletResponse resp )
141                throws ServletException, IOException
142            {
143                FileInputStream fis = new FileInputStream( hugeFile );
144
145                IOUtil.copy( fis, resp.getOutputStream() );
146                fis.close();
147            }
148        } );
149        root.addServlet( servletHolder, "/*" );
150        server.setHandler( root );
151
152        server.start();
153
154        File dest = null;
155        try
156        {
157            Wagon wagon = getWagon();
158            wagon.connect( new Repository( "id", "http://localhost:" + connector.getLocalPort() ) );
159
160            dest = File.createTempFile( "huge", "txt" );
161
162            LOGGER.info( "Fetching 'hugefile.txt' in chunks" );
163            wagon.get( "hugefile.txt", dest );
164
165            assertTrue( dest.length() >= HUGE_FILE_SIZE );
166            LOGGER.info( "The file was successfully fetched" );
167
168            wagon.disconnect();
169        }
170        finally
171        {
172            server.stop();
173            dest.delete();
174            hugeFile.delete();
175        }
176
177    }
178
179    protected Wagon getWagon()
180        throws Exception
181    {
182        Wagon wagon = (Wagon) lookup( Wagon.ROLE, "http" );
183
184        Debug debug = new Debug();
185
186        wagon.addSessionListener( debug );
187
188        return wagon;
189    }
190
191    private void makeHugeFile( File hugeFile )
192        throws Exception
193    {
194        LOGGER.info( "Creating test file" );
195        final ByteBuffer buf = ByteBuffer.allocate( 4 ).putInt( 2 );
196        buf.rewind();
197
198        final OpenOption[] options = { StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW,
199                                       StandardOpenOption.SPARSE };
200
201        try ( final SeekableByteChannel channel = Files.newByteChannel( hugeFile.toPath(), options ) )
202        {
203            channel.position( HUGE_FILE_SIZE );
204            channel.write( buf );
205        }
206        LOGGER.info( "Test file created" );
207    }
208
209}