View Javadoc

1   package org.apache.maven.wagon.http;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.maven.wagon.FileTestUtils;
23  import org.apache.maven.wagon.ResourceDoesNotExistException;
24  import org.apache.maven.wagon.StreamingWagon;
25  import org.apache.maven.wagon.StreamingWagonTestCase;
26  import org.apache.maven.wagon.TransferFailedException;
27  import org.apache.maven.wagon.Wagon;
28  import org.apache.maven.wagon.authentication.AuthenticationInfo;
29  import org.apache.maven.wagon.authorization.AuthorizationException;
30  import org.apache.maven.wagon.proxy.ProxyInfo;
31  import org.apache.maven.wagon.repository.Repository;
32  import org.apache.maven.wagon.resource.Resource;
33  import org.codehaus.plexus.util.FileUtils;
34  import org.codehaus.plexus.util.IOUtil;
35  import org.codehaus.plexus.util.StringOutputStream;
36  import org.codehaus.plexus.util.StringUtils;
37  import org.mortbay.jetty.Handler;
38  import org.mortbay.jetty.HttpConnection;
39  import org.mortbay.jetty.Request;
40  import org.mortbay.jetty.Response;
41  import org.mortbay.jetty.Server;
42  import org.mortbay.jetty.handler.AbstractHandler;
43  import org.mortbay.jetty.handler.HandlerCollection;
44  import org.mortbay.jetty.security.Constraint;
45  import org.mortbay.jetty.security.ConstraintMapping;
46  import org.mortbay.jetty.security.HashUserRealm;
47  import org.mortbay.jetty.security.SecurityHandler;
48  import org.mortbay.jetty.servlet.Context;
49  import org.mortbay.jetty.servlet.DefaultServlet;
50  import org.mortbay.jetty.servlet.ServletHolder;
51  
52  import javax.servlet.ServletException;
53  import javax.servlet.ServletInputStream;
54  import javax.servlet.http.HttpServletRequest;
55  import javax.servlet.http.HttpServletResponse;
56  import java.io.File;
57  import java.io.FileInputStream;
58  import java.io.FileOutputStream;
59  import java.io.IOException;
60  import java.io.OutputStream;
61  import java.lang.reflect.Method;
62  import java.net.URLDecoder;
63  import java.util.ArrayList;
64  import java.util.Collections;
65  import java.util.Enumeration;
66  import java.util.HashMap;
67  import java.util.List;
68  import java.util.Map;
69  import java.util.Properties;
70  import java.util.zip.GZIPOutputStream;
71  
72  /**
73   * @version $Id: LightweightHttpWagonTest.java 680764 2008-07-29 16:45:51Z brett $
74   */
75  public abstract class HttpWagonTestCase
76      extends StreamingWagonTestCase
77  {
78      private Server server;
79  
80      protected void setupWagonTestingFixtures()
81          throws Exception
82      {
83          // File round trip testing
84  
85          File file = FileTestUtils.createUniqueFile( "local-repository", "test-resource" );
86  
87          file.delete();
88  
89          file.getParentFile().mkdirs();
90  
91          File repositoryDirectory = getRepositoryDirectory();
92          FileUtils.deleteDirectory( repositoryDirectory );
93          repositoryDirectory.mkdirs();
94  
95          server = new Server( 0 );
96  
97          PutHandler putHandler = new PutHandler( repositoryDirectory );
98          server.addHandler( putHandler );
99  
100         createContext( server, repositoryDirectory );
101 
102         addConnectors( server );
103 
104         server.start();
105 
106         testRepository.setUrl( getTestRepositoryUrl() );
107     }
108 
109     @Override
110     protected final int getTestRepositoryPort()
111     {
112         if ( server == null )
113         {
114             return 0;
115         }
116         return server.getConnectors()[0].getLocalPort();
117     }
118 
119     protected void createContext( Server server, File repositoryDirectory )
120         throws IOException
121     {
122         Context root = new Context( server, "/", Context.SESSIONS );
123         root.setResourceBase( repositoryDirectory.getAbsolutePath() );
124         ServletHolder servletHolder = new ServletHolder( new DefaultServlet() );
125         root.addServlet( servletHolder, "/*" );
126     }
127 
128     protected void tearDownWagonTestingFixtures()
129         throws Exception
130     {
131         server.stop();
132     }
133 
134     public void testWagonGetFileList()
135         throws Exception
136     {
137         File dir = getRepositoryDirectory();
138         FileUtils.deleteDirectory( dir );
139 
140         File f = new File( dir, "file-list" );
141         f.mkdirs();
142 
143         super.testWagonGetFileList();
144     }
145 
146     public void testHttpHeaders()
147         throws Exception
148     {
149         Properties properties = new Properties();
150         properties.setProperty( "User-Agent", "Maven-Wagon/1.0" );
151 
152         StreamingWagon wagon = (StreamingWagon) getWagon();
153 
154         setHttpHeaders( wagon, properties );
155 
156         Server server = new Server( 0 );
157         TestHeaderHandler handler = new TestHeaderHandler();
158         server.setHandler( handler );
159         addConnectors( server );
160         server.start();
161 
162         wagon.connect(
163             new Repository( "id", getProtocol() + "://localhost:" + server.getConnectors()[0].getLocalPort() ) );
164 
165         wagon.getToStream( "resource", new StringOutputStream() );
166 
167         wagon.disconnect();
168 
169         server.stop();
170 
171         assertEquals( "Maven-Wagon/1.0", handler.headers.get( "User-Agent" ) );
172     }
173 
174     /**
175      * test set of User-Agent as it's done by aether wagon connector with using setHttpHeaders
176      */
177     public void testHttpHeadersWithCommonMethods()
178         throws Exception
179     {
180         Properties properties = new Properties();
181         properties.setProperty( "User-Agent", "Maven-Wagon/1.0" );
182 
183         StreamingWagon wagon = (StreamingWagon) getWagon();
184 
185         Method setHttpHeaders = wagon.getClass().getMethod( "setHttpHeaders", Properties.class );
186         setHttpHeaders.invoke( wagon, properties );
187 
188         Server server = new Server( 0 );
189         TestHeaderHandler handler = new TestHeaderHandler();
190         server.setHandler( handler );
191         addConnectors( server );
192         server.start();
193 
194         wagon.connect(
195             new Repository( "id", getProtocol() + "://localhost:" + server.getConnectors()[0].getLocalPort() ) );
196 
197         wagon.getToStream( "resource", new StringOutputStream() );
198 
199         wagon.disconnect();
200 
201         server.stop();
202 
203         assertEquals( "Maven-Wagon/1.0", handler.headers.get( "User-Agent" ) );
204     }
205 
206     protected abstract void setHttpHeaders( StreamingWagon wagon, Properties properties );
207 
208     protected void addConnectors( Server server )
209     {
210     }
211 
212     protected String getRepositoryUrl( Server server )
213     {
214         int localPort = server.getConnectors()[0].getLocalPort();
215         return getProtocol() + "://localhost:" + localPort;
216     }
217 
218     public void testGetForbidden()
219         throws Exception
220     {
221         try
222         {
223             runTestGet( HttpServletResponse.SC_FORBIDDEN );
224             fail();
225         }
226         catch ( AuthorizationException e )
227         {
228             assertTrue( true );
229         }
230     }
231 
232     public void testGet404()
233         throws Exception
234     {
235         try
236         {
237             runTestGet( HttpServletResponse.SC_NOT_FOUND );
238             fail();
239         }
240         catch ( ResourceDoesNotExistException e )
241         {
242             assertTrue( true );
243         }
244     }
245 
246     public void testGet500()
247         throws Exception
248     {
249         try
250         {
251             runTestGet( HttpServletResponse.SC_INTERNAL_SERVER_ERROR );
252             fail();
253         }
254         catch ( TransferFailedException e )
255         {
256             assertTrue( true );
257         }
258     }
259 
260     private void runTestGet( int status )
261         throws Exception
262     {
263         StreamingWagon wagon = (StreamingWagon) getWagon();
264 
265         Server server = new Server( 0 );
266         StatusHandler handler = new StatusHandler();
267         handler.setStatusToReturn( status );
268         server.setHandler( handler );
269         addConnectors( server );
270         server.start();
271 
272         wagon.connect( new Repository( "id", getRepositoryUrl( server ) ) );
273 
274         try
275         {
276             wagon.getToStream( "resource", new StringOutputStream() );
277             fail();
278         }
279         finally
280         {
281             wagon.disconnect();
282 
283             server.stop();
284         }
285     }
286 
287     public void testResourceExistsForbidden()
288         throws Exception
289     {
290         try
291         {
292             runTestResourceExists( HttpServletResponse.SC_FORBIDDEN );
293             fail();
294         }
295         catch ( AuthorizationException e )
296         {
297             assertTrue( true );
298         }
299     }
300 
301     public void testResourceExists404()
302         throws Exception
303     {
304         try
305         {
306             assertFalse( runTestResourceExists( HttpServletResponse.SC_NOT_FOUND ) );
307         }
308         catch ( ResourceDoesNotExistException e )
309         {
310             assertTrue( true );
311         }
312     }
313 
314     public void testResourceExists500()
315         throws Exception
316     {
317         try
318         {
319             runTestResourceExists( HttpServletResponse.SC_INTERNAL_SERVER_ERROR );
320             fail();
321         }
322         catch ( TransferFailedException e )
323         {
324             assertTrue( true );
325         }
326     }
327 
328     private boolean runTestResourceExists( int status )
329         throws Exception
330     {
331         StreamingWagon wagon = (StreamingWagon) getWagon();
332 
333         Server server = new Server( 0 );
334         StatusHandler handler = new StatusHandler();
335         handler.setStatusToReturn( status );
336         server.setHandler( handler );
337         addConnectors( server );
338         server.start();
339 
340         wagon.connect( new Repository( "id", getRepositoryUrl( server ) ) );
341 
342         try
343         {
344             return wagon.resourceExists( "resource" );
345         }
346         finally
347         {
348             wagon.disconnect();
349 
350             server.stop();
351         }
352     }
353 
354     protected long getExpectedLastModifiedOnGet( Repository repository, Resource resource )
355     {
356         File file = new File( getRepositoryDirectory(), resource.getName() );
357         return ( file.lastModified() / 1000 ) * 1000;
358     }
359 
360     protected File getRepositoryDirectory()
361     {
362         return getTestFile( "target/test-output/http-repository" );
363     }
364 
365     public void testGzipGet()
366         throws Exception
367     {
368         Server server = new Server( getTestRepositoryPort() );
369 
370         String localRepositoryPath = FileTestUtils.getTestOutputDir().toString();
371         Context root = new Context( server, "/", Context.SESSIONS );
372         root.setResourceBase( localRepositoryPath );
373         ServletHolder servletHolder = new ServletHolder( new DefaultServlet() );
374         servletHolder.setInitParameter( "gzip", "true" );
375         root.addServlet( servletHolder, "/*" );
376         addConnectors( server );
377         server.start();
378 
379         try
380         {
381             Wagon wagon = getWagon();
382 
383             Repository testRepository = new Repository( "id", getRepositoryUrl( server ) );
384 
385             File sourceFile = new File( localRepositoryPath + "/gzip" );
386 
387             sourceFile.deleteOnExit();
388 
389             String resName = "gzip-res.txt";
390             String sourceContent = writeTestFileGzip( sourceFile, resName );
391 
392             wagon.connect( testRepository );
393 
394             File destFile = FileTestUtils.createUniqueFile( getName(), getName() );
395 
396             destFile.deleteOnExit();
397 
398             wagon.get( "gzip/" + resName, destFile );
399 
400             wagon.disconnect();
401 
402             String destContent = FileUtils.fileRead( destFile );
403 
404             assertEquals( sourceContent, destContent );
405         }
406         finally
407         {
408             server.stop();
409         }
410     }
411 
412     public void testProxiedRequest()
413         throws Exception
414     {
415         ProxyInfo proxyInfo = createProxyInfo();
416         TestHeaderHandler handler = new TestHeaderHandler();
417 
418         runTestProxiedRequest( proxyInfo, handler );
419     }
420 
421     public void testProxiedRequestWithAuthentication()
422         throws Exception
423     {
424         ProxyInfo proxyInfo = createProxyInfo();
425         proxyInfo.setUserName( "user" );
426         proxyInfo.setPassword( "secret" );
427         AuthorizingProxyHandler handler = new AuthorizingProxyHandler();
428 
429         runTestProxiedRequest( proxyInfo, handler );
430 
431         assertTrue( handler.headers.containsKey( "Proxy-Authorization" ) );
432 
433         if ( supportProxyPreemptiveAuthentication() )
434         {
435             assertEquals( 200, handler.securityHandlerRequestReponses.get( 0 ).responseCode );
436         }
437         else
438         {
439             assertEquals( 407, handler.securityHandlerRequestReponses.get( 0 ).responseCode );
440             assertEquals( 200, handler.securityHandlerRequestReponses.get( 1 ).responseCode );
441         }
442 
443     }
444 
445     private void runTestProxiedRequest( ProxyInfo proxyInfo, TestHeaderHandler handler )
446         throws Exception
447     {
448         // what an UGLY hack!
449         // but apparently jetty needs some time to free up resources
450         // <5s: broken test :(
451         Thread.sleep( 5001L );
452 
453         Server proxyServer = new Server( 0 );
454 
455         proxyServer.setHandler( handler );
456 
457         proxyServer.start();
458 
459         proxyInfo.setPort( proxyServer.getConnectors()[0].getLocalPort() );
460 
461         System.out.println(
462             "start proxy on host/port " + proxyInfo.getHost() + "/" + proxyInfo.getPort() + " with non proxyHosts "
463                 + proxyInfo.getNonProxyHosts() );
464 
465         while ( !proxyServer.isRunning() || !proxyServer.isStarted() )
466         {
467             Thread.sleep( 10 );
468         }
469 
470         try
471         {
472             StreamingWagon wagon = (StreamingWagon) getWagon();
473 
474             System.out.println( " wagon hashCode " + wagon.hashCode() );
475 
476             Repository testRepository = new Repository( "id", "http://www.example.com/" );
477 
478             String localRepositoryPath = FileTestUtils.getTestOutputDir().toString();
479             File sourceFile = new File( localRepositoryPath, "test-proxied-resource" );
480             FileUtils.fileWrite( sourceFile.getAbsolutePath(), "content" );
481 
482             wagon.connect( testRepository, proxyInfo );
483 
484             StringOutputStream out = new StringOutputStream();
485             try
486             {
487                 wagon.getToStream( "test-proxied-resource", out );
488 
489                 assertTrue( handler.headers.containsKey( "Proxy-Connection" ) );
490             }
491             finally
492             {
493                 System.setProperty( "http.proxyHost", "" );
494                 System.setProperty( "http.proxyPort", "" );
495                 wagon.disconnect();
496             }
497         }
498         finally
499         {
500             proxyServer.stop();
501         }
502     }
503 
504     private ProxyInfo createProxyInfo()
505     {
506         ProxyInfo proxyInfo = new ProxyInfo();
507         proxyInfo.setHost( "localhost" );
508         proxyInfo.setNonProxyHosts( null );
509         proxyInfo.setType( "http" );
510         return proxyInfo;
511     }
512 
513     public void testSecuredGetUnauthorized()
514         throws Exception
515     {
516         try
517         {
518             runTestSecuredGet( null );
519             fail();
520         }
521         catch ( AuthorizationException e )
522         {
523             assertTrue( true );
524         }
525     }
526 
527     public void testSecuredGetWrongPassword()
528         throws Exception
529     {
530         try
531         {
532             AuthenticationInfo authInfo = new AuthenticationInfo();
533             authInfo.setUserName( "user" );
534             authInfo.setPassword( "admin" );
535             runTestSecuredGet( authInfo );
536             fail();
537         }
538         catch ( AuthorizationException e )
539         {
540             assertTrue( true );
541         }
542     }
543 
544     public void testSecuredGet()
545         throws Exception
546     {
547         AuthenticationInfo authInfo = new AuthenticationInfo();
548         authInfo.setUserName( "user" );
549         authInfo.setPassword( "secret" );
550         runTestSecuredGet( authInfo );
551     }
552 
553     public void runTestSecuredGet( AuthenticationInfo authInfo )
554         throws Exception
555     {
556         String localRepositoryPath = FileTestUtils.getTestOutputDir().toString();
557         Server server = createSecurityServer( localRepositoryPath );
558         server.start();
559 
560         try
561         {
562             StreamingWagon wagon = (StreamingWagon) getWagon();
563 
564             Repository testRepository = new Repository( "id", getRepositoryUrl( server ) );
565 
566             File sourceFile = new File( localRepositoryPath, "test-secured-resource" );
567             FileUtils.fileWrite( sourceFile.getAbsolutePath(), "top secret" );
568 
569             wagon.connect( testRepository, authInfo );
570 
571             StringOutputStream out = new StringOutputStream();
572             try
573             {
574                 wagon.getToStream( "test-secured-resource", out );
575             }
576             finally
577             {
578                 wagon.disconnect();
579             }
580 
581             assertEquals( "top secret", out.toString() );
582         }
583         finally
584         {
585             server.stop();
586         }
587     }
588 
589     public void testSecuredResourceExistsUnauthorized()
590         throws Exception
591     {
592         try
593         {
594             runTestSecuredResourceExists( null );
595             fail();
596         }
597         catch ( AuthorizationException e )
598         {
599             assertTrue( true );
600         }
601     }
602 
603     public void testSecuredResourceExistsWrongPassword()
604         throws Exception
605     {
606         try
607         {
608             AuthenticationInfo authInfo = new AuthenticationInfo();
609             authInfo.setUserName( "user" );
610             authInfo.setPassword( "admin" );
611             runTestSecuredResourceExists( authInfo );
612         }
613         catch ( AuthorizationException e )
614         {
615             assertTrue( true );
616         }
617     }
618 
619     public void testSecuredResourceExists()
620         throws Exception
621     {
622         AuthenticationInfo authInfo = new AuthenticationInfo();
623         authInfo.setUserName( "user" );
624         authInfo.setPassword( "secret" );
625         runTestSecuredResourceExists( authInfo );
626     }
627 
628     public void runTestSecuredResourceExists( AuthenticationInfo authInfo )
629         throws Exception
630     {
631         String localRepositoryPath = FileTestUtils.getTestOutputDir().toString();
632         Server server = createSecurityServer( localRepositoryPath );
633         server.start();
634 
635         try
636         {
637             StreamingWagon wagon = (StreamingWagon) getWagon();
638 
639             Repository testRepository = new Repository( "id", getRepositoryUrl( server ) );
640 
641             File sourceFile = new File( localRepositoryPath, "test-secured-resource-exists" );
642             FileUtils.fileWrite( sourceFile.getAbsolutePath(), "top secret" );
643 
644             wagon.connect( testRepository, authInfo );
645 
646             try
647             {
648                 assertTrue( wagon.resourceExists( "test-secured-resource-exists" ) );
649 
650                 assertFalse( wagon.resourceExists( "test-secured-resource-not-exists" ) );
651             }
652             finally
653             {
654                 wagon.disconnect();
655             }
656         }
657         finally
658         {
659             server.stop();
660         }
661     }
662 
663     private Server createSecurityServer( String localRepositoryPath )
664     {
665         Server server = new Server( 0 );
666 
667         SecurityHandler sh = createSecurityHandler();
668 
669         Context root = new Context( Context.SESSIONS );
670         root.setContextPath( "/" );
671         root.addHandler( sh );
672         root.setResourceBase( localRepositoryPath );
673         ServletHolder servletHolder = new ServletHolder( new DefaultServlet() );
674         root.addServlet( servletHolder, "/*" );
675 
676         server.setHandler( root );
677         addConnectors( server );
678         return server;
679     }
680 
681 
682     private String writeTestFileGzip( File parent, String child )
683         throws IOException
684     {
685         File file = new File( parent, child );
686         file.getParentFile().mkdirs();
687         file.deleteOnExit();
688         OutputStream out = new FileOutputStream( file );
689         try
690         {
691             out.write( child.getBytes() );
692         }
693         finally
694         {
695             out.close();
696         }
697 
698         file = new File( parent, child + ".gz" );
699         file.deleteOnExit();
700         String content;
701         out = new FileOutputStream( file );
702         out = new GZIPOutputStream( out );
703         try
704         {
705             // write out different data than non-gz file, so we can
706             // assert the gz version was returned
707             content = file.getAbsolutePath();
708             out.write( content.getBytes() );
709         }
710         finally
711         {
712             out.close();
713         }
714 
715         return content;
716     }
717 
718     public void testPutForbidden()
719         throws Exception
720     {
721         try
722         {
723             runTestPut( HttpServletResponse.SC_FORBIDDEN );
724             fail();
725         }
726         catch ( AuthorizationException e )
727         {
728             assertTrue( true );
729         }
730     }
731 
732     public void testPut404()
733         throws Exception
734     {
735         try
736         {
737             runTestPut( HttpServletResponse.SC_NOT_FOUND );
738             fail();
739         }
740         catch ( ResourceDoesNotExistException e )
741         {
742             assertTrue( true );
743         }
744     }
745 
746     public void testPut500()
747         throws Exception
748     {
749         try
750         {
751             runTestPut( HttpServletResponse.SC_INTERNAL_SERVER_ERROR );
752             fail();
753         }
754         catch ( TransferFailedException e )
755         {
756             assertTrue( true );
757         }
758     }
759 
760     private void runTestPut( int status )
761         throws Exception
762     {
763         StreamingWagon wagon = (StreamingWagon) getWagon();
764 
765         Server server = new Server( 0 );
766         StatusHandler handler = new StatusHandler();
767         handler.setStatusToReturn( status );
768         server.setHandler( handler );
769         addConnectors( server );
770         server.start();
771 
772         wagon.connect( new Repository( "id", getRepositoryUrl( server ) ) );
773 
774         File tempFile = File.createTempFile( "wagon", "tmp" );
775         tempFile.deleteOnExit();
776         FileUtils.fileWrite( tempFile.getAbsolutePath(), "content" );
777 
778         try
779         {
780             wagon.put( tempFile, "resource" );
781             fail();
782         }
783         finally
784         {
785             wagon.disconnect();
786 
787             server.stop();
788 
789             tempFile.delete();
790         }
791     }
792 
793     public void testSecuredPutUnauthorized()
794         throws Exception
795     {
796         try
797         {
798             runTestSecuredPut( null );
799             fail();
800         }
801         catch ( TransferFailedException e )
802         {
803             assertTrue( true );
804         }
805     }
806 
807     public void testSecuredPutWrongPassword()
808         throws Exception
809     {
810         try
811         {
812             AuthenticationInfo authInfo = new AuthenticationInfo();
813             authInfo.setUserName( "user" );
814             authInfo.setPassword( "admin" );
815             runTestSecuredPut( authInfo );
816             fail();
817         }
818         catch ( TransferFailedException e )
819         {
820             assertTrue( true );
821         }
822     }
823 
824     public void testSecuredPut()
825         throws Exception
826     {
827         AuthenticationInfo authInfo = new AuthenticationInfo();
828         authInfo.setUserName( "user" );
829         authInfo.setPassword( "secret" );
830         runTestSecuredPut( authInfo );
831     }
832 
833     public void runTestSecuredPut( AuthenticationInfo authInfo )
834         throws Exception
835     {
836         runTestSecuredPut( authInfo, 1 );
837     }
838 
839     public void runTestSecuredPut( AuthenticationInfo authInfo, int putNumber )
840         throws Exception
841     {
842         String localRepositoryPath = FileTestUtils.getTestOutputDir().toString();
843         Server server = new Server( 0 );
844 
845         TestSecurityHandler sh = createSecurityHandler();
846 
847         PutHandler putHandler = new PutHandler( new File( localRepositoryPath ) );
848 
849         HandlerCollection handlers = new HandlerCollection();
850         handlers.setHandlers( new Handler[]{ sh, putHandler } );
851 
852         server.setHandler( handlers );
853         addConnectors( server );
854         server.start();
855 
856         StreamingWagon wagon = (StreamingWagon) getWagon();
857         Repository testRepository = new Repository( "id", getRepositoryUrl( server ) );
858         wagon.connect( testRepository, authInfo );
859         try
860         {
861             for ( int i = 0; i < putNumber; i++ )
862             {
863                 File sourceFile = new File( localRepositoryPath, "test-secured-put-resource" );
864                 sourceFile.delete();
865                 assertFalse( sourceFile.exists() );
866 
867                 File tempFile = File.createTempFile( "wagon", "tmp" );
868                 tempFile.deleteOnExit();
869                 FileUtils.fileWrite( tempFile.getAbsolutePath(), "put top secret" );
870 
871                 try
872                 {
873                     wagon.put( tempFile, "test-secured-put-resource" );
874                 }
875                 finally
876                 {
877                     tempFile.delete();
878                 }
879 
880                 assertEquals( "put top secret", FileUtils.fileRead( sourceFile.getAbsolutePath() ) );
881             }
882         }
883         finally
884         {
885             wagon.disconnect();
886             server.stop();
887         }
888         assertEquals( putNumber, putHandler.putCallNumber );
889         testPreemptiveAuthentication( sh );
890     }
891 
892     public void testNonSecuredPutFromStream()
893         throws Exception
894     {
895         AuthenticationInfo authInfo = new AuthenticationInfo();
896         authInfo.setUserName( "user" );
897         authInfo.setPassword( "secret" );
898         runTestSecuredPutFromStream( authInfo, 1, false );
899     }
900 
901     public void testSecuredPutFromStream()
902         throws Exception
903     {
904         AuthenticationInfo authInfo = new AuthenticationInfo();
905         authInfo.setUserName( "user" );
906         authInfo.setPassword( "secret" );
907         runTestSecuredPutFromStream( authInfo, 1, true );
908     }
909 
910     public void runTestSecuredPutFromStream( AuthenticationInfo authInfo, int putNumber, boolean addSecurityHandler )
911         throws Exception
912     {
913         String localRepositoryPath = FileTestUtils.getTestOutputDir().toString();
914         Server server = new Server( 0 );
915 
916         TestSecurityHandler sh = createSecurityHandler();
917 
918         PutHandler putHandler = new PutHandler( new File( localRepositoryPath ) );
919 
920         HandlerCollection handlers = new HandlerCollection();
921         handlers.setHandlers( addSecurityHandler ? new Handler[]{ sh, putHandler } : new Handler[]{ putHandler } );
922 
923         server.setHandler( handlers );
924         addConnectors( server );
925         server.start();
926 
927         StreamingWagon wagon = (StreamingWagon) getWagon();
928         Repository testRepository = new Repository( "id", getRepositoryUrl( server ) );
929         if ( addSecurityHandler )
930         {
931             wagon.connect( testRepository, authInfo );
932         }
933         else
934         {
935             wagon.connect( testRepository );
936         }
937         try
938         {
939             for ( int i = 0; i < putNumber; i++ )
940             {
941                 File sourceFile = new File( localRepositoryPath, "test-secured-put-resource" );
942                 sourceFile.delete();
943                 assertFalse( sourceFile.exists() );
944 
945                 File tempFile = File.createTempFile( "wagon", "tmp" );
946                 tempFile.deleteOnExit();
947                 String content = "put top secret";
948                 FileUtils.fileWrite( tempFile.getAbsolutePath(), content );
949 
950                 FileInputStream fileInputStream = new FileInputStream( tempFile );
951                 try
952                 {
953                     wagon.putFromStream( fileInputStream, "test-secured-put-resource", content.length(), -1 );
954                 }
955                 finally
956                 {
957                     fileInputStream.close();
958                     tempFile.delete();
959 
960                 }
961 
962                 assertEquals( content, FileUtils.fileRead( sourceFile.getAbsolutePath() ) );
963             }
964         }
965         finally
966         {
967             wagon.disconnect();
968             server.stop();
969         }
970         assertEquals( putNumber, putHandler.putCallNumber );
971         if ( addSecurityHandler )
972         {
973             testPreemptiveAuthentication( sh );
974         }
975 
976         // ensure we didn't use chunked transfer which doesn't work on ngnix
977         for ( DeployedResource deployedResource : putHandler.deployedResources )
978         {
979             if ( StringUtils.equalsIgnoreCase( "chunked", deployedResource.transferEncoding ) )
980             {
981                 fail( "deployedResource use chunked: " + deployedResource );
982             }
983         }
984     }
985 
986 
987     protected abstract boolean supportPreemptiveAuthentication();
988 
989     protected boolean supportProxyPreemptiveAuthentication()
990     {
991         return false;
992     }
993 
994     protected void testPreemptiveAuthentication( TestSecurityHandler sh )
995     {
996 
997         if ( supportPreemptiveAuthentication() )
998         {
999             assertEquals( "not 1 security handler use " + sh.securityHandlerRequestReponses, 1,
1000                           sh.securityHandlerRequestReponses.size() );
1001             assertEquals( 200, sh.securityHandlerRequestReponses.get( 0 ).responseCode );
1002         }
1003         else
1004         {
1005             assertEquals( "not 2 security handler use " + sh.securityHandlerRequestReponses, 2,
1006                           sh.securityHandlerRequestReponses.size() );
1007             assertEquals( 401, sh.securityHandlerRequestReponses.get( 0 ).responseCode );
1008             assertEquals( 200, sh.securityHandlerRequestReponses.get( 1 ).responseCode );
1009 
1010         }
1011     }
1012 
1013     static class StatusHandler
1014         extends AbstractHandler
1015     {
1016         private int status;
1017 
1018         public void setStatusToReturn( int status )
1019         {
1020             this.status = status;
1021         }
1022 
1023         public void handle( String target, HttpServletRequest request, HttpServletResponse response, int dispatch )
1024             throws IOException, ServletException
1025         {
1026             if ( status != 0 )
1027             {
1028                 response.setStatus( status );
1029                 ( (Request) request ).setHandled( true );
1030             }
1031         }
1032     }
1033 
1034     static class DeployedResource
1035     {
1036         String httpMethod;
1037 
1038         String requestUri;
1039 
1040         String contentLength;
1041 
1042         String transferEncoding;
1043 
1044         public DeployedResource()
1045         {
1046             // no op
1047         }
1048 
1049         @Override
1050         public String toString()
1051         {
1052             final StringBuilder sb = new StringBuilder();
1053             sb.append( "DeployedResource" );
1054             sb.append( "{httpMethod='" ).append( httpMethod ).append( '\'' );
1055             sb.append( ", requestUri='" ).append( requestUri ).append( '\'' );
1056             sb.append( ", contentLength='" ).append( contentLength ).append( '\'' );
1057             sb.append( ", transferEncoding='" ).append( transferEncoding ).append( '\'' );
1058             sb.append( '}' );
1059             return sb.toString();
1060         }
1061     }
1062 
1063     static class PutHandler
1064         extends AbstractHandler
1065     {
1066         private final File resourceBase;
1067 
1068         public List<DeployedResource> deployedResources = new ArrayList<DeployedResource>();
1069 
1070         public int putCallNumber = 0;
1071 
1072         public PutHandler( File repositoryDirectory )
1073         {
1074             this.resourceBase = repositoryDirectory;
1075         }
1076 
1077         public void handle( String target, HttpServletRequest request, HttpServletResponse response, int dispatch )
1078             throws IOException, ServletException
1079         {
1080             Request base_request =
1081                 request instanceof Request ? (Request) request : HttpConnection.getCurrentConnection().getRequest();
1082 
1083             if ( base_request.isHandled() || !"PUT".equals( base_request.getMethod() ) )
1084             {
1085                 return;
1086             }
1087 
1088             base_request.setHandled( true );
1089 
1090             File file = new File( resourceBase, URLDecoder.decode( request.getPathInfo() ) );
1091             file.getParentFile().mkdirs();
1092             FileOutputStream out = new FileOutputStream( file );
1093             ServletInputStream in = request.getInputStream();
1094             try
1095             {
1096                 IOUtil.copy( in, out );
1097             }
1098             finally
1099             {
1100                 in.close();
1101                 out.close();
1102             }
1103             System.out.println( "put file " + request.getPathInfo() );
1104             putCallNumber++;
1105             DeployedResource deployedResource = new DeployedResource();
1106 
1107             deployedResource.httpMethod = request.getMethod();
1108             deployedResource.requestUri = request.getRequestURI();
1109             deployedResource.transferEncoding = request.getHeader( "Transfer-Encoding" );
1110             deployedResource.contentLength = request.getHeader( "Content-Length" );
1111             deployedResources.add( deployedResource );
1112 
1113             response.setStatus( HttpServletResponse.SC_CREATED );
1114         }
1115     }
1116 
1117     private static class AuthorizingProxyHandler
1118         extends TestHeaderHandler
1119     {
1120 
1121         List<SecurityHandlerRequestReponse> securityHandlerRequestReponses =
1122             new ArrayList<SecurityHandlerRequestReponse>();
1123 
1124         public void handle( String target, HttpServletRequest request, HttpServletResponse response, int dispatch )
1125             throws IOException, ServletException
1126         {
1127             System.out.println( " handle proxy request" );
1128             if ( request.getHeader( "Proxy-Authorization" ) == null )
1129             {
1130                 securityHandlerRequestReponses.add( new SecurityHandlerRequestReponse( request.getMethod(), 407 ) );
1131                 response.setStatus( 407 );
1132                 response.addHeader( "Proxy-Authenticate", "Basic realm=\"Squid proxy-caching web server\"" );
1133 
1134                 ( (Request) request ).setHandled( true );
1135                 return;
1136             }
1137             securityHandlerRequestReponses.add( new SecurityHandlerRequestReponse( request.getMethod(), 200 ) );
1138             super.handle( target, request, response, dispatch );
1139         }
1140     }
1141 
1142     private static class TestHeaderHandler
1143         extends AbstractHandler
1144     {
1145         public Map headers = Collections.EMPTY_MAP;
1146 
1147         public TestHeaderHandler()
1148         {
1149         }
1150 
1151         public void handle( String target, HttpServletRequest request, HttpServletResponse response, int dispatch )
1152             throws IOException, ServletException
1153         {
1154             headers = new HashMap();
1155             for ( Enumeration e = request.getHeaderNames(); e.hasMoreElements(); )
1156             {
1157                 String name = (String) e.nextElement();
1158                 headers.put( name, request.getHeader( name ) );
1159             }
1160 
1161             response.setContentType( "text/plain" );
1162             response.setStatus( HttpServletResponse.SC_OK );
1163             response.getWriter().println( "Hello, World!" );
1164 
1165             ( (Request) request ).setHandled( true );
1166         }
1167 
1168     }
1169 
1170     protected TestSecurityHandler createSecurityHandler()
1171     {
1172         Constraint constraint = new Constraint();
1173         constraint.setName( Constraint.__BASIC_AUTH );
1174         constraint.setRoles( new String[]{ "admin" } );
1175         constraint.setAuthenticate( true );
1176 
1177         ConstraintMapping cm = new ConstraintMapping();
1178         cm.setConstraint( constraint );
1179         cm.setPathSpec( "/*" );
1180 
1181         TestSecurityHandler sh = new TestSecurityHandler();
1182         HashUserRealm hashUserRealm = new HashUserRealm( "MyRealm" );
1183         hashUserRealm.put( "user", "secret" );
1184         hashUserRealm.addUserToRole( "user", "admin" );
1185         sh.setUserRealm( hashUserRealm );
1186         sh.setConstraintMappings( new ConstraintMapping[]{ cm } );
1187         return sh;
1188     }
1189 
1190     public static class TestSecurityHandler
1191         extends SecurityHandler
1192     {
1193 
1194         public List<SecurityHandlerRequestReponse> securityHandlerRequestReponses =
1195             new ArrayList<SecurityHandlerRequestReponse>();
1196 
1197         @Override
1198         public void handle( String target, HttpServletRequest request, HttpServletResponse response, int dispatch )
1199             throws IOException, ServletException
1200         {
1201             String method = request.getMethod();
1202             super.handle( target, request, response, dispatch );
1203             System.out.println( "method in SecurityHandler: " + method );
1204 
1205             securityHandlerRequestReponses.add(
1206                 new SecurityHandlerRequestReponse( method, ( (Response) response ).getStatus() ) );
1207         }
1208 
1209     }
1210 
1211     public static class SecurityHandlerRequestReponse
1212     {
1213         public String method;
1214 
1215         public int responseCode;
1216 
1217         private SecurityHandlerRequestReponse( String method, int responseCode )
1218         {
1219             this.method = method;
1220             this.responseCode = responseCode;
1221         }
1222 
1223         @Override
1224         public String toString()
1225         {
1226             final StringBuilder sb = new StringBuilder();
1227             sb.append( "SecurityHandlerRequestReponse" );
1228             sb.append( "{method='" ).append( method ).append( '\'' );
1229             sb.append( ", responseCode=" ).append( responseCode );
1230             sb.append( '}' );
1231             return sb.toString();
1232         }
1233     }
1234 }