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