org.ops4j.pax.url.mvn.internal.wagon.ConfigurableHttpWagon.java Source code

Java tutorial

Introduction

Here is the source code for org.ops4j.pax.url.mvn.internal.wagon.ConfigurableHttpWagon.java

Source

/*
 * Copyright (C) 2014 Guillaume Nodet
 *
 * Licensed 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.
 */
package org.ops4j.pax.url.mvn.internal.wagon;

import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import org.apache.http.HttpException;
import org.apache.http.HttpHost;
import org.apache.http.auth.AUTH;
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.CredentialsProvider;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicHeader;
import org.apache.http.protocol.HTTP;
import org.apache.maven.wagon.ConnectionException;
import org.apache.maven.wagon.authentication.AuthenticationException;
import org.apache.maven.wagon.authentication.AuthenticationInfo;
import org.apache.maven.wagon.providers.http.AbstractHttpClientWagon;
import org.apache.maven.wagon.providers.http.HttpMethodConfiguration;
import org.apache.maven.wagon.providers.http.HttpWagon;
import org.apache.maven.wagon.proxy.ProxyInfo;
import org.apache.maven.wagon.proxy.ProxyInfoProvider;
import org.apache.maven.wagon.repository.Repository;
import org.ops4j.net.URLUtils;

/**
 * An http wagon provider providing more configuration options
 * through the use of an HttpClient instance.
 *
 * @author Guillaume Nodet
 */
public class ConfigurableHttpWagon extends HttpWagon {

    private final CloseableHttpClient client;

    public ConfigurableHttpWagon(CloseableHttpClient client, int readTimeout, int connectionTimeout) {
        this.client = client;
        setReadTimeout(readTimeout);
        setTimeout(connectionTimeout);
    }

    @Override
    protected CloseableHttpResponse execute(HttpUriRequest httpMethod) throws HttpException, IOException {
        setHeaders(httpMethod);
        String userAgent = getUserAgent(httpMethod);
        if (userAgent != null) {
            httpMethod.setHeader(HTTP.USER_AGENT, userAgent);
        }

        RequestConfig.Builder requestConfigBuilder = RequestConfig.custom();
        // WAGON-273: default the cookie-policy to browser compatible
        requestConfigBuilder.setCookieSpec(CookieSpecs.BROWSER_COMPATIBILITY);

        Repository repo = getRepository();
        ProxyInfo proxyInfo = getProxyInfo(repo.getProtocol(), repo.getHost());
        if (proxyInfo != null) {
            HttpHost proxy = new HttpHost(proxyInfo.getHost(), proxyInfo.getPort());
            requestConfigBuilder.setProxy(proxy);
        }

        HttpMethodConfiguration config = getHttpConfiguration() == null ? null
                : getHttpConfiguration().getMethodConfiguration(httpMethod);

        if (config != null) {
            copyConfig(config, requestConfigBuilder);
        } else {
            requestConfigBuilder.setSocketTimeout(getReadTimeout());
            requestConfigBuilder.setConnectTimeout(getTimeout());
        }

        getLocalContext().setRequestConfig(requestConfigBuilder.build());

        if (config != null && config.isUsePreemptive()) {
            HttpHost targetHost = new HttpHost(repo.getHost(), repo.getPort(), repo.getProtocol());
            AuthScope targetScope = getBasicAuthScope().getScope(targetHost);

            if (getCredentialsProvider().getCredentials(targetScope) != null) {
                BasicScheme targetAuth = new BasicScheme();
                targetAuth.processChallenge(new BasicHeader(AUTH.WWW_AUTH, "BASIC preemptive"));
                getAuthCache().put(targetHost, targetAuth);
            }
        }

        if (proxyInfo != null) {
            if (proxyInfo.getHost() != null) {
                HttpHost proxyHost = new HttpHost(proxyInfo.getHost(), proxyInfo.getPort());
                AuthScope proxyScope = getProxyBasicAuthScope().getScope(proxyHost);

                String proxyUsername = proxyInfo.getUserName();
                String proxyPassword = proxyInfo.getPassword();
                String proxyNtlmHost = proxyInfo.getNtlmHost();
                String proxyNtlmDomain = proxyInfo.getNtlmDomain();

                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);
                    }

                    getCredentialsProvider().setCredentials(proxyScope, creds);
                    BasicScheme proxyAuth = new BasicScheme();
                    proxyAuth.processChallenge(new BasicHeader(AUTH.PROXY_AUTH, "BASIC preemptive"));
                    getAuthCache().put(proxyHost, proxyAuth);
                }
            }
        }

        return client.execute(httpMethod, getLocalContext());
    }

    @Override
    public void connect(Repository repository, AuthenticationInfo authenticationInfo,
            ProxyInfoProvider proxyInfoProvider) throws ConnectionException, AuthenticationException {
        if (repository == null) {
            throw new IllegalStateException("The repository specified cannot be null.");
        }

        if (authenticationInfo == null) {
            authenticationInfo = new AuthenticationInfo();
        }

        if (authenticationInfo.getUserName() == null) {
            // Get user/pass that were encoded in the URL.
            if (repository.getUsername() != null) {
                // Need to decode username/password because it may contain encoded characters (http://www.w3schools.com/tags/ref_urlencode.asp)
                // A common encoding is to provide a username as an email address like user%40domain.org
                authenticationInfo.setUserName(URLUtils.decode(repository.getUsername()));
                if (repository.getPassword() != null && authenticationInfo.getPassword() == null) {
                    authenticationInfo.setPassword(URLUtils.decode(repository.getPassword()));
                }
            }
        }

        super.connect(repository, authenticationInfo, proxyInfoProvider);
    }

    private AuthCache getAuthCache() {
        return getField(AuthCache.class, "authCache");
    }

    private CredentialsProvider getCredentialsProvider() {
        return getField(CredentialsProvider.class, "credentialsProvider");
    }

    private HttpClientContext getLocalContext() {
        return getField(HttpClientContext.class, "localContext");
    }

    private <T> T getField(Class<T> clazz, String name) {
        try {
            Field field = AbstractHttpClientWagon.class.getDeclaredField(name);
            field.setAccessible(true);
            return clazz.cast(field.get(this));
        } catch (NoSuchFieldException e) {
            throw new IllegalStateException("Unable to retrieve field " + name, e);
        } catch (IllegalAccessException e) {
            throw new IllegalStateException("Unable to retrieve field " + name, e);
        }
    }

    private void copyConfig(HttpMethodConfiguration config, RequestConfig.Builder builder) {
        try {
            Class<?> clazz = getClass().getClassLoader()
                    .loadClass("org.apache.maven.wagon.providers.http.ConfigurationUtils");
            Method method = clazz.getMethod("copyConfig", HttpMethodConfiguration.class,
                    RequestConfig.Builder.class);
            method.invoke(null, config, builder);
        } catch (ClassNotFoundException e) {
            throw new IllegalStateException("Unable to call copyConfig", e);
        } catch (InvocationTargetException e) {
            throw new IllegalStateException("Unable to call copyConfig", e);
        } catch (NoSuchMethodException e) {
            throw new IllegalStateException("Unable to call copyConfig", e);
        } catch (IllegalAccessException e) {
            throw new IllegalStateException("Unable to call copyConfig", e);
        }
    }

}