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