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