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