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