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.proxy.ProxyInfoProvider;
32  import org.apache.maven.wagon.repository.Repository;
33  import org.apache.maven.wagon.resource.Resource;
34  import org.codehaus.plexus.util.FileUtils;
35  import org.codehaus.plexus.util.IOUtil;
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.ByteArrayOutputStream;
57  import java.io.File;
58  import java.io.FileInputStream;
59  import java.io.FileOutputStream;
60  import java.io.IOException;
61  import java.io.OutputStream;
62  import java.lang.reflect.Method;
63  import java.net.URLDecoder;
64  import java.util.ArrayList;
65  import java.util.Collections;
66  import java.util.Enumeration;
67  import java.util.HashMap;
68  import java.util.List;
69  import java.util.Map;
70  import java.util.Properties;
71  import java.util.concurrent.atomic.AtomicBoolean;
72  import java.util.zip.GZIPOutputStream;
73  
74  /**
75   *
76   */
77  public abstract class HttpWagonTestCase
78      extends StreamingWagonTestCase
79  {
80      public static final int SC_TOO_MANY_REQUESTS = 429;
81  
82      private Server server;
83  
84      protected void setupWagonTestingFixtures()
85          throws Exception
86      {
87          // File round trip testing
88  
89          File file = FileTestUtils.createUniqueFile( "local-repository", "test-resource" );
90  
91          file.delete();
92  
93          file.getParentFile().mkdirs();
94  
95          File repositoryDirectory = getRepositoryDirectory();
96          FileUtils.deleteDirectory( repositoryDirectory );
97          repositoryDirectory.mkdirs();
98  
99          server = new Server( 0 );
100 
101         PutHandler putHandler = new PutHandler( repositoryDirectory );
102         server.addHandler( putHandler );
103 
104         createContext( server, repositoryDirectory );
105 
106         addConnectors( server );
107 
108         server.start();
109 
110         testRepository.setUrl( getTestRepositoryUrl() );
111     }
112 
113     @Override
114     protected final int getTestRepositoryPort()
115     {
116         if ( server == null )
117         {
118             return 0;
119         }
120         return server.getConnectors()[0].getLocalPort();
121     }
122 
123     protected void createContext( Server server, File repositoryDirectory )
124         throws IOException
125     {
126         Context root = new Context( server, "/", Context.SESSIONS );
127         root.setResourceBase( repositoryDirectory.getAbsolutePath() );
128         ServletHolder servletHolder = new ServletHolder( new DefaultServlet() );
129         root.addServlet( servletHolder, "/*" );
130     }
131 
132     protected void tearDownWagonTestingFixtures()
133         throws Exception
134     {
135         server.stop();
136     }
137 
138     public void testWagonGetFileList()
139         throws Exception
140     {
141         File dir = getRepositoryDirectory();
142         FileUtils.deleteDirectory( dir );
143 
144         File f = new File( dir, "file-list" );
145         f.mkdirs();
146 
147         super.testWagonGetFileList();
148     }
149 
150     public void testHttpHeaders()
151         throws Exception
152     {
153         Properties properties = new Properties();
154         properties.setProperty( "User-Agent", "Maven-Wagon/1.0" );
155 
156         StreamingWagon wagon = (StreamingWagon) getWagon();
157 
158         setHttpHeaders( wagon, properties );
159 
160         Server server = new Server( 0 );
161         TestHeaderHandler handler = new TestHeaderHandler();
162         server.setHandler( handler );
163         addConnectors( server );
164         server.start();
165 
166         wagon.connect(
167             new Repository( "id", getProtocol() + "://localhost:" + server.getConnectors()[0].getLocalPort() ) );
168 
169         wagon.getToStream( "resource", new ByteArrayOutputStream() );
170 
171         wagon.disconnect();
172 
173         server.stop();
174 
175         assertEquals( "Maven-Wagon/1.0", handler.headers.get( "User-Agent" ) );
176     }
177 
178     /**
179      * test set of User-Agent as it's done by aether wagon connector with using setHttpHeaders
180      */
181     public void testHttpHeadersWithCommonMethods()
182         throws Exception
183     {
184         Properties properties = new Properties();
185         properties.setProperty( "User-Agent", "Maven-Wagon/1.0" );
186 
187         StreamingWagon wagon = (StreamingWagon) getWagon();
188 
189         Method setHttpHeaders = wagon.getClass().getMethod( "setHttpHeaders", Properties.class );
190         setHttpHeaders.invoke( wagon, properties );
191 
192         Server server = new Server( 0 );
193         TestHeaderHandler handler = new TestHeaderHandler();
194         server.setHandler( handler );
195         addConnectors( server );
196         server.start();
197 
198         wagon.connect(
199             new Repository( "id", getProtocol() + "://localhost:" + server.getConnectors()[0].getLocalPort() ) );
200 
201         wagon.getToStream( "resource", new ByteArrayOutputStream() );
202 
203         wagon.disconnect();
204 
205         server.stop();
206 
207         assertEquals( "Maven-Wagon/1.0", handler.headers.get( "User-Agent" ) );
208     }
209 
210     public void testUserAgentHeaderIsPresentByDefault()
211         throws Exception
212     {
213         StreamingWagon wagon = (StreamingWagon) getWagon();
214         Server server = new Server( 0 );
215         TestHeaderHandler handler = new TestHeaderHandler();
216         server.setHandler( handler );
217         addConnectors( server );
218         server.start();
219         wagon.connect( new Repository( "id", getProtocol() + "://localhost:" 
220           + server.getConnectors()[0].getLocalPort() ) );
221         wagon.getToStream( "resource", new ByteArrayOutputStream() );
222         wagon.disconnect();
223         server.stop();
224 
225         assertNotNull( "default User-Agent header of wagon provider should be present",
226                        handler.headers.get( "User-Agent" ) );
227     }
228 
229     public void testUserAgentHeaderIsPresentOnlyOnceIfSetMultipleTimes()
230         throws Exception
231     {
232         StreamingWagon wagon = (StreamingWagon) getWagon();
233 
234         // 1. set User-Agent header via HttpConfiguration
235         Properties headers1 = new Properties();
236         headers1.setProperty( "User-Agent", "test-user-agent" );
237         setHttpHeaders( wagon, headers1 );
238 
239         // 2. redundantly set User-Agent header via setHttpHeaders()
240         Properties headers2 = new Properties();
241         headers2.setProperty( "User-Agent", "test-user-agent" );
242         Method setHttpHeaders = wagon.getClass().getMethod( "setHttpHeaders", Properties.class );
243         setHttpHeaders.invoke( wagon, headers2 );
244 
245         Server server = new Server( 0 );
246         TestHeaderHandler handler = new TestHeaderHandler();
247         server.setHandler( handler );
248         addConnectors( server );
249         server.start();
250         wagon.connect( new Repository( "id", getProtocol() + "://localhost:"
251           + server.getConnectors()[0].getLocalPort() ) );
252         wagon.getToStream( "resource", new ByteArrayOutputStream() );
253         wagon.disconnect();
254         server.stop();
255 
256         assertEquals( "test-user-agent", handler.headers.get( "User-Agent" ) );
257 
258     }
259 
260     protected abstract void setHttpHeaders( StreamingWagon wagon, Properties properties );
261 
262     protected void addConnectors( Server server )
263     {
264     }
265 
266     protected String getRepositoryUrl( Server server )
267     {
268         int localPort = server.getConnectors()[0].getLocalPort();
269         return getProtocol() + "://localhost:" + localPort;
270     }
271 
272     public void testGetForbidden()
273         throws Exception
274     {
275         try
276         {
277             runTestGet( HttpServletResponse.SC_FORBIDDEN );
278             fail();
279         }
280         catch ( AuthorizationException e )
281         {
282             assertTrue( true );
283         }
284     }
285 
286     public void testGet404()
287         throws Exception
288     {
289         try
290         {
291             runTestGet( HttpServletResponse.SC_NOT_FOUND );
292             fail();
293         }
294         catch ( ResourceDoesNotExistException e )
295         {
296             assertTrue( true );
297         }
298     }
299 
300     public void testList429()
301         throws Exception
302     {
303         StreamingWagon wagon = (StreamingWagon) getWagon();
304         try
305         {
306 
307             Server server = new Server( 0 );
308             final AtomicBoolean called = new AtomicBoolean();
309 
310             AbstractHandler handler = new AbstractHandler()
311             {
312                 public void handle( String s, HttpServletRequest request, HttpServletResponse response, int i )
313                     throws IOException, ServletException
314                 {
315                     if ( called.get() )
316                     {
317                         response.setStatus( HttpServletResponse.SC_OK );
318                         ( (Request) request ).setHandled( true );
319                     }
320                     else
321                     {
322                         called.set( true );
323                         response.setStatus( SC_TOO_MANY_REQUESTS );
324                         ( (Request) request ).setHandled( true );
325 
326                     }
327                 }
328             };
329 
330             server.setHandler( handler );
331             addConnectors( server );
332             server.start();
333 
334             wagon.connect( new Repository( "id", getRepositoryUrl( server ) ) );
335 
336             try
337             {
338                 wagon.getFileList( "resource" );
339             }
340             finally
341             {
342                 wagon.disconnect();
343 
344                 server.stop();
345             }
346 
347         }
348         catch ( ResourceDoesNotExistException e )
349         {
350             assertTrue( true );
351         }
352         catch ( TransferFailedException e )
353         {
354             if ( wagon.getClass().getName().contains( "Lightweight" ) )
355             {
356                 //we don't care about lightweight
357                 assertTrue( true );
358             }
359             else
360             {
361                 fail();
362             }
363 
364         }
365     }
366 
367     public void testGet500()
368         throws Exception
369     {
370         try
371         {
372             runTestGet( HttpServletResponse.SC_INTERNAL_SERVER_ERROR );
373             fail();
374         }
375         catch ( TransferFailedException e )
376         {
377             assertTrue( true );
378         }
379     }
380 
381     private void runTestGet( int status )
382         throws Exception
383     {
384         StreamingWagon wagon = (StreamingWagon) getWagon();
385 
386         Server server = new Server( 0 );
387         StatusHandler handler = new StatusHandler();
388         handler.setStatusToReturn( status );
389         server.setHandler( handler );
390         addConnectors( server );
391         server.start();
392 
393         wagon.connect( new Repository( "id", getRepositoryUrl( server ) ) );
394 
395         try
396         {
397             wagon.getToStream( "resource", new ByteArrayOutputStream() );
398             fail();
399         }
400         finally
401         {
402             wagon.disconnect();
403 
404             server.stop();
405         }
406     }
407 
408     public void testResourceExistsForbidden()
409         throws Exception
410     {
411         try
412         {
413             runTestResourceExists( HttpServletResponse.SC_FORBIDDEN );
414             fail();
415         }
416         catch ( AuthorizationException e )
417         {
418             assertTrue( true );
419         }
420     }
421 
422     public void testResourceExists404()
423         throws Exception
424     {
425         try
426         {
427             assertFalse( runTestResourceExists( HttpServletResponse.SC_NOT_FOUND ) );
428         }
429         catch ( ResourceDoesNotExistException e )
430         {
431             assertTrue( true );
432         }
433     }
434 
435     public void testResourceExists500()
436         throws Exception
437     {
438         try
439         {
440             runTestResourceExists( HttpServletResponse.SC_INTERNAL_SERVER_ERROR );
441             fail();
442         }
443         catch ( TransferFailedException e )
444         {
445             assertTrue( true );
446         }
447     }
448 
449     public void testResourceExists429()
450         throws Exception
451     {
452         try
453         {
454 
455             final AtomicBoolean called = new AtomicBoolean();
456 
457             AbstractHandler handler = new AbstractHandler()
458             {
459                 public void handle( String s, HttpServletRequest request, HttpServletResponse response, int i )
460                     throws IOException, ServletException
461                 {
462                     if ( called.get() )
463                     {
464                         response.setStatus( HttpServletResponse.SC_INTERNAL_SERVER_ERROR );
465                         ( (Request) request ).setHandled( true );
466                     }
467                     else
468                     {
469                         called.set( true );
470                         response.setStatus( SC_TOO_MANY_REQUESTS );
471                         ( (Request) request ).setHandled( true );
472                     }
473                 }
474             };
475 
476             StreamingWagon wagon = (StreamingWagon) getWagon();
477             Server server = new Server( 0 );
478             server.setHandler( handler );
479             addConnectors( server );
480             server.start();
481             wagon.connect( new Repository( "id", getRepositoryUrl( server ) ) );
482 
483             try
484             {
485                 wagon.resourceExists( "resource" );
486             }
487             finally
488             {
489                 wagon.disconnect();
490 
491                 server.stop();
492             }
493 
494             fail();
495         }
496         catch ( TransferFailedException e )
497         {
498             assertTrue( true );
499         }
500     }
501 
502 
503     private boolean runTestResourceExists( int status )
504         throws Exception
505     {
506         StreamingWagon wagon = (StreamingWagon) getWagon();
507 
508         Server server = new Server( 0 );
509         StatusHandler handler = new StatusHandler();
510         handler.setStatusToReturn( status );
511         server.setHandler( handler );
512         addConnectors( server );
513         server.start();
514 
515         wagon.connect( new Repository( "id", getRepositoryUrl( server ) ) );
516 
517         try
518         {
519             return wagon.resourceExists( "resource" );
520         }
521         finally
522         {
523             wagon.disconnect();
524 
525             server.stop();
526         }
527     }
528 
529     protected long getExpectedLastModifiedOnGet( Repository repository, Resource resource )
530     {
531         File file = new File( getRepositoryDirectory(), resource.getName() );
532         return ( file.lastModified() / 1000 ) * 1000;
533     }
534 
535     protected File getRepositoryDirectory()
536     {
537         return getTestFile( "target/test-output/http-repository" );
538     }
539 
540     public void testGzipGet()
541         throws Exception
542     {
543         Server server = new Server( getTestRepositoryPort() );
544 
545         String localRepositoryPath = FileTestUtils.getTestOutputDir().toString();
546         Context root = new Context( server, "/", Context.SESSIONS );
547         root.setResourceBase( localRepositoryPath );
548         ServletHolder servletHolder = new ServletHolder( new DefaultServlet() );
549         servletHolder.setInitParameter( "gzip", "true" );
550         root.addServlet( servletHolder, "/*" );
551         addConnectors( server );
552         server.start();
553 
554         try
555         {
556             Wagon wagon = getWagon();
557 
558             Repository testRepository = new Repository( "id", getRepositoryUrl( server ) );
559 
560             File sourceFile = new File( localRepositoryPath + "/gzip" );
561 
562             sourceFile.deleteOnExit();
563 
564             String resName = "gzip-res.txt";
565             String sourceContent = writeTestFileGzip( sourceFile, resName );
566 
567             wagon.connect( testRepository );
568 
569             File destFile = FileTestUtils.createUniqueFile( getName(), getName() );
570 
571             destFile.deleteOnExit();
572 
573             wagon.get( "gzip/" + resName, destFile );
574 
575             wagon.disconnect();
576 
577             String destContent = FileUtils.fileRead( destFile );
578 
579             assertEquals( sourceContent, destContent );
580         }
581         finally
582         {
583             server.stop();
584         }
585     }
586 
587     public void testProxiedRequest()
588         throws Exception
589     {
590         ProxyInfo proxyInfo = createProxyInfo();
591         TestHeaderHandler handler = new TestHeaderHandler();
592 
593         runTestProxiedRequest( proxyInfo, handler );
594     }
595 
596     public void testProxiedRequestWithAuthentication()
597         throws Exception
598     {
599         ProxyInfo proxyInfo = createProxyInfo();
600         proxyInfo.setUserName( "user" );
601         proxyInfo.setPassword( "secret" );
602         AuthorizingProxyHandler handler = new AuthorizingProxyHandler();
603 
604         runTestProxiedRequest( proxyInfo, handler );
605 
606         assertTrue( handler.headers.containsKey( "Proxy-Authorization" ) );
607 
608         if ( supportProxyPreemptiveAuthentication() )
609         {
610             assertEquals( HttpServletResponse.SC_OK, handler.handlerRequestResponses.get( 0 ).responseCode );
611         }
612         else
613         {
614             assertEquals( HttpServletResponse.SC_PROXY_AUTHENTICATION_REQUIRED,
615                           handler.handlerRequestResponses.get( 0 ).responseCode );
616             assertEquals( HttpServletResponse.SC_OK, handler.handlerRequestResponses.get( 1 ).responseCode );
617         }
618 
619     }
620 
621     public void testProxiedRequestWithAuthenticationWithProvider()
622         throws Exception
623     {
624         final ProxyInfo proxyInfo = createProxyInfo();
625         proxyInfo.setUserName( "user" );
626         proxyInfo.setPassword( "secret" );
627         AuthorizingProxyHandler handler = new AuthorizingProxyHandler();
628 
629         ProxyInfoProvider proxyInfoProvider = new ProxyInfoProvider()
630         {
631             public ProxyInfo getProxyInfo( String protocol )
632             {
633                 return proxyInfo;
634             }
635         };
636         runTestProxiedRequestWithProvider( proxyInfoProvider, handler );
637 
638         assertTrue( handler.headers.containsKey( "Proxy-Authorization" ) );
639 
640         if ( supportProxyPreemptiveAuthentication() )
641         {
642             assertEquals( HttpServletResponse.SC_OK, handler.handlerRequestResponses.get( 0 ).responseCode );
643         }
644         else
645         {
646             assertEquals( HttpServletResponse.SC_PROXY_AUTHENTICATION_REQUIRED,
647                           handler.handlerRequestResponses.get( 0 ).responseCode );
648             assertEquals( HttpServletResponse.SC_OK, handler.handlerRequestResponses.get( 1 ).responseCode );
649         }
650 
651     }
652 
653     public void testRedirectGetToStream()
654         throws Exception
655     {
656         StreamingWagon wagon = (StreamingWagon) getWagon();
657 
658         Server server = new Server( 0 );
659         TestHeaderHandler handler = new TestHeaderHandler();
660 
661         server.setHandler( handler );
662         addConnectors( server );
663         server.start();
664 
665         Server redirectServer = new Server( 0 );
666 
667         addConnectors( redirectServer );
668 
669         String protocol = getProtocol();
670 
671         // protocol is wagon protocol but in fact dav is http(s)
672         if ( protocol.equals( "dav" ) )
673         {
674             protocol = "http";
675         }
676 
677         if ( protocol.equals( "davs" ) )
678         {
679             protocol = "https";
680         }
681 
682         String redirectUrl = protocol + "://localhost:" + server.getConnectors()[0].getLocalPort();
683 
684         RedirectHandler redirectHandler =
685             new RedirectHandler( "Found", HttpServletResponse.SC_SEE_OTHER, redirectUrl, null );
686 
687         redirectServer.setHandler( redirectHandler );
688 
689         redirectServer.start();
690 
691         wagon.connect( new Repository( "id", getRepositoryUrl( redirectServer ) ) );
692 
693         File tmpResult = File.createTempFile( "foo", "get" );
694 
695         FileOutputStream fileOutputStream = new FileOutputStream( tmpResult );
696 
697         try
698         {
699             wagon.getToStream( "resource", fileOutputStream );
700             fileOutputStream.flush();
701             fileOutputStream.close();
702             String found = FileUtils.fileRead( tmpResult );
703             assertEquals( "found:'" + found + "'", "Hello, World!", found );
704 
705             checkHandlerResult( handler.handlerRequestResponses, HttpServletResponse.SC_OK );
706             checkHandlerResult( redirectHandler.handlerRequestResponses, HttpServletResponse.SC_FOUND );
707         }
708         finally
709         {
710             wagon.disconnect();
711 
712             server.stop();
713 
714             tmpResult.delete();
715         }
716     }
717 
718     public void testRedirectGet()
719         throws Exception
720     {
721         StreamingWagon wagon = (StreamingWagon) getWagon();
722 
723         Server server = new Server( 0 );
724         TestHeaderHandler handler = new TestHeaderHandler();
725 
726         server.setHandler( handler );
727         addConnectors( server );
728         server.start();
729 
730         Server redirectServer = new Server( 0 );
731 
732         addConnectors( redirectServer );
733 
734         String protocol = getProtocol();
735 
736         // protocol is wagon protocol but in fact dav is http(s)
737         if ( protocol.equals( "dav" ) )
738         {
739             protocol = "http";
740         }
741 
742         if ( protocol.equals( "davs" ) )
743         {
744             protocol = "https";
745         }
746 
747         String redirectUrl = protocol + "://localhost:" + server.getConnectors()[0].getLocalPort();
748 
749         RedirectHandler redirectHandler =
750             new RedirectHandler( "Found", HttpServletResponse.SC_SEE_OTHER, redirectUrl, null );
751 
752         redirectServer.setHandler( redirectHandler );
753 
754         redirectServer.start();
755 
756         wagon.connect( new Repository( "id", getRepositoryUrl( redirectServer ) ) );
757 
758         File tmpResult = File.createTempFile( "foo", "get" );
759 
760         try
761         {
762             wagon.get( "resource", tmpResult );
763             String found = FileUtils.fileRead( tmpResult );
764             assertEquals( "found:'" + found + "'", "Hello, World!", found );
765 
766             checkHandlerResult( handler.handlerRequestResponses, HttpServletResponse.SC_OK );
767             checkHandlerResult( redirectHandler.handlerRequestResponses, HttpServletResponse.SC_FOUND );
768         }
769         finally
770         {
771             wagon.disconnect();
772 
773             server.stop();
774 
775             tmpResult.delete();
776         }
777     }
778 
779 
780     public void testRedirectPutFromStreamWithFullUrl()
781         throws Exception
782     {
783         Server realServer = new Server( 0 );
784 
785         addConnectors( realServer );
786 
787         File repositoryDirectory = getRepositoryDirectory();
788         FileUtils.deleteDirectory( repositoryDirectory );
789         repositoryDirectory.mkdirs();
790 
791         PutHandler putHandler = new PutHandler( repositoryDirectory );
792 
793         realServer.setHandler( putHandler );
794 
795         realServer.start();
796 
797         Server redirectServer = new Server( 0 );
798 
799         addConnectors( redirectServer );
800 
801         String protocol = getProtocol();
802 
803         // protocol is wagon protocol but in fact dav is http(s)
804         if ( protocol.equals( "dav" ) )
805         {
806             protocol = "http";
807         }
808 
809         if ( protocol.equals( "davs" ) )
810         {
811             protocol = "https";
812         }
813 
814         String redirectUrl = protocol + "://localhost:" + realServer.getConnectors()[0].getLocalPort();
815 
816         RedirectHandler redirectHandler =
817             new RedirectHandler( "Found", HttpServletResponse.SC_SEE_OTHER, redirectUrl, repositoryDirectory );
818 
819         redirectServer.setHandler( redirectHandler );
820 
821         redirectServer.start();
822 
823         try
824         {
825             StreamingWagon wagon = (StreamingWagon) getWagon();
826             Repository repository = new Repository( "foo", getRepositoryUrl( redirectServer ) );
827             wagon.connect( repository );
828 
829             File sourceFile = new File( repositoryDirectory, "test-secured-put-resource" );
830             sourceFile.delete();
831             assertFalse( sourceFile.exists() );
832 
833             File tempFile = File.createTempFile( "wagon", "tmp" );
834             tempFile.deleteOnExit();
835             String content = "put top secret";
836             FileUtils.fileWrite( tempFile.getAbsolutePath(), content );
837 
838             FileInputStream fileInputStream = new FileInputStream( tempFile );
839             try
840             {
841                 wagon.putFromStream( fileInputStream, "test-secured-put-resource", content.length(), -1 );
842             }
843             finally
844             {
845                 fileInputStream.close();
846                 tempFile.delete();
847 
848             }
849 
850             assertEquals( content, FileUtils.fileRead( sourceFile.getAbsolutePath() ) );
851 
852             checkRequestResponseForRedirectPutFromStreamWithFullUrl( putHandler, redirectHandler );
853         }
854         finally
855         {
856             realServer.stop();
857             redirectServer.stop();
858         }
859     }
860 
861     protected void checkRequestResponseForRedirectPutFromStreamWithFullUrl( PutHandler putHandler,
862                                                                             RedirectHandler redirectHandler )
863     {
864         checkHandlerResult( putHandler.handlerRequestResponses, HttpServletResponse.SC_CREATED );
865         checkHandlerResult( redirectHandler.handlerRequestResponses, HttpServletResponse.SC_FOUND );
866     }
867 
868     public void testRedirectPutFromStreamRelativeUrl()
869         throws Exception
870     {
871         Server realServer = new Server( 0 );
872         addConnectors( realServer );
873         File repositoryDirectory = getRepositoryDirectory();
874         FileUtils.deleteDirectory( repositoryDirectory );
875         repositoryDirectory.mkdirs();
876 
877         PutHandler putHandler = new PutHandler( repositoryDirectory );
878 
879         realServer.setHandler( putHandler );
880 
881         realServer.start();
882 
883         Server redirectServer = new Server( 0 );
884 
885         addConnectors( redirectServer );
886 
887         RedirectHandler redirectHandler =
888             new RedirectHandler( "Found", HttpServletResponse.SC_SEE_OTHER, "/redirectRequest/foo",
889                                  repositoryDirectory );
890 
891         redirectServer.setHandler( redirectHandler );
892 
893         redirectServer.start();
894 
895         try
896         {
897             StreamingWagon wagon = (StreamingWagon) getWagon();
898             Repository repository = new Repository( "foo", getRepositoryUrl( redirectServer ) );
899             wagon.connect( repository );
900 
901             File sourceFile = new File( repositoryDirectory, "/redirectRequest/foo/test-secured-put-resource" );
902             sourceFile.delete();
903             assertFalse( sourceFile.exists() );
904 
905             File tempFile = File.createTempFile( "wagon", "tmp" );
906             tempFile.deleteOnExit();
907             String content = "put top secret";
908             FileUtils.fileWrite( tempFile.getAbsolutePath(), content );
909 
910             FileInputStream fileInputStream = new FileInputStream( tempFile );
911             try
912             {
913                 wagon.putFromStream( fileInputStream, "test-secured-put-resource", content.length(), -1 );
914             }
915             finally
916             {
917                 fileInputStream.close();
918                 tempFile.delete();
919 
920             }
921 
922             assertEquals( content, FileUtils.fileRead( sourceFile.getAbsolutePath() ) );
923 
924             checkRequestResponseForRedirectPutFromStreamWithRelativeUrl( putHandler, redirectHandler );
925 
926         }
927         finally
928         {
929             realServer.stop();
930             redirectServer.stop();
931         }
932     }
933 
934     protected void checkRequestResponseForRedirectPutFromStreamWithRelativeUrl( PutHandler putHandler,
935                                                                                 RedirectHandler redirectHandler )
936     {
937         checkHandlerResult( putHandler.handlerRequestResponses );
938         checkHandlerResult( redirectHandler.handlerRequestResponses, HttpServletResponse.SC_FOUND,
939                             HttpServletResponse.SC_CREATED );
940     }
941 
942     protected void checkHandlerResult( List<HandlerRequestResponse> handlerRequestResponses,
943                                        int... expectedResponseCodes )
944     {
945         boolean success = true;
946         if ( handlerRequestResponses.size() == expectedResponseCodes.length )
947         {
948             for ( int i = 0; i < expectedResponseCodes.length; i++ )
949             {
950                 success &= ( expectedResponseCodes[i] == handlerRequestResponses.get( i ).responseCode );
951             }
952         }
953 
954         if ( !success )
955         {
956             fail( "expected " + expectedResponseCodes + ", got " + handlerRequestResponses );
957         }
958     }
959 
960     public void testRedirectPutFileWithFullUrl()
961         throws Exception
962     {
963         Server realServer = new Server( 0 );
964 
965         addConnectors( realServer );
966 
967         File repositoryDirectory = getRepositoryDirectory();
968         FileUtils.deleteDirectory( repositoryDirectory );
969         repositoryDirectory.mkdirs();
970 
971         PutHandler putHandler = new PutHandler( repositoryDirectory );
972 
973         realServer.setHandler( putHandler );
974 
975         realServer.start();
976 
977         Server redirectServer = new Server( 0 );
978 
979         addConnectors( redirectServer );
980 
981         String protocol = getProtocol();
982 
983         // protocol is wagon protocol but in fact dav is http(s)
984         if ( protocol.equals( "dav" ) )
985         {
986             protocol = "http";
987         }
988 
989         if ( protocol.equals( "davs" ) )
990         {
991             protocol = "https";
992         }
993 
994         String redirectUrl = protocol + "://localhost:" + realServer.getConnectors()[0].getLocalPort();
995 
996         RedirectHandler redirectHandler =
997             new RedirectHandler( "Found", HttpServletResponse.SC_SEE_OTHER, redirectUrl, repositoryDirectory );
998 
999         redirectServer.setHandler( redirectHandler );
1000 
1001         redirectServer.start();
1002 
1003         try
1004         {
1005             StreamingWagon wagon = (StreamingWagon) getWagon();
1006             Repository repository = new Repository( "foo", getRepositoryUrl( redirectServer ) );
1007             wagon.connect( repository );
1008 
1009             File sourceFile = new File( repositoryDirectory, "test-secured-put-resource" );
1010             sourceFile.delete();
1011             assertFalse( sourceFile.exists() );
1012 
1013             File tempFile = File.createTempFile( "wagon", "tmp" );
1014             tempFile.deleteOnExit();
1015             String content = "put top secret";
1016             FileUtils.fileWrite( tempFile.getAbsolutePath(), content );
1017 
1018             try
1019             {
1020                 wagon.put( tempFile, "test-secured-put-resource" );
1021             }
1022             finally
1023             {
1024                 tempFile.delete();
1025             }
1026 
1027             assertEquals( content, FileUtils.fileRead( sourceFile.getAbsolutePath() ) );
1028 
1029         }
1030         finally
1031         {
1032             realServer.stop();
1033             redirectServer.stop();
1034         }
1035     }
1036 
1037 
1038     public void testRedirectPutFileRelativeUrl()
1039         throws Exception
1040     {
1041         Server realServer = new Server( 0 );
1042         addConnectors( realServer );
1043         File repositoryDirectory = getRepositoryDirectory();
1044         FileUtils.deleteDirectory( repositoryDirectory );
1045         repositoryDirectory.mkdirs();
1046 
1047         PutHandler putHandler = new PutHandler( repositoryDirectory );
1048 
1049         realServer.setHandler( putHandler );
1050 
1051         realServer.start();
1052 
1053         Server redirectServer = new Server( 0 );
1054 
1055         addConnectors( redirectServer );
1056 
1057         RedirectHandler redirectHandler =
1058             new RedirectHandler( "Found", HttpServletResponse.SC_SEE_OTHER, "/redirectRequest/foo",
1059                                  repositoryDirectory );
1060 
1061         redirectServer.setHandler( redirectHandler );
1062 
1063         redirectServer.start();
1064 
1065         try
1066         {
1067             StreamingWagon wagon = (StreamingWagon) getWagon();
1068             Repository repository = new Repository( "foo", getRepositoryUrl( redirectServer ) );
1069             wagon.connect( repository );
1070 
1071             File sourceFile = new File( repositoryDirectory, "/redirectRequest/foo/test-secured-put-resource" );
1072             sourceFile.delete();
1073             assertFalse( sourceFile.exists() );
1074 
1075             File tempFile = File.createTempFile( "wagon", "tmp" );
1076             tempFile.deleteOnExit();
1077             String content = "put top secret";
1078             FileUtils.fileWrite( tempFile.getAbsolutePath(), content );
1079 
1080             try
1081             {
1082                 wagon.put( tempFile, "test-secured-put-resource" );
1083             }
1084             finally
1085             {
1086                 tempFile.delete();
1087             }
1088 
1089             assertEquals( content, FileUtils.fileRead( sourceFile.getAbsolutePath() ) );
1090 
1091         }
1092         finally
1093         {
1094             realServer.stop();
1095             redirectServer.stop();
1096         }
1097     }
1098 
1099 
1100     /**
1101      * 
1102      */
1103     @SuppressWarnings( "checkstyle:visibilitymodifier" )
1104     public static class RedirectHandler
1105         extends AbstractHandler
1106     {
1107         String reason;
1108 
1109         int retCode;
1110 
1111         String redirectUrl;
1112 
1113         File repositoryDirectory;
1114 
1115         public List<HandlerRequestResponse> handlerRequestResponses = new ArrayList<HandlerRequestResponse>();
1116 
1117         RedirectHandler( String reason, int retCode, String redirectUrl, File repositoryDirectory )
1118         {
1119             this.reason = reason;
1120             this.retCode = retCode;
1121             this.redirectUrl = redirectUrl;
1122             this.repositoryDirectory = repositoryDirectory;
1123         }
1124 
1125         public void handle( String s, HttpServletRequest req, HttpServletResponse resp, int i )
1126             throws IOException, ServletException
1127         {
1128             if ( req.getRequestURI().contains( "redirectRequest" ) )
1129             {
1130                 PutHandler putHandler = new PutHandler( this.repositoryDirectory );
1131                 putHandler.handle( s, req, resp, i );
1132                 handlerRequestResponses.add(
1133                     new HandlerRequestResponse( req.getMethod(), ( (Response) resp ).getStatus(),
1134                                                 req.getRequestURI() ) );
1135                 return;
1136             }
1137             resp.setStatus( this.retCode );
1138             resp.sendRedirect( this.redirectUrl + "/" + req.getRequestURI() );
1139             handlerRequestResponses.add(
1140                 new HandlerRequestResponse( req.getMethod(), ( (Response) resp ).getStatus(), req.getRequestURI() ) );
1141         }
1142     }
1143 
1144 
1145     private void runTestProxiedRequest( ProxyInfo proxyInfo, TestHeaderHandler handler )
1146         throws Exception
1147     {
1148         // what an UGLY hack!
1149         // but apparently jetty needs some time to free up resources
1150         // <5s: broken test :(
1151         // CHECKSTYLE_OFF: MagicNumber
1152         Thread.sleep( 5001L );
1153         // CHECKSTYLE_ON: MagicNumber
1154 
1155         Server proxyServer = new Server( 0 );
1156 
1157         proxyServer.setHandler( handler );
1158 
1159         proxyServer.start();
1160 
1161         proxyInfo.setPort( proxyServer.getConnectors()[0].getLocalPort() );
1162 
1163         System.out.println(
1164             "start proxy on host/port " + proxyInfo.getHost() + "/" + proxyInfo.getPort() + " with non proxyHosts "
1165                 + proxyInfo.getNonProxyHosts() );
1166 
1167         while ( !proxyServer.isRunning() || !proxyServer.isStarted() )
1168         {
1169             Thread.sleep( 10 );
1170         }
1171 
1172         try
1173         {
1174             StreamingWagon wagon = (StreamingWagon) getWagon();
1175 
1176             Repository testRepository = new Repository( "id", "http://www.example.com/" );
1177 
1178             String localRepositoryPath = FileTestUtils.getTestOutputDir().toString();
1179             File sourceFile = new File( localRepositoryPath, "test-proxied-resource" );
1180             FileUtils.fileWrite( sourceFile.getAbsolutePath(), "content" );
1181 
1182             wagon.connect( testRepository, proxyInfo );
1183 
1184             try
1185             {
1186                 wagon.getToStream( "test-proxied-resource", new ByteArrayOutputStream() );
1187 
1188                 assertTrue( handler.headers.containsKey( "Proxy-Connection" ) );
1189             }
1190             finally
1191             {
1192                 System.setProperty( "http.proxyHost", "" );
1193                 System.setProperty( "http.proxyPort", "" );
1194                 wagon.disconnect();
1195             }
1196         }
1197         finally
1198         {
1199             proxyServer.stop();
1200         }
1201     }
1202 
1203     private void runTestProxiedRequestWithProvider( ProxyInfoProvider proxyInfoProvider, TestHeaderHandler handler )
1204         throws Exception
1205     {
1206         // what an UGLY hack!
1207         // but apparently jetty needs some time to free up resources
1208         // <5s: broken test :(
1209         // CHECKSTYLE_OFF: MagicNumber
1210         Thread.sleep( 5001L );
1211         // CHECKSTYLE_ON: MagicNumber
1212 
1213         Server proxyServer = new Server( 0 );
1214 
1215         proxyServer.setHandler( handler );
1216 
1217         proxyServer.start();
1218 
1219         proxyInfoProvider.getProxyInfo( null ).setPort( proxyServer.getConnectors()[0].getLocalPort() );
1220 
1221         System.out.println( "start proxy on host/port " + proxyInfoProvider.getProxyInfo( null ).getHost() + "/"
1222                                 + proxyInfoProvider.getProxyInfo( null ).getPort() + " with non proxyHosts "
1223                                 + proxyInfoProvider.getProxyInfo( null ).getNonProxyHosts() );
1224 
1225         while ( !proxyServer.isRunning() || !proxyServer.isStarted() )
1226         {
1227             Thread.sleep( 10 );
1228         }
1229 
1230         try
1231         {
1232             StreamingWagon wagon = (StreamingWagon) getWagon();
1233 
1234             Repository testRepository = new Repository( "id", "http://www.example.com/" );
1235 
1236             String localRepositoryPath = FileTestUtils.getTestOutputDir().toString();
1237             File sourceFile = new File( localRepositoryPath, "test-proxied-resource" );
1238             FileUtils.fileWrite( sourceFile.getAbsolutePath(), "content" );
1239 
1240             wagon.connect( testRepository, proxyInfoProvider );
1241 
1242             try
1243             {
1244                 wagon.getToStream( "test-proxied-resource", new ByteArrayOutputStream() );
1245 
1246                 assertTrue( handler.headers.containsKey( "Proxy-Connection" ) );
1247             }
1248             finally
1249             {
1250                 System.setProperty( "http.proxyHost", "" );
1251                 System.setProperty( "http.proxyPort", "" );
1252                 wagon.disconnect();
1253             }
1254         }
1255         finally
1256         {
1257             proxyServer.stop();
1258         }
1259     }
1260 
1261     private ProxyInfo createProxyInfo()
1262     {
1263         ProxyInfo proxyInfo = new ProxyInfo();
1264         proxyInfo.setHost( "localhost" );
1265         proxyInfo.setNonProxyHosts( null );
1266         proxyInfo.setType( "http" );
1267         return proxyInfo;
1268     }
1269 
1270     public void testSecuredGetUnauthorized()
1271         throws Exception
1272     {
1273         try
1274         {
1275             runTestSecuredGet( null );
1276             fail();
1277         }
1278         catch ( AuthorizationException e )
1279         {
1280             assertTrue( true );
1281         }
1282     }
1283 
1284     public void testSecuredGetWrongPassword()
1285         throws Exception
1286     {
1287         try
1288         {
1289             AuthenticationInfo authInfo = new AuthenticationInfo();
1290             authInfo.setUserName( "user" );
1291             authInfo.setPassword( "admin" );
1292             runTestSecuredGet( authInfo );
1293             fail();
1294         }
1295         catch ( AuthorizationException e )
1296         {
1297             assertTrue( true );
1298         }
1299     }
1300 
1301     public void testSecuredGet()
1302         throws Exception
1303     {
1304         AuthenticationInfo authInfo = new AuthenticationInfo();
1305         authInfo.setUserName( "user" );
1306         authInfo.setPassword( "secret" );
1307         runTestSecuredGet( authInfo );
1308     }
1309 
1310 
1311     public void runTestSecuredGet( AuthenticationInfo authInfo )
1312         throws Exception
1313     {
1314         String localRepositoryPath = FileTestUtils.getTestOutputDir().toString();
1315         Server server = createSecurityServer( localRepositoryPath );
1316 
1317         server.start();
1318 
1319         try
1320         {
1321             StreamingWagon wagon = (StreamingWagon) getWagon();
1322 
1323             Repository testRepository = new Repository( "id", getRepositoryUrl( server ) );
1324 
1325             File sourceFile = new File( localRepositoryPath, "test-secured-resource" );
1326             FileUtils.fileWrite( sourceFile.getAbsolutePath(), "top secret" );
1327 
1328             wagon.connect( testRepository, authInfo );
1329 
1330             File file = File.createTempFile( "wagon-test", "txt" );
1331 
1332             try
1333             {
1334                 wagon.get( "test-secured-resource", file );
1335             }
1336             finally
1337             {
1338                 wagon.disconnect();
1339             }
1340 
1341             FileInputStream in = new FileInputStream( file );
1342 
1343             assertEquals( "top secret", IOUtil.toString( in ) );
1344 
1345             TestSecurityHandler securityHandler = (TestSecurityHandler) ( (Context) server.getHandler() ).getHandler();
1346             testPreemptiveAuthenticationGet( securityHandler, supportPreemptiveAuthenticationGet() );
1347 
1348         }
1349         finally
1350         {
1351             server.stop();
1352         }
1353     }
1354 
1355 
1356     public void testSecuredGetToStream()
1357         throws Exception
1358     {
1359         AuthenticationInfo authInfo = new AuthenticationInfo();
1360         authInfo.setUserName( "user" );
1361         authInfo.setPassword( "secret" );
1362         runTestSecuredGetToStream( authInfo );
1363     }
1364 
1365     public void runTestSecuredGetToStream( AuthenticationInfo authInfo )
1366         throws Exception
1367     {
1368         String localRepositoryPath = FileTestUtils.getTestOutputDir().toString();
1369         Server server = createSecurityServer( localRepositoryPath );
1370 
1371         server.start();
1372 
1373         try
1374         {
1375             StreamingWagon wagon = (StreamingWagon) getWagon();
1376 
1377             Repository testRepository = new Repository( "id", getRepositoryUrl( server ) );
1378 
1379             File sourceFile = new File( localRepositoryPath, "test-secured-resource" );
1380             FileUtils.fileWrite( sourceFile.getAbsolutePath(), "top secret" );
1381 
1382             wagon.connect( testRepository, authInfo );
1383 
1384             ByteArrayOutputStream out = new ByteArrayOutputStream();
1385             try
1386             {
1387                 wagon.getToStream( "test-secured-resource", out );
1388             }
1389             finally
1390             {
1391                 wagon.disconnect();
1392             }
1393 
1394             assertEquals( "top secret", out.toString( "US-ASCII" ) );
1395 
1396             TestSecurityHandler securityHandler = (TestSecurityHandler) ( (Context) server.getHandler() ).getHandler();
1397             testPreemptiveAuthenticationGet( securityHandler, supportPreemptiveAuthenticationGet() );
1398         }
1399         finally
1400         {
1401             server.stop();
1402         }
1403     }
1404 
1405     public void testSecuredResourceExistsUnauthorized()
1406         throws Exception
1407     {
1408         try
1409         {
1410             runTestSecuredResourceExists( null );
1411             fail();
1412         }
1413         catch ( AuthorizationException e )
1414         {
1415             assertTrue( true );
1416         }
1417     }
1418 
1419     public void testSecuredResourceExistsWrongPassword()
1420         throws Exception
1421     {
1422         try
1423         {
1424             AuthenticationInfo authInfo = new AuthenticationInfo();
1425             authInfo.setUserName( "user" );
1426             authInfo.setPassword( "admin" );
1427             runTestSecuredResourceExists( authInfo );
1428         }
1429         catch ( AuthorizationException e )
1430         {
1431             assertTrue( true );
1432         }
1433     }
1434 
1435     public void testSecuredResourceExists()
1436         throws Exception
1437     {
1438         AuthenticationInfo authInfo = new AuthenticationInfo();
1439         authInfo.setUserName( "user" );
1440         authInfo.setPassword( "secret" );
1441         runTestSecuredResourceExists( authInfo );
1442     }
1443 
1444     public void runTestSecuredResourceExists( AuthenticationInfo authInfo )
1445         throws Exception
1446     {
1447         String localRepositoryPath = FileTestUtils.getTestOutputDir().toString();
1448         Server server = createSecurityServer( localRepositoryPath );
1449 
1450         server.start();
1451 
1452         try
1453         {
1454             StreamingWagon wagon = (StreamingWagon) getWagon();
1455 
1456             Repository testRepository = new Repository( "id", getRepositoryUrl( server ) );
1457 
1458             File sourceFile = new File( localRepositoryPath, "test-secured-resource-exists" );
1459             FileUtils.fileWrite( sourceFile.getAbsolutePath(), "top secret" );
1460 
1461             wagon.connect( testRepository, authInfo );
1462 
1463             try
1464             {
1465                 assertTrue( wagon.resourceExists( "test-secured-resource-exists" ) );
1466 
1467                 assertFalse( wagon.resourceExists( "test-secured-resource-not-exists" ) );
1468             }
1469             finally
1470             {
1471                 wagon.disconnect();
1472             }
1473         }
1474         finally
1475         {
1476             server.stop();
1477         }
1478     }
1479 
1480     private Server createSecurityServer( String localRepositoryPath )
1481     {
1482         Server server = new Server( 0 );
1483 
1484         SecurityHandler sh = createSecurityHandler();
1485 
1486         Context root = new Context( Context.SESSIONS );
1487         root.setContextPath( "/" );
1488         root.addHandler( sh );
1489         root.setResourceBase( localRepositoryPath );
1490         ServletHolder servletHolder = new ServletHolder( new DefaultServlet() );
1491         root.addServlet( servletHolder, "/*" );
1492 
1493         server.setHandler( root );
1494         addConnectors( server );
1495         return server;
1496     }
1497 
1498 
1499     private String writeTestFileGzip( File parent, String child )
1500         throws IOException
1501     {
1502         File file = new File( parent, child );
1503         file.getParentFile().mkdirs();
1504         file.deleteOnExit();
1505         OutputStream out = new FileOutputStream( file );
1506         try
1507         {
1508             out.write( child.getBytes() );
1509         }
1510         finally
1511         {
1512             out.close();
1513         }
1514 
1515         file = new File( parent, child + ".gz" );
1516         file.deleteOnExit();
1517         String content;
1518         out = new FileOutputStream( file );
1519         out = new GZIPOutputStream( out );
1520         try
1521         {
1522             // write out different data than non-gz file, so we can
1523             // assert the gz version was returned
1524             content = file.getAbsolutePath();
1525             out.write( content.getBytes() );
1526         }
1527         finally
1528         {
1529             out.close();
1530         }
1531 
1532         return content;
1533     }
1534 
1535     public void testPutForbidden()
1536         throws Exception
1537     {
1538         try
1539         {
1540             runTestPut( HttpServletResponse.SC_FORBIDDEN );
1541             fail();
1542         }
1543         catch ( AuthorizationException e )
1544         {
1545             assertTrue( true );
1546         }
1547     }
1548 
1549     public void testPut404()
1550         throws Exception
1551     {
1552         try
1553         {
1554             runTestPut( HttpServletResponse.SC_NOT_FOUND );
1555             fail();
1556         }
1557         catch ( ResourceDoesNotExistException e )
1558         {
1559             assertTrue( true );
1560         }
1561     }
1562 
1563     public void testPut500()
1564         throws Exception
1565     {
1566         try
1567         {
1568             runTestPut( HttpServletResponse.SC_INTERNAL_SERVER_ERROR );
1569             fail();
1570         }
1571         catch ( TransferFailedException e )
1572         {
1573             assertTrue( true );
1574         }
1575     }
1576 
1577     public void testPut429()
1578         throws Exception
1579     {
1580 
1581         try
1582         {
1583 
1584             StreamingWagon wagon = (StreamingWagon) getWagon();
1585             Server server = new Server( 0 );
1586             final AtomicBoolean called = new AtomicBoolean();
1587 
1588             AbstractHandler handler = new AbstractHandler()
1589             {
1590                 public void handle( String s, HttpServletRequest request, HttpServletResponse response, int i )
1591                     throws IOException, ServletException
1592                 {
1593                     if ( called.get() )
1594                     {
1595                         response.setStatus( HttpServletResponse.SC_INTERNAL_SERVER_ERROR );
1596                         ( (Request) request ).setHandled( true );
1597                     }
1598                     else
1599                     {
1600                         called.set( true );
1601                         response.setStatus( SC_TOO_MANY_REQUESTS );
1602                         ( (Request) request ).setHandled( true );
1603                     }
1604                 }
1605             };
1606 
1607             server.setHandler( handler );
1608             addConnectors( server );
1609             server.start();
1610 
1611             wagon.connect( new Repository( "id", getRepositoryUrl( server ) ) );
1612 
1613             File tempFile = File.createTempFile( "wagon", "tmp" );
1614             tempFile.deleteOnExit();
1615             FileUtils.fileWrite( tempFile.getAbsolutePath(), "content" );
1616 
1617             try
1618             {
1619                 wagon.put( tempFile, "resource" );
1620                 fail();
1621             }
1622             finally
1623             {
1624                 wagon.disconnect();
1625 
1626                 server.stop();
1627 
1628                 tempFile.delete();
1629             }
1630 
1631         }
1632         catch ( TransferFailedException e )
1633         {
1634             assertTrue( true );
1635         }
1636     }
1637 
1638 
1639     private void runTestPut( int status )
1640         throws Exception
1641     {
1642         StreamingWagon wagon = (StreamingWagon) getWagon();
1643 
1644         Server server = new Server( 0 );
1645         StatusHandler handler = new StatusHandler();
1646         handler.setStatusToReturn( status );
1647         server.setHandler( handler );
1648         addConnectors( server );
1649         server.start();
1650 
1651         wagon.connect( new Repository( "id", getRepositoryUrl( server ) ) );
1652 
1653         File tempFile = File.createTempFile( "wagon", "tmp" );
1654         tempFile.deleteOnExit();
1655         FileUtils.fileWrite( tempFile.getAbsolutePath(), "content" );
1656 
1657         try
1658         {
1659             wagon.put( tempFile, "resource" );
1660             fail();
1661         }
1662         finally
1663         {
1664             wagon.disconnect();
1665 
1666             server.stop();
1667 
1668             tempFile.delete();
1669         }
1670     }
1671 
1672     public void testSecuredPutUnauthorized()
1673         throws Exception
1674     {
1675         try
1676         {
1677             runTestSecuredPut( null );
1678             fail();
1679         }
1680         catch ( TransferFailedException e )
1681         {
1682             assertTrue( true );
1683         }
1684     }
1685 
1686     public void testSecuredPutWrongPassword()
1687         throws Exception
1688     {
1689         try
1690         {
1691             AuthenticationInfo authInfo = new AuthenticationInfo();
1692             authInfo.setUserName( "user" );
1693             authInfo.setPassword( "admin" );
1694             runTestSecuredPut( authInfo );
1695             fail();
1696         }
1697         catch ( TransferFailedException e )
1698         {
1699             assertTrue( true );
1700         }
1701     }
1702 
1703     public void testSecuredPut()
1704         throws Exception
1705     {
1706         AuthenticationInfo authInfo = new AuthenticationInfo();
1707         authInfo.setUserName( "user" );
1708         authInfo.setPassword( "secret" );
1709         runTestSecuredPut( authInfo );
1710     }
1711 
1712     public void runTestSecuredPut( AuthenticationInfo authInfo )
1713         throws Exception
1714     {
1715         runTestSecuredPut( authInfo, 1 );
1716     }
1717 
1718     public void runTestSecuredPut( AuthenticationInfo authInfo, int putNumber )
1719         throws Exception
1720     {
1721         String localRepositoryPath = FileTestUtils.getTestOutputDir().toString();
1722         Server server = new Server( 0 );
1723 
1724         TestSecurityHandler sh = createSecurityHandler();
1725 
1726         PutHandler putHandler = new PutHandler( new File( localRepositoryPath ) );
1727 
1728         HandlerCollection handlers = new HandlerCollection();
1729         handlers.setHandlers( new Handler[]{ sh, putHandler } );
1730 
1731         server.setHandler( handlers );
1732         addConnectors( server );
1733         server.start();
1734 
1735         StreamingWagon wagon = (StreamingWagon) getWagon();
1736         Repository testRepository = new Repository( "id", getRepositoryUrl( server ) );
1737         wagon.connect( testRepository, authInfo );
1738         try
1739         {
1740             for ( int i = 0; i < putNumber; i++ )
1741             {
1742                 File sourceFile = new File( localRepositoryPath, "test-secured-put-resource" );
1743                 sourceFile.delete();
1744                 assertFalse( sourceFile.exists() );
1745 
1746                 File tempFile = File.createTempFile( "wagon", "tmp" );
1747                 tempFile.deleteOnExit();
1748                 FileUtils.fileWrite( tempFile.getAbsolutePath(), "put top secret" );
1749 
1750                 try
1751                 {
1752                     wagon.put( tempFile, "test-secured-put-resource" );
1753                 }
1754                 finally
1755                 {
1756                     tempFile.delete();
1757                 }
1758 
1759                 assertEquals( "put top secret", FileUtils.fileRead( sourceFile.getAbsolutePath() ) );
1760             }
1761         }
1762         finally
1763         {
1764             wagon.disconnect();
1765             server.stop();
1766         }
1767         assertEquals( putNumber, putHandler.putCallNumber );
1768         testPreemptiveAuthenticationPut( sh, supportPreemptiveAuthenticationPut() );
1769     }
1770 
1771     public void testNonSecuredPutFromStream()
1772         throws Exception
1773     {
1774         AuthenticationInfo authInfo = new AuthenticationInfo();
1775         authInfo.setUserName( "user" );
1776         authInfo.setPassword( "secret" );
1777         runTestSecuredPutFromStream( authInfo, 1, false );
1778     }
1779 
1780     public void testSecuredPutFromStream()
1781         throws Exception
1782     {
1783         AuthenticationInfo authInfo = new AuthenticationInfo();
1784         authInfo.setUserName( "user" );
1785         authInfo.setPassword( "secret" );
1786         runTestSecuredPutFromStream( authInfo, 1, true );
1787     }
1788 
1789     public void runTestSecuredPutFromStream( AuthenticationInfo authInfo, int putNumber, boolean addSecurityHandler )
1790         throws Exception
1791     {
1792         String localRepositoryPath = FileTestUtils.getTestOutputDir().toString();
1793         Server server = new Server( 0 );
1794 
1795         TestSecurityHandler sh = createSecurityHandler();
1796 
1797         PutHandler putHandler = new PutHandler( new File( localRepositoryPath ) );
1798 
1799         HandlerCollection handlers = new HandlerCollection();
1800         handlers.setHandlers( addSecurityHandler ? new Handler[]{ sh, putHandler } : new Handler[]{ putHandler } );
1801 
1802         server.setHandler( handlers );
1803         addConnectors( server );
1804         server.start();
1805 
1806         StreamingWagon wagon = (StreamingWagon) getWagon();
1807         Repository testRepository = new Repository( "id", getRepositoryUrl( server ) );
1808         if ( addSecurityHandler )
1809         {
1810             wagon.connect( testRepository, authInfo );
1811         }
1812         else
1813         {
1814             wagon.connect( testRepository );
1815         }
1816         try
1817         {
1818             for ( int i = 0; i < putNumber; i++ )
1819             {
1820                 File sourceFile = new File( localRepositoryPath, "test-secured-put-resource" );
1821                 sourceFile.delete();
1822                 assertFalse( sourceFile.exists() );
1823 
1824                 File tempFile = File.createTempFile( "wagon", "tmp" );
1825                 tempFile.deleteOnExit();
1826                 String content = "put top secret";
1827                 FileUtils.fileWrite( tempFile.getAbsolutePath(), content );
1828 
1829                 FileInputStream fileInputStream = new FileInputStream( tempFile );
1830                 try
1831                 {
1832                     wagon.putFromStream( fileInputStream, "test-secured-put-resource", content.length(), -1 );
1833                 }
1834                 finally
1835                 {
1836                     fileInputStream.close();
1837                     tempFile.delete();
1838 
1839                 }
1840 
1841                 assertEquals( content, FileUtils.fileRead( sourceFile.getAbsolutePath() ) );
1842             }
1843         }
1844         finally
1845         {
1846             wagon.disconnect();
1847             server.stop();
1848         }
1849         assertEquals( putNumber, putHandler.putCallNumber );
1850         if ( addSecurityHandler )
1851         {
1852             testPreemptiveAuthenticationPut( sh, supportPreemptiveAuthenticationPut() );
1853         }
1854 
1855         // ensure we didn't use chunked transfer which doesn't work on ngnix
1856         for ( DeployedResource deployedResource : putHandler.deployedResources )
1857         {
1858             if ( StringUtils.equalsIgnoreCase( "chunked", deployedResource.transferEncoding ) )
1859             {
1860                 fail( "deployedResource use chunked: " + deployedResource );
1861             }
1862         }
1863     }
1864 
1865 
1866     protected abstract boolean supportPreemptiveAuthenticationPut();
1867 
1868     protected abstract boolean supportPreemptiveAuthenticationGet();
1869 
1870     protected abstract boolean supportProxyPreemptiveAuthentication();
1871 
1872     protected void testPreemptiveAuthenticationGet( TestSecurityHandler sh, boolean preemptive )
1873     {
1874         testPreemptiveAuthentication( sh, preemptive );
1875     }
1876 
1877     protected void testPreemptiveAuthenticationPut( TestSecurityHandler sh, boolean preemptive )
1878     {
1879         testPreemptiveAuthentication( sh, preemptive );
1880     }
1881 
1882     protected void testPreemptiveAuthentication( TestSecurityHandler sh, boolean preemptive )
1883     {
1884 
1885         if ( preemptive )
1886         {
1887             assertEquals( "not 1 security handler use " + sh.handlerRequestResponses, 1,
1888                           sh.handlerRequestResponses.size() );
1889             assertEquals( HttpServletResponse.SC_OK, sh.handlerRequestResponses.get( 0 ).responseCode );
1890         }
1891         else
1892         {
1893             assertEquals( "not 2 security handler use " + sh.handlerRequestResponses, 2,
1894                           sh.handlerRequestResponses.size() );
1895             assertEquals( HttpServletResponse.SC_UNAUTHORIZED, sh.handlerRequestResponses.get( 0 ).responseCode );
1896             assertEquals( HttpServletResponse.SC_OK, sh.handlerRequestResponses.get( 1 ).responseCode );
1897 
1898         }
1899     }
1900 
1901     static class StatusHandler
1902         extends AbstractHandler
1903     {
1904         private int status;
1905 
1906         public void setStatusToReturn( int status )
1907         {
1908             this.status = status;
1909         }
1910 
1911         public void handle( String target, HttpServletRequest request, HttpServletResponse response, int dispatch )
1912             throws IOException, ServletException
1913         {
1914             if ( status != 0 )
1915             {
1916                 response.setStatus( status );
1917                 ( (Request) request ).setHandled( true );
1918             }
1919         }
1920     }
1921 
1922     static class DeployedResource
1923     {
1924         String httpMethod;
1925 
1926         String requestUri;
1927 
1928         String contentLength;
1929 
1930         String transferEncoding;
1931 
1932         public DeployedResource()
1933         {
1934             // no op
1935         }
1936 
1937         @Override
1938         public String toString()
1939         {
1940             final StringBuilder sb = new StringBuilder();
1941             sb.append( "DeployedResource" );
1942             sb.append( "{httpMethod='" ).append( httpMethod ).append( '\'' );
1943             sb.append( ", requestUri='" ).append( requestUri ).append( '\'' );
1944             sb.append( ", contentLength='" ).append( contentLength ).append( '\'' );
1945             sb.append( ", transferEncoding='" ).append( transferEncoding ).append( '\'' );
1946             sb.append( '}' );
1947             return sb.toString();
1948         }
1949     }
1950 
1951     /**
1952      * 
1953      */
1954     @SuppressWarnings( "checkstyle:visibilitymodifier" )
1955     public static class PutHandler
1956         extends AbstractHandler
1957     {
1958         private final File resourceBase;
1959 
1960         public List<DeployedResource> deployedResources = new ArrayList<DeployedResource>();
1961 
1962         public int putCallNumber = 0;
1963 
1964         public List<HandlerRequestResponse> handlerRequestResponses = new ArrayList<HandlerRequestResponse>();
1965 
1966         public PutHandler( File repositoryDirectory )
1967         {
1968             this.resourceBase = repositoryDirectory;
1969         }
1970 
1971         public void handle( String target, HttpServletRequest request, HttpServletResponse response, int dispatch )
1972             throws IOException, ServletException
1973         {
1974             Request baseRequest =
1975                 request instanceof Request ? (Request) request : HttpConnection.getCurrentConnection().getRequest();
1976 
1977             if ( baseRequest.isHandled() || !"PUT".equals( baseRequest.getMethod() ) )
1978             {
1979                 return;
1980             }
1981 
1982             baseRequest.setHandled( true );
1983 
1984             File file = new File( resourceBase, URLDecoder.decode( request.getPathInfo() ) );
1985             file.getParentFile().mkdirs();
1986             FileOutputStream out = new FileOutputStream( file );
1987             ServletInputStream in = request.getInputStream();
1988             try
1989             {
1990                 IOUtil.copy( in, out );
1991             }
1992             finally
1993             {
1994                 in.close();
1995                 out.close();
1996             }
1997             putCallNumber++;
1998             DeployedResource deployedResource = new DeployedResource();
1999 
2000             deployedResource.httpMethod = request.getMethod();
2001             deployedResource.requestUri = request.getRequestURI();
2002             deployedResource.transferEncoding = request.getHeader( "Transfer-Encoding" );
2003             deployedResource.contentLength = request.getHeader( "Content-Length" );
2004             deployedResources.add( deployedResource );
2005 
2006             response.setStatus( HttpServletResponse.SC_CREATED );
2007 
2008             handlerRequestResponses.add(
2009                 new HandlerRequestResponse( request.getMethod(), ( (Response) response ).getStatus(),
2010                                             request.getRequestURI() ) );
2011         }
2012     }
2013 
2014     private static class AuthorizingProxyHandler
2015         extends TestHeaderHandler
2016     {
2017 
2018         List<HandlerRequestResponse> handlerRequestResponses = new ArrayList<HandlerRequestResponse>();
2019 
2020         public void handle( String target, HttpServletRequest request, HttpServletResponse response, int dispatch )
2021             throws IOException, ServletException
2022         {
2023             System.out.println( " handle proxy request" );
2024             if ( request.getHeader( "Proxy-Authorization" ) == null )
2025             {
2026                 handlerRequestResponses.add(
2027                     new HandlerRequestResponse( request.getMethod(),
2028                                                 HttpServletResponse.SC_PROXY_AUTHENTICATION_REQUIRED,
2029                                                 request.getRequestURI() ) );
2030                 response.setStatus( HttpServletResponse.SC_PROXY_AUTHENTICATION_REQUIRED );
2031                 response.addHeader( "Proxy-Authenticate", "Basic realm=\"Squid proxy-caching web server\"" );
2032 
2033                 ( (Request) request ).setHandled( true );
2034                 return;
2035             }
2036             handlerRequestResponses.add(
2037                 new HandlerRequestResponse( request.getMethod(), HttpServletResponse.SC_OK, request.getRequestURI() ) );
2038             super.handle( target, request, response, dispatch );
2039         }
2040     }
2041 
2042     /**
2043      * 
2044      */
2045     @SuppressWarnings( "checkstyle:visibilitymodifier" )
2046     private static class TestHeaderHandler
2047         extends AbstractHandler
2048     {
2049         public Map<String, String> headers = Collections.emptyMap();
2050 
2051         public List<HandlerRequestResponse> handlerRequestResponses = new ArrayList<HandlerRequestResponse>();
2052 
2053         public TestHeaderHandler()
2054         {
2055         }
2056 
2057         public void handle( String target, HttpServletRequest request, HttpServletResponse response, int dispatch )
2058             throws IOException, ServletException
2059         {
2060             headers = new HashMap<String, String>();
2061             for ( Enumeration<String> e = request.getHeaderNames(); e.hasMoreElements(); )
2062             {
2063                 String name = e.nextElement();
2064                 Enumeration headerValues = request.getHeaders( name );
2065                 // as per HTTP spec http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html
2066                 // multiple values for the same header key are concatenated separated by comma
2067                 // otherwise we wouldn't notice headers with same key added multiple times
2068                 StringBuffer combinedHeaderValue = new StringBuffer();
2069                 for ( int i = 0; headerValues.hasMoreElements(); i++ )
2070                 {
2071                     if ( i > 0 )
2072                     {
2073                         combinedHeaderValue.append( "," );
2074                     }
2075                     combinedHeaderValue.append( headerValues.nextElement() );
2076                 }
2077                 headers.put( name, combinedHeaderValue.toString() );
2078             }
2079 
2080             response.setContentType( "text/plain" );
2081             response.setStatus( HttpServletResponse.SC_OK );
2082             response.getWriter().print( "Hello, World!" );
2083 
2084             handlerRequestResponses.add(
2085                 new HandlerRequestResponse( request.getMethod(), ( (Response) response ).getStatus(),
2086                                             request.getRequestURI() ) );
2087 
2088             ( (Request) request ).setHandled( true );
2089         }
2090 
2091     }
2092 
2093     protected TestSecurityHandler createSecurityHandler()
2094     {
2095         Constraint constraint = new Constraint();
2096         constraint.setName( Constraint.__BASIC_AUTH );
2097         constraint.setRoles( new String[]{ "admin" } );
2098         constraint.setAuthenticate( true );
2099 
2100         ConstraintMapping cm = new ConstraintMapping();
2101         cm.setConstraint( constraint );
2102         cm.setPathSpec( "/*" );
2103 
2104         TestSecurityHandler sh = new TestSecurityHandler();
2105         HashUserRealm hashUserRealm = new HashUserRealm( "MyRealm" );
2106         hashUserRealm.put( "user", "secret" );
2107         hashUserRealm.addUserToRole( "user", "admin" );
2108         sh.setUserRealm( hashUserRealm );
2109         sh.setConstraintMappings( new ConstraintMapping[]{ cm } );
2110         return sh;
2111     }
2112 
2113     /**
2114      * 
2115      */
2116     @SuppressWarnings( "checkstyle:visibilitymodifier" )
2117     public static class TestSecurityHandler
2118         extends SecurityHandler
2119     {
2120 
2121         public List<HandlerRequestResponse> handlerRequestResponses = new ArrayList<HandlerRequestResponse>();
2122 
2123         @Override
2124         public void handle( String target, HttpServletRequest request, HttpServletResponse response, int dispatch )
2125             throws IOException, ServletException
2126         {
2127             String method = request.getMethod();
2128             super.handle( target, request, response, dispatch );
2129 
2130             handlerRequestResponses.add(
2131                 new HandlerRequestResponse( method, ( (Response) response ).getStatus(), request.getRequestURI() ) );
2132         }
2133 
2134     }
2135 
2136     /**
2137      * 
2138      */
2139     @SuppressWarnings( "checkstyle:visibilitymodifier" )
2140     public static class HandlerRequestResponse
2141     {
2142         public String method;
2143 
2144         public int responseCode;
2145 
2146         public String requestUri;
2147 
2148         private HandlerRequestResponse( String method, int responseCode, String requestUri )
2149         {
2150             this.method = method;
2151             this.responseCode = responseCode;
2152             this.requestUri = requestUri;
2153         }
2154 
2155         @Override
2156         public String toString()
2157         {
2158             final StringBuilder sb = new StringBuilder();
2159             sb.append( "HandlerRequestResponse" );
2160             sb.append( "{method='" ).append( method ).append( '\'' );
2161             sb.append( ", responseCode=" ).append( responseCode );
2162             sb.append( ", requestUri='" ).append( requestUri ).append( '\'' );
2163             sb.append( '}' );
2164             return sb.toString();
2165         }
2166     }
2167 }