You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by hb...@apache.org on 2013/02/09 01:25:02 UTC

[1/2] [WAGON-388] moved code dependant on HttpComponents from wagon-http-shared4 to wagon-http

http://git-wip-us.apache.org/repos/asf/maven-wagon/blob/34e9c2a0/wagon-providers/wagon-http/src/main/java/org/apache/maven/wagon/providers/http/AbstractHttpClientWagon.java
----------------------------------------------------------------------
diff --git a/wagon-providers/wagon-http/src/main/java/org/apache/maven/wagon/providers/http/AbstractHttpClientWagon.java b/wagon-providers/wagon-http/src/main/java/org/apache/maven/wagon/providers/http/AbstractHttpClientWagon.java
new file mode 100644
index 0000000..4abaded
--- /dev/null
+++ b/wagon-providers/wagon-http/src/main/java/org/apache/maven/wagon/providers/http/AbstractHttpClientWagon.java
@@ -0,0 +1,1056 @@
+package org.apache.maven.wagon.providers.http;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URLEncoder;
+import java.nio.ByteBuffer;
+import java.security.cert.X509Certificate;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Properties;
+import java.util.TimeZone;
+import java.util.zip.GZIPInputStream;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+
+import org.apache.http.Header;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpException;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.Credentials;
+import org.apache.http.auth.NTCredentials;
+import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.http.client.AuthCache;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpHead;
+import org.apache.http.client.methods.HttpPut;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.client.params.ClientPNames;
+import org.apache.http.client.params.CookiePolicy;
+import org.apache.http.client.protocol.ClientContext;
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.conn.params.ConnRoutePNames;
+import org.apache.http.conn.scheme.PlainSocketFactory;
+import org.apache.http.conn.scheme.Scheme;
+import org.apache.http.conn.scheme.SchemeRegistry;
+import org.apache.http.conn.ssl.SSLSocketFactory;
+import org.apache.http.conn.ssl.X509HostnameVerifier;
+import org.apache.http.entity.AbstractHttpEntity;
+import org.apache.http.impl.auth.BasicScheme;
+import org.apache.http.impl.client.BasicAuthCache;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.impl.conn.BasicClientConnectionManager;
+import org.apache.http.impl.conn.PoolingClientConnectionManager;
+import org.apache.http.impl.cookie.DateParseException;
+import org.apache.http.impl.cookie.DateUtils;
+import org.apache.http.message.BasicHeader;
+import org.apache.http.params.CoreConnectionPNames;
+import org.apache.http.params.CoreProtocolPNames;
+import org.apache.http.params.HttpParams;
+import org.apache.http.protocol.BasicHttpContext;
+import org.apache.maven.wagon.InputData;
+import org.apache.maven.wagon.OutputData;
+import org.apache.maven.wagon.PathUtils;
+import org.apache.maven.wagon.ResourceDoesNotExistException;
+import org.apache.maven.wagon.StreamWagon;
+import org.apache.maven.wagon.TransferFailedException;
+import org.apache.maven.wagon.Wagon;
+import org.apache.maven.wagon.authorization.AuthorizationException;
+import org.apache.maven.wagon.events.TransferEvent;
+import org.apache.maven.wagon.proxy.ProxyInfo;
+import org.apache.maven.wagon.repository.Repository;
+import org.apache.maven.wagon.resource.Resource;
+import org.codehaus.plexus.util.IOUtil;
+import org.codehaus.plexus.util.StringUtils;
+
+/**
+ * @author <a href="michal.maczka@dimatics.com">Michal Maczka</a>
+ * @author <a href="mailto:james@atlassian.com">James William Dumay</a>
+ */
+public abstract class AbstractHttpClientWagon
+    extends StreamWagon
+{
+
+    private BasicHttpContext localContext;
+
+    private final class RequestEntityImplementation
+        extends AbstractHttpEntity
+    {
+
+        private final static int BUFFER_SIZE = 2048;
+
+        private final Resource resource;
+
+        private final Wagon wagon;
+
+        private ByteBuffer byteBuffer;
+
+        private File source;
+
+        private long length = -1;
+
+        private RequestEntityImplementation( final InputStream stream, final Resource resource, final Wagon wagon,
+                                             final File source )
+            throws TransferFailedException
+        {
+            if ( source != null )
+            {
+                this.source = source;
+            }
+            else
+            {
+                try
+                {
+                    byte[] bytes = IOUtil.toByteArray( stream );
+                    byteBuffer = ByteBuffer.allocate( bytes.length );
+                    byteBuffer.put( bytes );
+                }
+                catch ( IOException e )
+                {
+                    throw new TransferFailedException( e.getMessage(), e );
+                }
+            }
+            this.resource = resource;
+            this.length = resource == null ? -1 : resource.getContentLength();
+
+            this.wagon = wagon;
+        }
+
+        public long getContentLength()
+        {
+            return length;
+        }
+
+        public InputStream getContent()
+            throws IOException, IllegalStateException
+        {
+            if ( this.source != null )
+            {
+                return new FileInputStream( this.source );
+            }
+            return new ByteArrayInputStream( this.byteBuffer.array() );
+        }
+
+        public boolean isRepeatable()
+        {
+            return true;
+        }
+
+        public void writeTo( final OutputStream outstream )
+            throws IOException
+        {
+            if ( outstream == null )
+            {
+                throw new IllegalArgumentException( "Output stream may not be null" );
+            }
+            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 )
+                : new ByteArrayInputStream( this.byteBuffer.array() );
+            try
+            {
+                byte[] buffer = new byte[BUFFER_SIZE];
+                int l;
+                if ( this.length < 0 )
+                {
+                    // until EOF
+                    while ( ( l = instream.read( buffer ) ) != -1 )
+                    {
+                        fireTransferProgress( transferEvent, buffer, -1 );
+                        outstream.write( buffer, 0, l );
+                    }
+                }
+                else
+                {
+                    // no need to consume more than length
+                    long remaining = this.length;
+                    while ( remaining > 0 )
+                    {
+                        l = instream.read( buffer, 0, (int) Math.min( BUFFER_SIZE, remaining ) );
+                        if ( l == -1 )
+                        {
+                            break;
+                        }
+                        fireTransferProgress( transferEvent, buffer, (int) Math.min( BUFFER_SIZE, remaining ) );
+                        outstream.write( buffer, 0, l );
+                        remaining -= l;
+                    }
+                }
+            }
+            finally
+            {
+                instream.close();
+            }
+        }
+
+        public boolean isStreaming()
+        {
+            return true;
+        }
+    }
+
+    protected static final int SC_NULL = -1;
+
+    protected static final TimeZone GMT_TIME_ZONE = TimeZone.getTimeZone( "GMT" );
+
+    private DefaultHttpClient client;
+
+    /**
+     * @since 2.0
+     */
+    protected static ClientConnectionManager connectionManagerPooled;
+
+    /**
+     * @since 2.0
+     */
+    protected ClientConnectionManager clientConnectionManager =
+        new BasicClientConnectionManager( createSchemeRegistry() );
+
+    /**
+     * use http(s) connection pool mechanism.
+     * <b>enabled by default</b>
+     *
+     * @since 2.0
+     */
+    protected static boolean useClientManagerPooled =
+        Boolean.valueOf( System.getProperty( "maven.wagon.http.pool", "true" ) );
+
+    /**
+     * skip failure on certificate validity checks.
+     * <b>disabled by default</b>
+     *
+     * @since 2.0
+     */
+    protected static boolean sslInsecure = Boolean.valueOf( System.getProperty( "maven.wagon.http.ssl.insecure", "false" ) );
+
+    /**
+     * if using sslInsecure, certificate date issues will be ignored
+     * <b>disabled by default</b>
+     *
+     * @since 2.0
+     */
+    protected static boolean IGNORE_SSL_VALIDITY_DATES =
+        Boolean.valueOf( System.getProperty( "maven.wagon.http.ssl.ignore.validity.dates", "false" ) );
+
+    /**
+     * If enabled, ssl hostname verifier does not check hostname. Disable this will use a browser compat hostname verifier
+     * <b>disabled by default</b>
+     *
+     * @since 2.0
+     * @see BrowserCompatHostnameVerifier
+     */
+    protected static boolean sslAllowAll =
+        Boolean.valueOf( System.getProperty( "maven.wagon.http.ssl.allowall", "false" ) );
+
+    private static SchemeRegistry createSchemeRegistry()
+    {
+        SchemeRegistry schemeRegistry = new SchemeRegistry();
+        schemeRegistry.register( new Scheme( "http", 80, PlainSocketFactory.getSocketFactory() ) );
+        SSLSocketFactory sslSocketFactory;
+        if ( sslInsecure )
+        {
+            try
+            {
+                sslSocketFactory = new SSLSocketFactory(
+                    RelaxedX509TrustManager.createRelaxedSSLContext(),
+                    sslAllowAll ? new RelaxedHostNameVerifier() : SSLSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER );
+            }
+            catch ( IOException e )
+            {
+                throw new RuntimeException( "failed to init SSLSocket Factory " + e.getMessage(), e );
+            }
+        }
+        else
+        {
+            sslSocketFactory = new SSLSocketFactory(
+                HttpsURLConnection.getDefaultSSLSocketFactory(),
+                SSLSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER );
+        }
+
+        Scheme httpsScheme = new Scheme( "https", 443, new ConfigurableSSLSocketFactoryDecorator( sslSocketFactory ) );
+        schemeRegistry.register( httpsScheme );
+
+        return schemeRegistry;
+    }
+
+    static
+    {
+        if ( !useClientManagerPooled )
+        {
+            System.out.println( "http connection pool disabled in wagon http" );
+        }
+        else
+        {
+            PoolingClientConnectionManager poolingClientConnectionManager =
+                new PoolingClientConnectionManager( createSchemeRegistry() );
+            int maxPerRoute =
+                Integer.parseInt( System.getProperty( "maven.wagon.httpconnectionManager.maxPerRoute", "20" ) );
+            poolingClientConnectionManager.setDefaultMaxPerRoute( maxPerRoute );
+            int maxTotal = Integer.parseInt( System.getProperty( "maven.wagon.httpconnectionManager.maxTotal", "40" ) );
+            poolingClientConnectionManager.setDefaultMaxPerRoute( maxPerRoute );
+            poolingClientConnectionManager.setMaxTotal( maxTotal );
+
+            connectionManagerPooled = poolingClientConnectionManager;
+        }
+    }
+
+    /**
+     * disable all host name verification
+     *
+     * @since 2.0
+     */
+    private static class RelaxedHostNameVerifier
+        implements X509HostnameVerifier
+    {
+        public void verify( String s, SSLSocket sslSocket )
+            throws IOException
+        {
+            //no op
+        }
+
+        public void verify( String s, X509Certificate x509Certificate )
+            throws SSLException
+        {
+            //no op
+        }
+
+        public void verify( String s, String[] strings, String[] strings1 )
+            throws SSLException
+        {
+            //no op
+        }
+
+        public boolean verify( String s, SSLSession sslSession )
+        {
+            return true;
+        }
+    }
+
+    public ClientConnectionManager getConnectionManager()
+    {
+        if ( !useClientManagerPooled )
+        {
+            return clientConnectionManager;
+        }
+        return connectionManagerPooled;
+    }
+
+    public static void setConnectionManagerPooled( ClientConnectionManager clientConnectionManager )
+    {
+        connectionManagerPooled = clientConnectionManager;
+    }
+
+    public static void setUseClientManagerPooled( boolean pooledClientManager )
+    {
+        useClientManagerPooled = pooledClientManager;
+    }
+
+    /**
+     * @plexus.configuration
+     * @deprecated Use httpConfiguration instead.
+     */
+    private Properties httpHeaders;
+
+    /**
+     * @since 1.0-beta-6
+     */
+    private HttpConfiguration httpConfiguration;
+
+    private HttpGet getMethod;
+
+    public void openConnectionInternal()
+    {
+        repository.setUrl( getURL( repository ) );
+        client = new DefaultHttpClient( getConnectionManager() );
+
+        // WAGON-273: default the cookie-policy to browser compatible
+        client.getParams().setParameter( ClientPNames.COOKIE_POLICY, CookiePolicy.BROWSER_COMPATIBILITY );
+
+        if ( authenticationInfo != null )
+        {
+
+            String username = authenticationInfo.getUserName();
+            String password = authenticationInfo.getPassword();
+
+            if ( StringUtils.isNotEmpty( username ) && StringUtils.isNotEmpty( password ) )
+            {
+                Credentials creds = new UsernamePasswordCredentials( username, password );
+
+                String host = getRepository().getHost();
+                int port = getRepository().getPort() > -1 ? getRepository().getPort() : AuthScope.ANY_PORT;
+
+                client.getCredentialsProvider().setCredentials( new AuthScope( host, port ), creds );
+                // preemptive off by default
+                /*
+                AuthCache authCache = new BasicAuthCache();
+                BasicScheme basicAuth = new BasicScheme();
+                HttpHost targetHost =
+                    new HttpHost( repository.getHost(), repository.getPort(), repository.getProtocol() );
+                authCache.put( targetHost, basicAuth );
+
+                localContext = new BasicHttpContext();
+                localContext.setAttribute( ClientContext.AUTH_CACHE, authCache );
+                */
+            }
+        }
+
+        ProxyInfo proxyInfo = getProxyInfo( getRepository().getProtocol(), getRepository().getHost() );
+        if ( proxyInfo != null )
+        {
+            String proxyUsername = proxyInfo.getUserName();
+            String proxyPassword = proxyInfo.getPassword();
+            String proxyHost = proxyInfo.getHost();
+            int proxyPort = proxyInfo.getPort();
+            String proxyNtlmHost = proxyInfo.getNtlmHost();
+            String proxyNtlmDomain = proxyInfo.getNtlmDomain();
+            if ( proxyHost != null )
+            {
+                HttpHost proxy = new HttpHost( proxyHost, proxyPort );
+
+                if ( proxyUsername != null && proxyPassword != null )
+                {
+                    Credentials creds;
+                    if ( proxyNtlmHost != null || proxyNtlmDomain != null )
+                    {
+                        creds = new NTCredentials( proxyUsername, proxyPassword, proxyNtlmHost, proxyNtlmDomain );
+                    }
+                    else
+                    {
+                        creds = new UsernamePasswordCredentials( proxyUsername, proxyPassword );
+                    }
+
+                    int port = proxyInfo.getPort() > -1 ? proxyInfo.getPort() : AuthScope.ANY_PORT;
+
+                    AuthScope authScope = new AuthScope( proxyHost, port );
+                    client.getCredentialsProvider().setCredentials( authScope, creds );
+                }
+
+                client.getParams().setParameter( ConnRoutePNames.DEFAULT_PROXY, proxy );
+            }
+        }
+    }
+
+    public void closeConnection()
+    {
+        if ( !useClientManagerPooled )
+        {
+            getConnectionManager().shutdown();
+        }
+    }
+
+    public void put( File source, String resourceName )
+        throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
+    {
+        Resource resource = new Resource( resourceName );
+
+        firePutInitiated( resource, source );
+
+        resource.setContentLength( source.length() );
+
+        resource.setLastModified( source.lastModified() );
+
+        put( null, resource, source );
+    }
+
+    public void putFromStream( final InputStream stream, String destination, long contentLength, long lastModified )
+        throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
+    {
+        Resource resource = new Resource( destination );
+
+        firePutInitiated( resource, null );
+
+        resource.setContentLength( contentLength );
+
+        resource.setLastModified( lastModified );
+
+        put( stream, resource, null );
+    }
+
+    private void put( final InputStream stream, Resource resource, File source )
+        throws TransferFailedException, AuthorizationException, ResourceDoesNotExistException
+    {
+        put( resource, source, new RequestEntityImplementation( stream, resource, this, source ) );
+    }
+
+    private void put( Resource resource, File source, HttpEntity httpEntity )
+        throws TransferFailedException, AuthorizationException, ResourceDoesNotExistException
+    {
+
+        StringBuilder url = new StringBuilder( getURL( getRepository() ) );
+        String[] parts = StringUtils.split( resource.getName(), "/" );
+        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 ) );
+        }
+        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
+        {
+            mkdirs( PathUtils.dirname( resource.getName() ) );
+        }
+        catch ( HttpException he )
+        {
+            fireTransferError( resource, he, TransferEvent.REQUEST_GET );
+        }
+        catch ( IOException e )
+        {
+            fireTransferError( resource, e, TransferEvent.REQUEST_GET );
+        }
+
+        if ( authenticationInfo != null )
+        {
+            String username = authenticationInfo.getUserName();
+            String password = authenticationInfo.getPassword();
+            // preemptive for put
+            if ( StringUtils.isNotEmpty( username ) && StringUtils.isNotEmpty( password ) )
+            {
+                AuthCache authCache = new BasicAuthCache();
+                BasicScheme basicAuth = new BasicScheme();
+                HttpHost targetHost =
+                    new HttpHost( repository.getHost(), repository.getPort(), repository.getProtocol() );
+                authCache.put( targetHost, basicAuth );
+
+                localContext = new BasicHttpContext();
+                localContext.setAttribute( ClientContext.AUTH_CACHE, authCache );
+            }
+        }
+
+        HttpPut putMethod = new HttpPut( url );
+
+        firePutStarted( resource, source );
+
+        try
+        {
+            putMethod.setEntity( httpEntity );
+
+            HttpResponse response;
+            try
+            {
+                response = execute( putMethod );
+            }
+            catch ( IOException e )
+            {
+                fireTransferError( resource, e, TransferEvent.REQUEST_PUT );
+
+                throw new TransferFailedException( e.getMessage(), e );
+            }
+            catch ( HttpException e )
+            {
+                fireTransferError( resource, e, TransferEvent.REQUEST_PUT );
+
+                throw new TransferFailedException( e.getMessage(), e );
+            }
+
+            int statusCode = response.getStatusLine().getStatusCode();
+            String reasonPhrase = ", ReasonPhrase: " + response.getStatusLine().getReasonPhrase() + ".";
+            fireTransferDebug( url + " - Status code: " + statusCode + reasonPhrase );
+
+            // Check that we didn't run out of retries.
+            switch ( statusCode )
+            {
+                // Success Codes
+                case HttpStatus.SC_OK: // 200
+                case HttpStatus.SC_CREATED: // 201
+                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 =
+                        new TransferFailedException( "Failed to transfer file: " + url + reasonPhrase );
+                    fireTransferError( resource, e, TransferEvent.REQUEST_PUT );
+                    throw e;
+                }
+
+                case HttpStatus.SC_FORBIDDEN:
+                    fireSessionConnectionRefused();
+                    throw new AuthorizationException( "Access denied to: " + url + reasonPhrase );
+
+                case HttpStatus.SC_NOT_FOUND:
+                    throw new ResourceDoesNotExistException( "File: " + url + " does not exist" + reasonPhrase );
+
+                    //add more entries here
+                default:
+                {
+                    TransferFailedException e = new TransferFailedException(
+                        "Failed to transfer file: " + url + ". Return code is: " + statusCode + reasonPhrase );
+                    fireTransferError( resource, e, TransferEvent.REQUEST_PUT );
+                    throw e;
+                }
+            }
+
+            firePutCompleted( resource, source );
+        }
+        finally
+        {
+            putMethod.abort();
+        }
+    }
+
+    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
+    {
+        // nothing to do
+    }
+
+    public boolean resourceExists( String resourceName )
+        throws TransferFailedException, AuthorizationException
+    {
+        String repositoryUrl = getRepository().getUrl();
+        String url = repositoryUrl + ( repositoryUrl.endsWith( "/" ) ? "" : "/" ) + resourceName;
+        HttpHead headMethod = new HttpHead( url );
+        HttpResponse response = null;
+        int statusCode;
+        try
+        {
+            response = execute( headMethod );
+        }
+        catch ( IOException e )
+        {
+            throw new TransferFailedException( e.getMessage(), e );
+        }
+        catch ( HttpException e )
+        {
+            throw new TransferFailedException( e.getMessage(), e );
+        }
+
+        try
+        {
+            statusCode = response.getStatusLine().getStatusCode();
+            String reasonPhrase = ", ReasonPhrase: " + response.getStatusLine().getReasonPhrase() + ".";
+            switch ( statusCode )
+            {
+                case HttpStatus.SC_OK:
+                    return true;
+
+                case HttpStatus.SC_NOT_MODIFIED:
+                    return true;
+
+                case SC_NULL:
+                    throw new TransferFailedException( "Failed to transfer file: " + url + reasonPhrase );
+
+                case HttpStatus.SC_FORBIDDEN:
+                    throw new AuthorizationException( "Access denied to: " + url + reasonPhrase );
+
+                case HttpStatus.SC_UNAUTHORIZED:
+                    throw new AuthorizationException( "Not authorized " + reasonPhrase );
+
+                case HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED:
+                    throw new AuthorizationException( "Not authorized by proxy " + reasonPhrase );
+
+                case HttpStatus.SC_NOT_FOUND:
+                    return false;
+
+                //add more entries here
+                default:
+                    throw new TransferFailedException(
+                        "Failed to transfer file: " + url + ". Return code is: " + statusCode + reasonPhrase );
+            }
+        }
+        finally
+        {
+            headMethod.abort();
+        }
+    }
+
+    protected HttpResponse execute( HttpUriRequest httpMethod )
+        throws HttpException, IOException
+    {
+        setParameters( httpMethod );
+        setHeaders( httpMethod );
+        client.getParams().setParameter( CoreProtocolPNames.USER_AGENT, getUserAgent( httpMethod ) );
+
+        ProxyInfo proxyInfo = getProxyInfo( getRepository().getProtocol(), getRepository().getHost() );
+
+        if ( proxyInfo != null )
+        {
+            if ( proxyInfo.getUserName() != null && proxyInfo.getPassword() != null )
+            {
+                Credentials creds;
+                if ( proxyInfo.getNtlmHost() != null || proxyInfo.getNtlmDomain() != null )
+                {
+                    creds =
+                        new NTCredentials( proxyInfo.getUserName(), proxyInfo.getPassword(), proxyInfo.getNtlmHost(),
+                                           proxyInfo.getNtlmDomain() );
+                }
+                else
+                {
+                    creds = new UsernamePasswordCredentials( proxyInfo.getUserName(), proxyInfo.getPassword() );
+                }
+
+                Header bs = new BasicScheme().authenticate( creds, httpMethod );
+                httpMethod.addHeader( "Proxy-Authorization", bs.getValue() );
+            }
+
+        }
+
+        return client.execute( httpMethod, localContext );
+    }
+
+    protected void setParameters( HttpUriRequest method )
+    {
+        HttpMethodConfiguration config =
+            httpConfiguration == null ? null : httpConfiguration.getMethodConfiguration( method );
+        if ( config != null )
+        {
+            HttpParams params = config.asMethodParams( method.getParams() );
+
+            if ( config.isUsePreemptive() && authenticationInfo != null )
+            {
+                String username = authenticationInfo.getUserName();
+                String password = authenticationInfo.getPassword();
+
+                if ( StringUtils.isNotEmpty( username ) && StringUtils.isNotEmpty( password ) )
+                {
+
+                    AuthCache authCache = new BasicAuthCache();
+                    BasicScheme basicAuth = new BasicScheme();
+                    HttpHost targetHost =
+                        new HttpHost( repository.getHost(), repository.getPort(), repository.getProtocol() );
+                    authCache.put( targetHost, basicAuth );
+
+                    localContext = new BasicHttpContext();
+                    localContext.setAttribute( ClientContext.AUTH_CACHE, authCache );
+                }
+
+            }
+
+            if ( params != null )
+            {
+                method.setParams( params );
+            }
+        }
+
+        if ( config == null )
+        {
+            int readTimeout = getReadTimeout();
+            method.getParams().setParameter( CoreConnectionPNames.SO_TIMEOUT, readTimeout );
+        }
+    }
+
+    protected void setHeaders( HttpUriRequest method )
+    {
+        HttpMethodConfiguration config =
+            httpConfiguration == null ? null : httpConfiguration.getMethodConfiguration( method );
+        if ( config == null || config.isUseDefaultHeaders() )
+        {
+            // TODO: merge with the other headers and have some better defaults, unify with lightweight headers
+            method.addHeader( "Cache-control", "no-cache" );
+            method.addHeader( "Cache-store", "no-store" );
+            method.addHeader( "Pragma", "no-cache" );
+            method.addHeader( "Expires", "0" );
+            method.addHeader( "Accept-Encoding", "gzip" );
+        }
+
+        if ( httpHeaders != null )
+        {
+            for ( Map.Entry<Object, Object> entry : httpHeaders.entrySet() )
+            {
+                method.addHeader( (String) entry.getKey(), (String) entry.getValue() );
+            }
+        }
+
+        Header[] headers = config == null ? null : config.asRequestHeaders();
+        if ( headers != null )
+        {
+            for ( int i = 0; i < headers.length; i++ )
+            {
+                method.addHeader( headers[i] );
+            }
+        }
+    }
+
+    protected String getUserAgent( HttpUriRequest method )
+    {
+        if ( httpHeaders != null )
+        {
+            String value = (String) httpHeaders.get( "User-Agent" );
+            if ( value != null )
+            {
+                return value;
+            }
+        }
+        HttpMethodConfiguration config =
+            httpConfiguration == null ? null : httpConfiguration.getMethodConfiguration( method );
+
+        if ( config != null )
+        {
+            return (String) config.getHeaders().get( "User-Agent" );
+        }
+        return null;
+    }
+
+    /**
+     * getUrl
+     * Implementors can override this to remove unwanted parts of the url such as role-hints
+     *
+     * @param repository
+     * @return
+     */
+    protected String getURL( Repository repository )
+    {
+        return repository.getUrl();
+    }
+
+    public HttpConfiguration getHttpConfiguration()
+    {
+        return httpConfiguration;
+    }
+
+    public void setHttpConfiguration( HttpConfiguration httpConfiguration )
+    {
+        this.httpConfiguration = httpConfiguration;
+    }
+
+    public void fillInputData( InputData inputData )
+        throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
+    {
+        Resource resource = inputData.getResource();
+
+        String repositoryUrl = getRepository().getUrl();
+        String url = repositoryUrl + ( repositoryUrl.endsWith( "/" ) ? "" : "/" ) + resource.getName();
+        getMethod = new HttpGet( url );
+        long timestamp = resource.getLastModified();
+        if ( timestamp > 0 )
+        {
+            SimpleDateFormat fmt = new SimpleDateFormat( "EEE, dd-MMM-yy HH:mm:ss zzz", Locale.US );
+            fmt.setTimeZone( GMT_TIME_ZONE );
+            Header hdr = new BasicHeader( "If-Modified-Since", fmt.format( new Date( timestamp ) ) );
+            fireTransferDebug( "sending ==> " + hdr + "(" + timestamp + ")" );
+            getMethod.addHeader( hdr );
+        }
+
+        HttpResponse response;
+        int statusCode;
+        try
+        {
+            response = execute( getMethod );
+        }
+        catch ( IOException e )
+        {
+            fireTransferError( resource, e, TransferEvent.REQUEST_GET );
+
+            throw new TransferFailedException( e.getMessage(), e );
+        }
+        catch ( HttpException e )
+        {
+            fireTransferError( resource, e, TransferEvent.REQUEST_GET );
+
+            throw new TransferFailedException( e.getMessage(), e );
+        }
+
+        statusCode = response.getStatusLine().getStatusCode();
+
+        String reasonPhrase = ", ReasonPhrase:" + response.getStatusLine().getReasonPhrase() + ".";
+
+        fireTransferDebug( url + " - Status code: " + statusCode + reasonPhrase );
+
+        // TODO [BP]: according to httpclient docs, really should swallow the output on error. verify if that is
+        // required
+        switch ( statusCode )
+        {
+            case HttpStatus.SC_OK:
+                break;
+
+            case HttpStatus.SC_NOT_MODIFIED:
+                // return, leaving last modified set to original value so getIfNewer should return unmodified
+                return;
+
+            case SC_NULL:
+            {
+                TransferFailedException e =
+                    new TransferFailedException( "Failed to transfer file: " + url + " " + reasonPhrase );
+                fireTransferError( resource, e, TransferEvent.REQUEST_GET );
+                throw e;
+            }
+
+            case HttpStatus.SC_FORBIDDEN:
+                fireSessionConnectionRefused();
+                throw new AuthorizationException( "Access denied to: " + url + " " + reasonPhrase );
+
+            case HttpStatus.SC_UNAUTHORIZED:
+                fireSessionConnectionRefused();
+                throw new AuthorizationException( "Not authorized " + reasonPhrase );
+
+            case HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED:
+                fireSessionConnectionRefused();
+                throw new AuthorizationException( "Not authorized by proxy " + reasonPhrase );
+
+            case HttpStatus.SC_NOT_FOUND:
+                throw new ResourceDoesNotExistException( "File: " + url + " " + reasonPhrase );
+
+                // add more entries here
+            default:
+            {
+                cleanupGetTransfer( resource );
+                TransferFailedException e = new TransferFailedException(
+                    "Failed to transfer file: " + url + ". Return code is: " + statusCode + " " + reasonPhrase );
+                fireTransferError( resource, e, TransferEvent.REQUEST_GET );
+                throw e;
+            }
+        }
+
+        InputStream is;
+
+        Header contentLengthHeader = response.getFirstHeader( "Content-Length" );
+
+        if ( contentLengthHeader != null )
+        {
+            try
+            {
+                long contentLength = Long.parseLong( contentLengthHeader.getValue() );
+
+                resource.setContentLength( contentLength );
+            }
+            catch ( NumberFormatException e )
+            {
+                fireTransferDebug(
+                    "error parsing content length header '" + contentLengthHeader.getValue() + "' " + e );
+            }
+        }
+
+        Header lastModifiedHeader = response.getFirstHeader( "Last-Modified" );
+
+        long lastModified = 0;
+
+        if ( lastModifiedHeader != null )
+        {
+            try
+            {
+                lastModified = DateUtils.parseDate( lastModifiedHeader.getValue() ).getTime();
+
+                resource.setLastModified( lastModified );
+            }
+            catch ( DateParseException e )
+            {
+                fireTransferDebug( "Unable to parse last modified header" );
+            }
+
+            fireTransferDebug( "last-modified = " + lastModifiedHeader.getValue() + " (" + lastModified + ")" );
+        }
+
+        Header contentEncoding = response.getFirstHeader( "Content-Encoding" );
+        boolean isGZipped = contentEncoding == null ? false : "gzip".equalsIgnoreCase( contentEncoding.getValue() );
+
+        try
+        {
+            is = response.getEntity().getContent();
+
+            if ( isGZipped )
+            {
+                is = new GZIPInputStream( is );
+            }
+        }
+        catch ( IOException e )
+        {
+            fireTransferError( resource, e, TransferEvent.REQUEST_GET );
+
+            String msg =
+                "Error occurred while retrieving from remote repository " + getRepository() + ": " + e.getMessage();
+
+            throw new TransferFailedException( msg, e );
+        }
+
+        inputData.setInputStream( is );
+    }
+
+    protected void cleanupGetTransfer( Resource resource )
+    {
+        if ( getMethod != null )
+        {
+            getMethod.abort();
+        }
+    }
+
+
+    @Override
+    public void putFromStream( InputStream stream, String destination )
+        throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
+    {
+        putFromStream( stream, destination, -1, -1 );
+    }
+
+    @Override
+    protected void putFromStream( InputStream stream, Resource resource )
+        throws TransferFailedException, AuthorizationException, ResourceDoesNotExistException
+    {
+        putFromStream( stream, resource.getName(), -1, -1 );
+    }
+
+    public Properties getHttpHeaders()
+    {
+        return httpHeaders;
+    }
+
+    public void setHttpHeaders( Properties httpHeaders )
+    {
+        this.httpHeaders = httpHeaders;
+    }
+
+    @Override
+    public void fillOutputData( OutputData outputData )
+        throws TransferFailedException
+    {
+        // no needed in this implementation but throw an Exception if used
+        throw new IllegalStateException( "this wagon http client must not use fillOutputData" );
+    }
+}

