You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by ol...@apache.org on 2012/03/14 18:15:02 UTC

svn commit: r1300648 - in /maven/wagon/trunk: wagon-provider-test/src/main/java/org/apache/maven/wagon/http/ wagon-providers/wagon-http-shared/src/main/java/org/apache/maven/wagon/shared/http/ wagon-providers/wagon-http-shared4/src/main/java/org/apache...

Author: olamy
Date: Wed Mar 14 17:15:02 2012
New Revision: 1300648

URL: http://svn.apache.org/viewvc?rev=1300648&view=rev
Log:
[WAGON-369] Maven deploy plugin doesn't follow HTTP 302 redirects.
with unit test from putFromStream.
Note as now the request is done twice InputStream is saved in byte array (used when putting metadata).

Modified:
    maven/wagon/trunk/wagon-provider-test/src/main/java/org/apache/maven/wagon/http/HttpWagonTestCase.java
    maven/wagon/trunk/wagon-providers/wagon-http-shared/src/main/java/org/apache/maven/wagon/shared/http/AbstractHttpClientWagon.java
    maven/wagon/trunk/wagon-providers/wagon-http-shared4/src/main/java/org/apache/maven/wagon/shared/http4/AbstractHttpClientWagon.java

Modified: maven/wagon/trunk/wagon-provider-test/src/main/java/org/apache/maven/wagon/http/HttpWagonTestCase.java
URL: http://svn.apache.org/viewvc/maven/wagon/trunk/wagon-provider-test/src/main/java/org/apache/maven/wagon/http/HttpWagonTestCase.java?rev=1300648&r1=1300647&r2=1300648&view=diff
==============================================================================
--- maven/wagon/trunk/wagon-provider-test/src/main/java/org/apache/maven/wagon/http/HttpWagonTestCase.java (original)
+++ maven/wagon/trunk/wagon-provider-test/src/main/java/org/apache/maven/wagon/http/HttpWagonTestCase.java Wed Mar 14 17:15:02 2012
@@ -442,6 +442,183 @@ public abstract class HttpWagonTestCase
 
     }
 
