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