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