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}