+    public void testRedirectPutFromStreamWithFullUrl()
+        throws Exception
+    {
+        Server realServer = new Server( 0 );
+
+        addConnectors( realServer );
+
+        File repositoryDirectory = getRepositoryDirectory();
+        FileUtils.deleteDirectory( repositoryDirectory );
+        repositoryDirectory.mkdirs();
+
+        PutHandler putHandler = new PutHandler( repositoryDirectory );
+
+        realServer.setHandler( putHandler );
+
+        realServer.start();
+
+        Server redirectServer = new Server( 0 );
+
+        addConnectors( redirectServer );
+
+        String protocol = getProtocol();
+
+        // protocol is wagon protocol but in fact dav is http(s)
+        if ( protocol.equals( "dav" ) )
+        {
+            protocol = "http";
+        }
+
+        if ( protocol.equals( "davs" ) )
+        {
+            protocol = "https";
+        }
+
+        String redirectUrl = protocol + "://localhost:" + realServer.getConnectors()[0].getLocalPort();
+
+        RedirectHandler redirectHandler = new RedirectHandler( "Found", 303, redirectUrl, repositoryDirectory );
+
+        redirectServer.setHandler( redirectHandler );
+
+        redirectServer.start();
+
+        try
+        {
+            StreamingWagon wagon = (StreamingWagon) getWagon();
+            Repository repository = new Repository( "foo", getRepositoryUrl( redirectServer ) );
+            wagon.connect( repository );
+
+            File sourceFile = new File( repositoryDirectory, "test-secured-put-resource" );
+            sourceFile.delete();
+            assertFalse( sourceFile.exists() );
+
+            File tempFile = File.createTempFile( "wagon", "tmp" );
+            tempFile.deleteOnExit();
+            String content = "put top secret";
+            FileUtils.fileWrite( tempFile.getAbsolutePath(), content );
+
+            FileInputStream fileInputStream = new FileInputStream( tempFile );
+            try
+            {
+                wagon.putFromStream( fileInputStream, "test-secured-put-resource", content.length(), -1 );
+            }
+            finally
+            {
+                fileInputStream.close();
+                tempFile.delete();
+
+            }
+
+            assertEquals( content, FileUtils.fileRead( sourceFile.getAbsolutePath() ) );
+
+        }
+        finally
+        {
+            realServer.stop();
+            redirectServer.stop();
+        }
+    }
+
+    public void testRedirectPutFromStreamRelativeUrl()
+        throws Exception
+    {
+        Server realServer = new Server( 0 );
+        addConnectors( realServer );
+        File repositoryDirectory = getRepositoryDirectory();
+        FileUtils.deleteDirectory( repositoryDirectory );
+        repositoryDirectory.mkdirs();
+
+        PutHandler putHandler = new PutHandler( repositoryDirectory );
+
+        realServer.setHandler( putHandler );
+
+        realServer.start();
+
+        Server redirectServer = new Server( 0 );
+
+        addConnectors( redirectServer );
+
+        RedirectHandler redirectHandler =
+            new RedirectHandler( "Found", 303, "/redirectRequest/foo", repositoryDirectory );
+
+        redirectServer.setHandler( redirectHandler );
+
+        redirectServer.start();
+
+        try
+        {
+            StreamingWagon wagon = (StreamingWagon) getWagon();
+            Repository repository = new Repository( "foo", getRepositoryUrl( redirectServer ) );
+            wagon.connect( repository );
+
+            File sourceFile = new File( repositoryDirectory, "/redirectRequest/foo/test-secured-put-resource" );
+            sourceFile.delete();
+            assertFalse( sourceFile.exists() );
+
+            File tempFile = File.createTempFile( "wagon", "tmp" );
+            tempFile.deleteOnExit();
+            String content = "put top secret";
+            FileUtils.fileWrite( tempFile.getAbsolutePath(), content );
+
+            FileInputStream fileInputStream = new FileInputStream( tempFile );
+            try
+            {
+                wagon.putFromStream( fileInputStream, "test-secured-put-resource", content.length(), -1 );
+            }
+            finally
+            {
+                fileInputStream.close();
+                tempFile.delete();
+
+            }
+
+            assertEquals( content, FileUtils.fileRead( sourceFile.getAbsolutePath() ) );
+
+        }
+        finally
+        {
+            realServer.stop();
+            redirectServer.stop();
+        }
+    }
+
+
+    public static class RedirectHandler
+        extends AbstractHandler
+    {
+        String reason;
+
+        int retCode;
+
+        String redirectUrl;
+
+        File repositoryDirectory;
+
+        RedirectHandler( String reason, int retCode, String redirectUrl, File repositoryDirectory )
+        {
+            this.reason = reason;
+            this.retCode = retCode;
+            this.redirectUrl = redirectUrl;
+            this.repositoryDirectory = repositoryDirectory;
+        }
+
+        public void handle( String s, HttpServletRequest req, HttpServletResponse resp, int i )
+            throws IOException, ServletException
+        {
+            if ( req.getRequestURI().contains( "redirectRequest" ) )
+            {
+                PutHandler putHandler = new PutHandler( this.repositoryDirectory );
+                putHandler.handle( s, req, resp, i );
+                return;
+            }
+            resp.setStatus( this.retCode );
+            resp.sendRedirect( this.redirectUrl + "/" + req.getRequestURI() );
+        }
+    }
+
+
     private void runTestProxiedRequest( ProxyInfo proxyInfo, TestHeaderHandler handler )
         throws Exception
     {

Modified: maven/wagon/trunk/wagon-providers/wagon-http-shared/src/main/java/org/apache/maven/wagon/shared/http/AbstractHttpClientWagon.java
URL: http://svn.apache.org/viewvc/maven/wagon/trunk/wagon-providers/wagon-http-shared/src/main/java/org/apache/maven/wagon/shared/http/AbstractHttpClientWagon.java?rev=1300648&r1=1300647&r2=1300648&view=diff
==============================================================================
--- maven/wagon/trunk/wagon-providers/wagon-http-shared/src/main/java/org/apache/maven/wagon/shared/http/AbstractHttpClientWagon.java (original)
+++ maven/wagon/trunk/wagon-providers/wagon-http-shared/src/main/java/org/apache/maven/wagon/shared/http/AbstractHttpClientWagon.java Wed Mar 14 17:15:02 2012
@@ -31,6 +31,7 @@ import org.apache.commons.httpclient.NTC
 import org.apache.commons.httpclient.UsernamePasswordCredentials;
 import org.apache.commons.httpclient.auth.AuthScope;
 import org.apache.commons.httpclient.cookie.CookiePolicy;
+import org.apache.commons.httpclient.methods.EntityEnclosingMethod;
 import org.apache.commons.httpclient.methods.GetMethod;
 import org.apache.commons.httpclient.methods.HeadMethod;
 import org.apache.commons.httpclient.methods.PutMethod;
@@ -322,16 +323,25 @@ public abstract class AbstractHttpClient
     {
         StringBuilder url = new StringBuilder( getRepository().getUrl() );
         String[] parts = StringUtils.split( resource.getName(), "/" );
-        for ( String part : parts )// int i = 0; i < parts.length; i++ )
+        for ( String part : parts )
         {
             // TODO: Fix encoding...
-            // url += "/" + URLEncoder.encode( parts[i], System.getProperty("file.encoding") );
             if ( !url.toString().endsWith( "/" ) )
             {
                 url.append( '/' );
             }
             url.append( URLEncoder.encode( part ) );
         }
+        RequestEntityImplementation requestEntityImplementation =
+            new RequestEntityImplementation( stream, resource, this, source );
+        put( resource, source, requestEntityImplementation, url.toString() );
+
+    }
+
+    private void put( Resource resource, File source, RequestEntityImplementation requestEntityImplementation,
+                      String url )
+        throws TransferFailedException, AuthorizationException, ResourceDoesNotExistException
+    {
 
         //Parent directories need to be created before posting
         try
@@ -343,18 +353,19 @@ public abstract class AbstractHttpClient
             fireTransferError( resource, e, TransferEvent.REQUEST_GET );
         }
 
-        PutMethod putMethod = new PutMethod( url.toString() );
+        PutMethod putMethod = new PutMethod( url );
 
         firePutStarted( resource, source );
 
         try
         {
-            putMethod.setRequestEntity( new RequestEntityImplementation( stream, resource, this, source ) );
+            putMethod.setRequestEntity( requestEntityImplementation );
 
             int statusCode;
             try
             {
                 statusCode = execute( putMethod );
+
             }
             catch ( IOException e )
             {
@@ -375,6 +386,15 @@ public abstract class AbstractHttpClient
                 case HttpStatus.SC_NO_CONTENT:  // 204
                     break;
 
+                // handle all redirect even if http specs says " the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user"
+                case HttpStatus.SC_MOVED_PERMANENTLY: // 301
+                case HttpStatus.SC_MOVED_TEMPORARILY: // 302
+                case HttpStatus.SC_SEE_OTHER: // 303
+                    String relocatedUrl = calculateRelocatedUrl( putMethod );
+                    fireTransferDebug( "relocate to " + relocatedUrl );
+                    put( resource, source, requestEntityImplementation, relocatedUrl );
+                    return;
+
                 case SC_NULL:
                 {
                     TransferFailedException e = new TransferFailedException( "Failed to transfer file: " + url );
@@ -407,6 +427,14 @@ public abstract class AbstractHttpClient
         }
     }
 
+    protected String calculateRelocatedUrl( EntityEnclosingMethod method )
+    {
+        Header locationHeader = method.getResponseHeader( "Location" );
+        String locationField = locationHeader.getValue();
+        // is it a relative Location or a full ?
+        return locationField.startsWith( "http" ) ? locationField : getURL( getRepository() ) + '/' + locationField;
+    }
+
     protected void mkdirs( String dirname )
         throws IOException
     {
@@ -423,6 +451,7 @@ public abstract class AbstractHttpClient
         }
         url.append( resourceName );
         HeadMethod headMethod = new HeadMethod( url.toString() );
+
         int statusCode;
         try
         {
@@ -588,6 +617,7 @@ public abstract class AbstractHttpClient
         url.append( resource.getName() );
 
         getMethod = new GetMethod( url.toString() );
+
         long timestamp = resource.getLastModified();
         if ( timestamp > 0 )
         {

Modified: maven/wagon/trunk/wagon-providers/wagon-http-shared4/src/main/java/org/apache/maven/wagon/shared/http4/AbstractHttpClientWagon.java
URL: http://svn.apache.org/viewvc/maven/wagon/trunk/wagon-providers/wagon-http-shared4/src/main/java/org/apache/maven/wagon/shared/http4/AbstractHttpClientWagon.java?rev=1300648&r1=1300647&r2=1300648&view=diff
==============================================================================
--- maven/wagon/trunk/wagon-providers/wagon-http-shared4/src/main/java/org/apache/maven/wagon/shared/http4/AbstractHttpClientWagon.java (original)
+++ maven/wagon/trunk/wagon-providers/wagon-http-shared4/src/main/java/org/apache/maven/wagon/shared/http4/AbstractHttpClientWagon.java Wed Mar 14 17:15:02 2012
@@ -19,6 +19,7 @@ package org.apache.maven.wagon.shared.ht
  * under the License.
  */
 
+import org.apache.commons.io.IOUtils;
 import org.apache.http.Header;
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpException;
@@ -73,6 +74,7 @@ import org.codehaus.plexus.util.StringUt
 import javax.net.ssl.SSLException;
 import javax.net.ssl.SSLSession;
 import javax.net.ssl.SSLSocket;
+import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
@@ -108,11 +110,13 @@ public abstract class AbstractHttpClient
 
         private final Wagon wagon;
 
-        private InputStream stream;
+        //private InputStream stream;
+
+        private byte[] bytes;
 
         private File source;
 
-        private long length;
+        private long length = -1;
 
         private RequestEntityImplementation( final InputStream stream, final Resource resource, final Wagon wagon,
                                              final File source )
@@ -124,10 +128,18 @@ public abstract class AbstractHttpClient
             }
             else
             {
-                this.stream = stream;
+                try
+                {
+                    this.bytes = IOUtils.toByteArray( stream );
+                }
+                catch ( IOException e )
+                {
+                    throw new TransferFailedException( e.getMessage(), e );
+                }
             }
             this.resource = resource;
             this.length = resource == null ? -1 : resource.getContentLength();
+
             this.wagon = wagon;
         }
 
@@ -140,12 +152,16 @@ public abstract class AbstractHttpClient
         public InputStream getContent()
             throws IOException, IllegalStateException
         {
-            return this.source != null ? new FileInputStream( this.source ) : this.stream;
+            if ( this.source != null )
+            {
+                return new FileInputStream( this.source );
+            }
+            return new ByteArrayInputStream( this.bytes );// this.stream;
         }
 
         public boolean isRepeatable()
         {
-            return false;
+            return true;
         }
 
 
@@ -159,7 +175,8 @@ public abstract class AbstractHttpClient
             TransferEvent transferEvent =
                 new TransferEvent( wagon, resource, TransferEvent.TRANSFER_PROGRESS, TransferEvent.REQUEST_PUT );
             transferEvent.setTimestamp( System.currentTimeMillis() );
-            InputStream instream = this.source != null ? new FileInputStream( this.source ) : this.stream;
+            InputStream instream =
+                this.source != null ? new FileInputStream( this.source ) : new ByteArrayInputStream( this.bytes );
             try
             {
                 byte[] buffer = new byte[BUFFER_SIZE];
@@ -474,7 +491,8 @@ public abstract class AbstractHttpClient
     private void put( Resource resource, File source, HttpEntity httpEntity )
         throws TransferFailedException, AuthorizationException, ResourceDoesNotExistException
     {
-        StringBuilder url = new StringBuilder( getRepository().getUrl() );
+
+        StringBuilder url = new StringBuilder( getURL( getRepository() ) );
         String[] parts = StringUtils.split( resource.getName(), "/" );
         for ( String part : parts )
         {
@@ -486,6 +504,12 @@ public abstract class AbstractHttpClient
             }
             url.append( URLEncoder.encode( part ) );
         }
+        put( resource, source, httpEntity, url.toString() );
+    }
+
+    private void put( Resource resource, File source, HttpEntity httpEntity, String url )
+        throws TransferFailedException, AuthorizationException, ResourceDoesNotExistException
+    {
 
         //Parent directories need to be created before posting
         try
@@ -501,7 +525,7 @@ public abstract class AbstractHttpClient
             fireTransferError( resource, e, TransferEvent.REQUEST_GET );
         }
 
-        HttpPut putMethod = new HttpPut( url.toString() );
+        HttpPut putMethod = new HttpPut( url );
 
         firePutStarted( resource, source );
 
@@ -540,7 +564,12 @@ public abstract class AbstractHttpClient
                 case HttpStatus.SC_ACCEPTED: // 202
                 case HttpStatus.SC_NO_CONTENT:  // 204
                     break;
-
+                // handle all redirect even if http specs says " the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user"
+                case HttpStatus.SC_MOVED_PERMANENTLY: // 301
+                case HttpStatus.SC_MOVED_TEMPORARILY: // 302
+                case HttpStatus.SC_SEE_OTHER: // 303
+                    put( resource, source, httpEntity, calculateRelocatedUrl( response ) );
+                    return;
                 case SC_NULL:
                 {
                     TransferFailedException e =
@@ -574,6 +603,14 @@ public abstract class AbstractHttpClient
         }
     }
 
+    protected String calculateRelocatedUrl( HttpResponse response )
+    {
+        Header locationHeader = response.getFirstHeader( "Location" );
+        String locationField = locationHeader.getValue();
+        // is it a relative Location or a full ?
+        return locationField.startsWith( "http" ) ? locationField : getURL( getRepository() ) + '/' + locationField;
+    }
+
     protected void mkdirs( String dirname )
         throws HttpException, IOException
     {