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;