http://git-wip-us.apache.org/repos/asf/maven-wagon/blob/34e9c2a0/wagon-providers/wagon-http/src/main/java/org/apache/maven/wagon/providers/http/ConfigurableSSLSocketFactoryDecorator.java
----------------------------------------------------------------------
diff --git a/wagon-providers/wagon-http/src/main/java/org/apache/maven/wagon/providers/http/ConfigurableSSLSocketFactoryDecorator.java b/wagon-providers/wagon-http/src/main/java/org/apache/maven/wagon/providers/http/ConfigurableSSLSocketFactoryDecorator.java
new file mode 100644
index 0000000..d3ab658
--- /dev/null
+++ b/wagon-providers/wagon-http/src/main/java/org/apache/maven/wagon/providers/http/ConfigurableSSLSocketFactoryDecorator.java
@@ -0,0 +1,88 @@
+package org.apache.maven.wagon.providers.http;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.UnknownHostException;
+
+import javax.net.ssl.SSLSocket;
+
+import org.apache.http.conn.ConnectTimeoutException;
+import org.apache.http.conn.scheme.SchemeLayeredSocketFactory;
+import org.apache.http.params.HttpParams;
+import org.codehaus.plexus.util.StringUtils;
+
+/**
+ * @since 2.4
+ */
+class ConfigurableSSLSocketFactoryDecorator
+    implements SchemeLayeredSocketFactory
+{
+
+    private final SchemeLayeredSocketFactory sslSocketFactory;
+
+    public ConfigurableSSLSocketFactoryDecorator( SchemeLayeredSocketFactory sslSocketFactory )
+    {
+        super();
+        this.sslSocketFactory = sslSocketFactory;
+    }
+
+    public Socket createSocket( final HttpParams params )
+        throws IOException
+    {
+        return enableSslProtocols( this.sslSocketFactory.createSocket( params ) );
+    }
+
+    public Socket createLayeredSocket( final Socket socket, final String target, int port, final HttpParams params )
+        throws IOException, UnknownHostException
+    {
+        return enableSslProtocols( this.sslSocketFactory.createLayeredSocket( socket, target, port, params ) );
+    }
+
+    public Socket connectSocket( final Socket sock, final InetSocketAddress remoteAddress,
+                                 final InetSocketAddress localAddress, final HttpParams params )
+        throws IOException, UnknownHostException, ConnectTimeoutException
+    {
+        return this.sslSocketFactory.connectSocket( sock, remoteAddress, localAddress, params );
+    }
+
+    public boolean isSecure( final Socket sock )
+        throws IllegalArgumentException
+    {
+        return this.sslSocketFactory.isSecure( sock );
+    }
+
+    protected Socket enableSslProtocols( Socket socket )
+    {
+        String httpsProtocols = System.getProperty( "https.protocols" );
+        if ( StringUtils.isNotEmpty( httpsProtocols ) )
+        {
+            String[] protocols = StringUtils.split( httpsProtocols, "," );
+            if ( socket instanceof SSLSocket )
+            {
+                ( (SSLSocket) socket ).setEnabledProtocols( protocols );
+            }
+        }
+
+        return socket;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/maven-wagon/blob/34e9c2a0/wagon-providers/wagon-http/src/main/java/org/apache/maven/wagon/providers/http/HttpConfiguration.java
----------------------------------------------------------------------
diff --git a/wagon-providers/wagon-http/src/main/java/org/apache/maven/wagon/providers/http/HttpConfiguration.java b/wagon-providers/wagon-http/src/main/java/org/apache/maven/wagon/providers/http/HttpConfiguration.java
new file mode 100644
index 0000000..cacad63
--- /dev/null
+++ b/wagon-providers/wagon-http/src/main/java/org/apache/maven/wagon/providers/http/HttpConfiguration.java
@@ -0,0 +1,104 @@
+package org.apache.maven.wagon.providers.http;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpHead;
+import org.apache.http.client.methods.HttpPut;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.protocol.HTTP;
+
+public class HttpConfiguration
+{
+    
+    private static final HttpMethodConfiguration DEFAULT_PUT =
+        new HttpMethodConfiguration().addParam( HTTP.EXPECT_CONTINUE, "%b,true" );
+
+    private HttpMethodConfiguration all;
+
+    private HttpMethodConfiguration get;
+
+    private HttpMethodConfiguration put;
+
+    private HttpMethodConfiguration head;
+
+    public HttpMethodConfiguration getAll()
+    {
+        return all;
+    }
+
+    public HttpConfiguration setAll( HttpMethodConfiguration all )
+    {
+        this.all = all;
+        return this;
+    }
+
+    public HttpMethodConfiguration getGet()
+    {
+        return get;
+    }
+
+    public HttpConfiguration setGet( HttpMethodConfiguration get )
+    {
+        this.get = get;
+        return this;
+    }
+
+    public HttpMethodConfiguration getPut()
+    {
+        return put;
+    }
+
+    public HttpConfiguration setPut( HttpMethodConfiguration put )
+    {
+        this.put = put;
+        return this;
+    }
+
+    public HttpMethodConfiguration getHead()
+    {
+        return head;
+    }
+
+    public HttpConfiguration setHead( HttpMethodConfiguration head )
+    {
+        this.head = head;
+        return this;
+    }
+
+    public HttpMethodConfiguration getMethodConfiguration( HttpUriRequest method )
+    {
+        if ( method instanceof HttpGet )
+        {
+            return HttpMethodConfiguration.merge( all, get );
+        }
+        else if ( method instanceof HttpPut )
+        {
+            return HttpMethodConfiguration.merge( DEFAULT_PUT, all, put );
+        }
+        else if ( method instanceof HttpHead )
+        {
+            return HttpMethodConfiguration.merge( all, head );
+        }
+
+        return all;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/maven-wagon/blob/34e9c2a0/wagon-providers/wagon-http/src/main/java/org/apache/maven/wagon/providers/http/HttpMethodConfiguration.java
----------------------------------------------------------------------
diff --git a/wagon-providers/wagon-http/src/main/java/org/apache/maven/wagon/providers/http/HttpMethodConfiguration.java b/wagon-providers/wagon-http/src/main/java/org/apache/maven/wagon/providers/http/HttpMethodConfiguration.java
new file mode 100644
index 0000000..8fb01e1
--- /dev/null
+++ b/wagon-providers/wagon-http/src/main/java/org/apache/maven/wagon/providers/http/HttpMethodConfiguration.java
@@ -0,0 +1,362 @@
+package org.apache.maven.wagon.providers.http;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.http.Header;
+import org.apache.http.message.BasicHeader;
+import org.apache.http.params.BasicHttpParams;
+import org.apache.http.params.CoreConnectionPNames;
+import org.apache.http.params.DefaultedHttpParams;
+import org.apache.http.params.HttpParams;
+import org.apache.maven.wagon.Wagon;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class HttpMethodConfiguration
+{
+
+    private static final String COERCE_PATTERN = "%(\\w+),(.+)";
+
+    private Boolean useDefaultHeaders;
+
+    private Properties headers = new Properties();
+
+    private Properties params = new Properties();
+
+    private int connectionTimeout = Wagon.DEFAULT_CONNECTION_TIMEOUT;
+
+    private int readTimeout =
+        Integer.parseInt( System.getProperty( "maven.wagon.rto", Integer.toString( Wagon.DEFAULT_READ_TIMEOUT ) ) );
+
+    private boolean usePreemptive = false;
+
+    public boolean isUseDefaultHeaders()
+    {
+        return useDefaultHeaders == null || useDefaultHeaders.booleanValue();
+    }
+
+    public HttpMethodConfiguration setUseDefaultHeaders( boolean useDefaultHeaders )
+    {
+        this.useDefaultHeaders = Boolean.valueOf( useDefaultHeaders );
+        return this;
+    }
+
+    public Boolean getUseDefaultHeaders()
+    {
+        return useDefaultHeaders;
+    }
+
+    public HttpMethodConfiguration addHeader( String header, String value )
+    {
+        headers.setProperty( header, value );
+        return this;
+    }
+
+    public Properties getHeaders()
+    {
+        return headers;
+    }
+
+    public HttpMethodConfiguration setHeaders( Properties headers )
+    {
+        this.headers = headers;
+        return this;
+    }
+
+    public HttpMethodConfiguration addParam( String param, String value )
+    {
+        params.setProperty( param, value );
+        return this;
+    }
+
+    public Properties getParams()
+    {
+        return params;
+    }
+
+    public HttpMethodConfiguration setParams( Properties params )
+    {
+        this.params = params;
+        return this;
+    }
+
+    public int getConnectionTimeout()
+    {
+        return connectionTimeout;
+    }
+
+    public HttpMethodConfiguration setConnectionTimeout( int connectionTimeout )
+    {
+        this.connectionTimeout = connectionTimeout;
+        return this;
+    }
+
+    public int getReadTimeout()
+    {
+        return readTimeout;
+    }
+
+    public HttpMethodConfiguration setReadTimeout( int readTimeout )
+    {
+        this.readTimeout = readTimeout;
+        return this;
+    }
+
+    public HttpParams asMethodParams( HttpParams defaults )
+    {
+        if ( !hasParams() )
+        {
+            return null;
+        }
+
+        DefaultedHttpParams p = new DefaultedHttpParams( new BasicHttpParams(), defaults );
+
+        fillParams( p );
+
+        return p;
+    }
+
+    private boolean hasParams()
+    {
+        if ( connectionTimeout < 1 && params == null && readTimeout < 1 )
+        {
+            return false;
+        }
+
+        return true;
+    }
+
+    public boolean isUsePreemptive()
+    {
+        return usePreemptive;
+    }
+
+    public HttpMethodConfiguration setUsePreemptive( boolean usePreemptive )
+    {
+        this.usePreemptive = usePreemptive;
+        return this;
+    }
+
+    private void fillParams( HttpParams p )
+    {
+        if ( !hasParams() )
+        {
+            return;
+        }
+
+        if ( connectionTimeout > 0 )
+        {
+            p.setParameter( CoreConnectionPNames.CONNECTION_TIMEOUT, connectionTimeout );
+        }
+
+        if ( readTimeout > 0 )
+        {
+            p.setParameter( CoreConnectionPNames.SO_TIMEOUT, readTimeout );
+        }
+
+        if ( params != null )
+        {
+            Pattern coercePattern = Pattern.compile( COERCE_PATTERN );
+
+            for ( Iterator<?> it = params.entrySet().iterator(); it.hasNext(); )
+            {
+                Map.Entry<String, String> entry = (Map.Entry) it.next();
+
+                String key = entry.getKey();
+                String value = entry.getValue();
+
+                Matcher matcher = coercePattern.matcher( value );
+                if ( matcher.matches() )
+                {
+                    char type = matcher.group( 1 ).charAt( 0 );
+                    value = matcher.group( 2 );
+
+                    switch ( type )
+                    {
+                        case 'i':
+                        {
+                            p.setIntParameter( key, Integer.parseInt( value ) );
+                            break;
+                        }
+                        case 'd':
+                        {
+                            p.setDoubleParameter( key, Double.parseDouble( value ) );
+                            break;
+                        }
+                        case 'l':
+                        {
+                            p.setLongParameter( key, Long.parseLong( value ) );
+                            break;
+                        }
+                        case 'b':
+                        {
+                            p.setBooleanParameter( key, Boolean.valueOf( value ).booleanValue() );
+                            break;
+                        }
+                        case 'c':
+                        {
+                            String[] entries = value.split( "," );
+                            List<String> collection = new ArrayList<String>();
+                            for ( int i = 0; i < entries.length; i++ )
+                            {
+                                collection.add( entries[i].trim() );
+                            }
+
+                            p.setParameter( key, collection );
+                            break;
+                        }
+                        case 'm':
+                        {
+                            String[] entries = value.split( "," );
+
+                            Map<String, String> map = new LinkedHashMap<String, String>();
+                            for ( int i = 0; i < entries.length; i++ )
+                            {
+                                int idx = entries[i].indexOf( "=>" );
+                                if ( idx < 1 )
+                                {
+                                    break;
+                                }
+
+                                String mapKey = entries[i].substring( 0, idx );
+                                String mapVal = entries[i].substring( idx + 1, entries[i].length() );
+                                map.put( mapKey.trim(), mapVal.trim() );
+                            }
+
+                            p.setParameter( key, map );
+                            break;
+                        }
+                    }
+                }
+                else
+                {
+                    p.setParameter( key, value );
+                }
+            }
+        }
+    }
+
+    public Header[] asRequestHeaders()
+    {
+        if ( headers == null )
+        {
+            return new Header[0];
+        }
+
+        Header[] result = new Header[headers.size()];
+
+        int index = 0;
+        for ( Iterator<?> it = headers.entrySet().iterator(); it.hasNext(); )
+        {
+            Map.Entry<String, String> entry = (Map.Entry) it.next();
+
+            String key = entry.getKey();
+            String value = entry.getValue();
+
+            Header header = new BasicHeader( key, value );
+            result[index++] = header;
+        }
+
+        return result;
+    }
+
+    private HttpMethodConfiguration copy()
+    {
+        HttpMethodConfiguration copy = new HttpMethodConfiguration();
+
+        copy.setConnectionTimeout( getConnectionTimeout() );
+        copy.setReadTimeout( getReadTimeout() );
+        if ( getHeaders() != null )
+        {
+            copy.setHeaders( getHeaders() );
+        }
+
+        if ( getParams() != null )
+        {
+            copy.setParams( getParams() );
+        }
+
+        copy.setUseDefaultHeaders( isUseDefaultHeaders() );
+
+        return copy;
+    }
+
+    public static HttpMethodConfiguration merge( HttpMethodConfiguration defaults, HttpMethodConfiguration base,
+                                                 HttpMethodConfiguration local )
+    {
+        HttpMethodConfiguration result = merge( defaults, base );
+        return merge( result, local );
+    }
+
+    public static HttpMethodConfiguration merge( HttpMethodConfiguration base, HttpMethodConfiguration local )
+    {
+        if ( base == null && local == null )
+        {
+            return null;
+        }
+        else if ( base == null )
+        {
+            return local;
+        }
+        else if ( local == null )
+        {
+            return base;
+        }
+        else
+        {
+            HttpMethodConfiguration result = base.copy();
+
+            if ( local.getConnectionTimeout() != Wagon.DEFAULT_CONNECTION_TIMEOUT )
+            {
+                result.setConnectionTimeout( local.getConnectionTimeout() );
+            }
+
+            if ( local.getReadTimeout() != Wagon.DEFAULT_READ_TIMEOUT )
+            {
+                result.setReadTimeout( local.getReadTimeout() );
+            }
+
+            if ( local.getHeaders() != null )
+            {
+                result.getHeaders().putAll( local.getHeaders() );
+            }
+
+            if ( local.getParams() != null )
+            {
+                result.getParams().putAll( local.getParams() );
+            }
+
+            if ( local.getUseDefaultHeaders() != null )
+            {
+                result.setUseDefaultHeaders( local.isUseDefaultHeaders() );
+            }
+
+            return result;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/maven-wagon/blob/34e9c2a0/wagon-providers/wagon-http/src/main/java/org/apache/maven/wagon/providers/http/HttpWagon.java
----------------------------------------------------------------------
diff --git a/wagon-providers/wagon-http/src/main/java/org/apache/maven/wagon/providers/http/HttpWagon.java b/wagon-providers/wagon-http/src/main/java/org/apache/maven/wagon/providers/http/HttpWagon.java
index 26b611f..e888de3 100644
--- a/wagon-providers/wagon-http/src/main/java/org/apache/maven/wagon/providers/http/HttpWagon.java
+++ b/wagon-providers/wagon-http/src/main/java/org/apache/maven/wagon/providers/http/HttpWagon.java
@@ -26,7 +26,6 @@ import org.apache.http.client.methods.HttpGet;
 import org.apache.maven.wagon.ResourceDoesNotExistException;
 import org.apache.maven.wagon.TransferFailedException;
 import org.apache.maven.wagon.authorization.AuthorizationException;
-import org.apache.maven.wagon.shared.http4.AbstractHttpClientWagon;
 import org.apache.maven.wagon.shared.http4.HtmlFileListParser;
 
 import java.io.IOException;

http://git-wip-us.apache.org/repos/asf/maven-wagon/blob/34e9c2a0/wagon-providers/wagon-http/src/main/java/org/apache/maven/wagon/providers/http/RelaxedX509TrustManager.java
----------------------------------------------------------------------
diff --git a/wagon-providers/wagon-http/src/main/java/org/apache/maven/wagon/providers/http/RelaxedX509TrustManager.java b/wagon-providers/wagon-http/src/main/java/org/apache/maven/wagon/providers/http/RelaxedX509TrustManager.java
new file mode 100644
index 0000000..f0d14eb
--- /dev/null
+++ b/wagon-providers/wagon-http/src/main/java/org/apache/maven/wagon/providers/http/RelaxedX509TrustManager.java
@@ -0,0 +1,131 @@
+package org.apache.maven.wagon.providers.http;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509TrustManager;
+import java.io.IOException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.X509Certificate;
+
+/**
+ * Relaxed X509 certificate trust manager: can ignore invalid certificate date.
+ *
+ * @author Olivier Lamy
+ * @since 2.0
+ * @see AbstractHttpClientWagon.IGNORE_SSL_VALIDITY_DATES
+ */
+public class RelaxedX509TrustManager
+    implements X509TrustManager
+{
+    private X509TrustManager standardTrustManager = null;
+
+    protected static SSLContext createRelaxedSSLContext()
+        throws IOException
+    {
+        try
+        {
+            SSLContext context = SSLContext.getInstance( "SSL" );
+            context.init( null, new TrustManager[]{ new RelaxedX509TrustManager( null ) }, null );
+            return context;
+        }
+        catch ( Exception e )
+        {
+            IOException ioe = new IOException( e.getMessage() );
+            ioe.initCause( e );
+            throw ioe;
+        }
+    }
+
+    /**
+     * Constructor for EasyX509TrustManager.
+     */
+    public RelaxedX509TrustManager( KeyStore keystore )
+        throws NoSuchAlgorithmException, KeyStoreException
+    {
+        super();
+        TrustManagerFactory factory = TrustManagerFactory.getInstance( TrustManagerFactory.getDefaultAlgorithm() );
+        factory.init( keystore );
+        TrustManager[] trustmanagers = factory.getTrustManagers();
+        if ( trustmanagers.length == 0 )
+        {
+            throw new NoSuchAlgorithmException( "no trust manager found" );
+        }
+        this.standardTrustManager = (X509TrustManager) trustmanagers[0];
+    }
+
+    /**
+     * @see javax.net.ssl.X509TrustManager#checkClientTrusted(X509Certificate[], String authType)
+     */
+    public void checkClientTrusted( X509Certificate[] certificates, String authType )
+        throws CertificateException
+    {
+        standardTrustManager.checkClientTrusted( certificates, authType );
+    }
+
+    /**
+     * @see javax.net.ssl.X509TrustManager#checkServerTrusted(X509Certificate[], String authType)
+     */
+    public void checkServerTrusted( X509Certificate[] certificates, String authType )
+        throws CertificateException
+    {
+
+        if ( ( certificates != null ) && ( certificates.length == 1 ) )
+        {
+            try
+            {
+                certificates[0].checkValidity();
+            }
+            catch ( CertificateExpiredException e )
+            {
+                if ( !AbstractHttpClientWagon.IGNORE_SSL_VALIDITY_DATES )
+                {
+                    throw e;
+                }
+            }
+            catch ( CertificateNotYetValidException e )
+            {
+                if ( !AbstractHttpClientWagon.IGNORE_SSL_VALIDITY_DATES )
+                {
+                    throw e;
+                }
+            }
+        }
+        else
+        {
+            standardTrustManager.checkServerTrusted( certificates, authType );
+        }
+    }
+
+    /**
+     * @see javax.net.ssl.X509TrustManager#getAcceptedIssuers()
+     */
+    public X509Certificate[] getAcceptedIssuers()
+    {
+        return this.standardTrustManager.getAcceptedIssuers();
+    }
+}

http://git-wip-us.apache.org/repos/asf/maven-wagon/blob/34e9c2a0/wagon-providers/wagon-http/src/test/java/org/apache/maven/wagon/providers/http/AbstractHttpClientWagonTest.java
----------------------------------------------------------------------
diff --git a/wagon-providers/wagon-http/src/test/java/org/apache/maven/wagon/providers/http/AbstractHttpClientWagonTest.java b/wagon-providers/wagon-http/src/test/java/org/apache/maven/wagon/providers/http/AbstractHttpClientWagonTest.java
new file mode 100644
index 0000000..82e9be2
--- /dev/null
+++ b/wagon-providers/wagon-http/src/test/java/org/apache/maven/wagon/providers/http/AbstractHttpClientWagonTest.java
@@ -0,0 +1,161 @@
+package org.apache.maven.wagon.providers.http;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+import junit.framework.TestCase;
+import org.apache.http.Header;
+import org.apache.http.client.methods.HttpHead;
+import org.apache.http.client.params.ClientPNames;
+import org.apache.http.params.HttpParams;
+import org.apache.maven.wagon.OutputData;
+import org.apache.maven.wagon.TransferFailedException;
+import org.apache.maven.wagon.providers.http.AbstractHttpClientWagon;
+import org.apache.maven.wagon.providers.http.HttpConfiguration;
+import org.apache.maven.wagon.providers.http.HttpMethodConfiguration;
+
+public class AbstractHttpClientWagonTest
+    extends TestCase
+{
+
+    public void testSetPreemptiveAuthParamViaConfig()
+    {
+        HttpMethodConfiguration methodConfig = new HttpMethodConfiguration();
+        //X TODO methodConfig.addParam( HttpClientParams.PREEMPTIVE_AUTHENTICATION, "%b,true" );
+
+        HttpConfiguration config = new HttpConfiguration();
+        config.setAll( methodConfig );
+
+        TestWagon wagon = new TestWagon();
+        wagon.setHttpConfiguration( config );
+
+        HttpHead method = new HttpHead();
+        wagon.setParameters( method );
+
+        HttpParams params = method.getParams();
+        assertNotNull( params );
+        //X TODO assertTrue( params.isParameterTrue( HttpClientParams.PREEMPTIVE_AUTHENTICATION ) );
+    }
+
+    public void testSetMaxRedirectsParamViaConfig()
+    {
+        HttpMethodConfiguration methodConfig = new HttpMethodConfiguration();
+        int maxRedirects = 2;
+        methodConfig.addParam( ClientPNames.MAX_REDIRECTS, "%i," + maxRedirects );
+
+        HttpConfiguration config = new HttpConfiguration();
+        config.setAll( methodConfig );
+
+        TestWagon wagon = new TestWagon();
+        wagon.setHttpConfiguration( config );
+
+        HttpHead method = new HttpHead();
+        wagon.setParameters( method );
+
+        HttpParams params = method.getParams();
+        assertNotNull( params );
+        assertEquals( maxRedirects, params.getIntParameter( ClientPNames.MAX_REDIRECTS, -1 ) );
+    }
+
+    public void testDefaultHeadersUsedByDefault()
+    {
+        HttpConfiguration config = new HttpConfiguration();
+        config.setAll( new HttpMethodConfiguration() );
+
+        TestWagon wagon = new TestWagon();
+        wagon.setHttpConfiguration( config );
+
+        HttpHead method = new HttpHead();
+        wagon.setHeaders( method );
+
+        // these are the default headers.
+        // method.addRequestHeader( "Cache-control", "no-cache" );
+        // method.addRequestHeader( "Cache-store", "no-store" );
+        // method.addRequestHeader( "Pragma", "no-cache" );
+        // method.addRequestHeader( "Expires", "0" );
+        // method.addRequestHeader( "Accept-Encoding", "gzip" );
+
+        Header header = method.getFirstHeader( "Cache-control" );
+        assertNotNull( header );
+        assertEquals( "no-cache", header.getValue() );
+
+        header = method.getFirstHeader( "Cache-store" );
+        assertNotNull( header );
+        assertEquals( "no-store", header.getValue() );
+
+        header = method.getFirstHeader( "Pragma" );
+        assertNotNull( header );
+        assertEquals( "no-cache", header.getValue() );
+
+        header = method.getFirstHeader( "Expires" );
+        assertNotNull( header );
+        assertEquals( "0", header.getValue() );
+
+        header = method.getFirstHeader( "Accept-Encoding" );
+        assertNotNull( header );
+        assertEquals( "gzip", header.getValue() );
+    }
+
+    public void testTurnOffDefaultHeaders()
+    {
+        HttpConfiguration config = new HttpConfiguration();
+        config.setAll( new HttpMethodConfiguration().setUseDefaultHeaders( false ) );
+
+        TestWagon wagon = new TestWagon();
+        wagon.setHttpConfiguration( config );
+
+        HttpHead method = new HttpHead();
+        wagon.setHeaders( method );
+
+        // these are the default headers.
+        // method.addRequestHeader( "Cache-control", "no-cache" );
+        // method.addRequestHeader( "Cache-store", "no-store" );
+        // method.addRequestHeader( "Pragma", "no-cache" );
+        // method.addRequestHeader( "Expires", "0" );
+        // method.addRequestHeader( "Accept-Encoding", "gzip" );
+
+        Header header = method.getFirstHeader( "Cache-control" );
+        assertNull( header );
+
+        header = method.getFirstHeader( "Cache-store" );
+        assertNull( header );
+
+        header = method.getFirstHeader( "Pragma" );
+        assertNull( header );
+
+        header = method.getFirstHeader( "Expires" );
+        assertNull( header );
+
+        header = method.getFirstHeader( "Accept-Encoding" );
+        assertNull( header );
+    }
+
+    private static final class TestWagon
+        extends AbstractHttpClientWagon
+    {
+        @Override
+        public void fillOutputData( OutputData outputData )
+            throws TransferFailedException
+        {
+
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/maven-wagon/blob/34e9c2a0/wagon-providers/wagon-http/src/test/java/org/apache/maven/wagon/providers/http/HttpWagonPreemptiveTest.java
----------------------------------------------------------------------
diff --git a/wagon-providers/wagon-http/src/test/java/org/apache/maven/wagon/providers/http/HttpWagonPreemptiveTest.java b/wagon-providers/wagon-http/src/test/java/org/apache/maven/wagon/providers/http/HttpWagonPreemptiveTest.java
index f3e4308..f8c8be5 100644
--- a/wagon-providers/wagon-http/src/test/java/org/apache/maven/wagon/providers/http/HttpWagonPreemptiveTest.java
+++ b/wagon-providers/wagon-http/src/test/java/org/apache/maven/wagon/providers/http/HttpWagonPreemptiveTest.java
@@ -20,8 +20,6 @@ package org.apache.maven.wagon.providers.http;
  */
 
 import org.apache.maven.wagon.Wagon;
-import org.apache.maven.wagon.shared.http4.HttpConfiguration;
-import org.apache.maven.wagon.shared.http4.HttpMethodConfiguration;
 
 /**
  * @author <a href="michal.maczka@dimatics.com">Michal Maczka</a>

http://git-wip-us.apache.org/repos/asf/maven-wagon/blob/34e9c2a0/wagon-providers/wagon-http/src/test/java/org/apache/maven/wagon/providers/http/HttpWagonTest.java
----------------------------------------------------------------------
diff --git a/wagon-providers/wagon-http/src/test/java/org/apache/maven/wagon/providers/http/HttpWagonTest.java b/wagon-providers/wagon-http/src/test/java/org/apache/maven/wagon/providers/http/HttpWagonTest.java
index c00c6fb..08824c3 100644
--- a/wagon-providers/wagon-http/src/test/java/org/apache/maven/wagon/providers/http/HttpWagonTest.java
+++ b/wagon-providers/wagon-http/src/test/java/org/apache/maven/wagon/providers/http/HttpWagonTest.java
@@ -24,8 +24,6 @@ import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
 import org.apache.maven.wagon.StreamingWagon;
 import org.apache.maven.wagon.Wagon;
 import org.apache.maven.wagon.http.HttpWagonTestCase;
-import org.apache.maven.wagon.shared.http4.HttpConfiguration;
-import org.apache.maven.wagon.shared.http4.HttpMethodConfiguration;
 
 import java.util.Properties;
 

http://git-wip-us.apache.org/repos/asf/maven-wagon/blob/34e9c2a0/wagon-providers/wagon-http/src/test/java/org/apache/maven/wagon/providers/http/HttpWagonTimeoutTest.java
----------------------------------------------------------------------
diff --git a/wagon-providers/wagon-http/src/test/java/org/apache/maven/wagon/providers/http/HttpWagonTimeoutTest.java b/wagon-providers/wagon-http/src/test/java/org/apache/maven/wagon/providers/http/HttpWagonTimeoutTest.java
index f986b83..c223f23 100644
--- a/wagon-providers/wagon-http/src/test/java/org/apache/maven/wagon/providers/http/HttpWagonTimeoutTest.java
+++ b/wagon-providers/wagon-http/src/test/java/org/apache/maven/wagon/providers/http/HttpWagonTimeoutTest.java
@@ -23,8 +23,6 @@ import org.apache.maven.wagon.FileTestUtils;
 import org.apache.maven.wagon.TransferFailedException;
 import org.apache.maven.wagon.Wagon;
 import org.apache.maven.wagon.repository.Repository;
-import org.apache.maven.wagon.shared.http4.HttpConfiguration;
-import org.apache.maven.wagon.shared.http4.HttpMethodConfiguration;
 import org.mortbay.jetty.servlet.ServletHolder;
 
 import java.io.File;

http://git-wip-us.apache.org/repos/asf/maven-wagon/blob/34e9c2a0/wagon-providers/wagon-http/src/test/java/org/apache/maven/wagon/providers/http/HttpsWagonPreemptiveTest.java
----------------------------------------------------------------------
diff --git a/wagon-providers/wagon-http/src/test/java/org/apache/maven/wagon/providers/http/HttpsWagonPreemptiveTest.java b/wagon-providers/wagon-http/src/test/java/org/apache/maven/wagon/providers/http/HttpsWagonPreemptiveTest.java
index 6f5179a..396823b 100644
--- a/wagon-providers/wagon-http/src/test/java/org/apache/maven/wagon/providers/http/HttpsWagonPreemptiveTest.java
+++ b/wagon-providers/wagon-http/src/test/java/org/apache/maven/wagon/providers/http/HttpsWagonPreemptiveTest.java
@@ -20,8 +20,6 @@ package org.apache.maven.wagon.providers.http;
  */
 
 import org.apache.maven.wagon.Wagon;
-import org.apache.maven.wagon.shared.http4.HttpConfiguration;
-import org.apache.maven.wagon.shared.http4.HttpMethodConfiguration;
 import org.mortbay.jetty.Connector;
 import org.mortbay.jetty.Server;
 import org.mortbay.jetty.security.SslSocketConnector;