001/*
002 * ====================================================================
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements.  See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership.  The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License.  You may obtain a copy of the License at
010 *
011 *   http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing,
014 * software distributed under the License is distributed on an
015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
016 * KIND, either express or implied.  See the License for the
017 * specific language governing permissions and limitations
018 * under the License.
019 * ====================================================================
020 *
021 * This software consists of voluntary contributions made by many
022 * individuals on behalf of the Apache Software Foundation.  For more
023 * information on the Apache Software Foundation, please see
024 * <http://www.apache.org/>.
025 *
026 */
027
028package org.apache.http.impl.client;
029
030import java.io.Closeable;
031import java.io.IOException;
032import java.util.List;
033import java.util.concurrent.TimeUnit;
034
035import org.apache.commons.logging.Log;
036import org.apache.commons.logging.LogFactory;
037import org.apache.http.HttpException;
038import org.apache.http.HttpHost;
039import org.apache.http.HttpRequest;
040import org.apache.http.annotation.Contract;
041import org.apache.http.annotation.ThreadingBehavior;
042import org.apache.http.auth.AuthSchemeProvider;
043import org.apache.http.auth.AuthState;
044import org.apache.http.client.ClientProtocolException;
045import org.apache.http.client.CookieStore;
046import org.apache.http.client.CredentialsProvider;
047import org.apache.http.client.config.RequestConfig;
048import org.apache.http.client.methods.CloseableHttpResponse;
049import org.apache.http.client.methods.Configurable;
050import org.apache.http.client.methods.HttpExecutionAware;
051import org.apache.http.client.methods.HttpRequestWrapper;
052import org.apache.http.client.params.ClientPNames;
053import org.apache.http.client.params.HttpClientParamConfig;
054import org.apache.http.client.protocol.HttpClientContext;
055import org.apache.http.config.Lookup;
056import org.apache.http.conn.ClientConnectionManager;
057import org.apache.http.conn.ClientConnectionRequest;
058import org.apache.http.conn.HttpClientConnectionManager;
059import org.apache.http.conn.ManagedClientConnection;
060import org.apache.http.conn.routing.HttpRoute;
061import org.apache.http.conn.routing.HttpRoutePlanner;
062import org.apache.http.conn.scheme.SchemeRegistry;
063import org.apache.http.cookie.CookieSpecProvider;
064import org.apache.http.impl.execchain.ClientExecChain;
065import org.apache.http.params.HttpParams;
066import org.apache.http.params.HttpParamsNames;
067import org.apache.http.protocol.BasicHttpContext;
068import org.apache.http.protocol.HttpContext;
069import org.apache.http.util.Args;
070
071/**
072 * Internal class.
073 *
074 * @since 4.3
075 */
076@Contract(threading = ThreadingBehavior.SAFE_CONDITIONAL)
077@SuppressWarnings("deprecation")
078class InternalHttpClient extends CloseableHttpClient implements Configurable {
079
080    private final Log log = LogFactory.getLog(getClass());
081
082    private final ClientExecChain execChain;
083    private final HttpClientConnectionManager connManager;
084    private final HttpRoutePlanner routePlanner;
085    private final Lookup<CookieSpecProvider> cookieSpecRegistry;
086    private final Lookup<AuthSchemeProvider> authSchemeRegistry;
087    private final CookieStore cookieStore;
088    private final CredentialsProvider credentialsProvider;
089    private final RequestConfig defaultConfig;
090    private final List<Closeable> closeables;
091
092    public InternalHttpClient(
093            final ClientExecChain execChain,
094            final HttpClientConnectionManager connManager,
095            final HttpRoutePlanner routePlanner,
096            final Lookup<CookieSpecProvider> cookieSpecRegistry,
097            final Lookup<AuthSchemeProvider> authSchemeRegistry,
098            final CookieStore cookieStore,
099            final CredentialsProvider credentialsProvider,
100            final RequestConfig defaultConfig,
101            final List<Closeable> closeables) {
102        super();
103        Args.notNull(execChain, "HTTP client exec chain");
104        Args.notNull(connManager, "HTTP connection manager");
105        Args.notNull(routePlanner, "HTTP route planner");
106        this.execChain = execChain;
107        this.connManager = connManager;
108        this.routePlanner = routePlanner;
109        this.cookieSpecRegistry = cookieSpecRegistry;
110        this.authSchemeRegistry = authSchemeRegistry;
111        this.cookieStore = cookieStore;
112        this.credentialsProvider = credentialsProvider;
113        this.defaultConfig = defaultConfig;
114        this.closeables = closeables;
115    }
116
117    private HttpRoute determineRoute(
118            final HttpHost target,
119            final HttpRequest request,
120            final HttpContext context) throws HttpException {
121        HttpHost host = target;
122        if (host == null) {
123            host = (HttpHost) request.getParams().getParameter(ClientPNames.DEFAULT_HOST);
124        }
125        return this.routePlanner.determineRoute(host, request, context);
126    }
127
128    private void setupContext(final HttpClientContext context) {
129        if (context.getAttribute(HttpClientContext.TARGET_AUTH_STATE) == null) {
130            context.setAttribute(HttpClientContext.TARGET_AUTH_STATE, new AuthState());
131        }
132        if (context.getAttribute(HttpClientContext.PROXY_AUTH_STATE) == null) {
133            context.setAttribute(HttpClientContext.PROXY_AUTH_STATE, new AuthState());
134        }
135        if (context.getAttribute(HttpClientContext.AUTHSCHEME_REGISTRY) == null) {
136            context.setAttribute(HttpClientContext.AUTHSCHEME_REGISTRY, this.authSchemeRegistry);
137        }
138        if (context.getAttribute(HttpClientContext.COOKIESPEC_REGISTRY) == null) {
139            context.setAttribute(HttpClientContext.COOKIESPEC_REGISTRY, this.cookieSpecRegistry);
140        }
141        if (context.getAttribute(HttpClientContext.COOKIE_STORE) == null) {
142            context.setAttribute(HttpClientContext.COOKIE_STORE, this.cookieStore);
143        }
144        if (context.getAttribute(HttpClientContext.CREDS_PROVIDER) == null) {
145            context.setAttribute(HttpClientContext.CREDS_PROVIDER, this.credentialsProvider);
146        }
147        if (context.getAttribute(HttpClientContext.REQUEST_CONFIG) == null) {
148            context.setAttribute(HttpClientContext.REQUEST_CONFIG, this.defaultConfig);
149        }
150    }
151
152    @Override
153    protected CloseableHttpResponse doExecute(
154            final HttpHost target,
155            final HttpRequest request,
156            final HttpContext context) throws IOException, ClientProtocolException {
157        Args.notNull(request, "HTTP request");
158        HttpExecutionAware execAware = null;
159        if (request instanceof HttpExecutionAware) {
160            execAware = (HttpExecutionAware) request;
161        }
162        try {
163            final HttpRequestWrapper wrapper = HttpRequestWrapper.wrap(request, target);
164            final HttpClientContext localcontext = HttpClientContext.adapt(
165                    context != null ? context : new BasicHttpContext());
166            RequestConfig config = null;
167            if (request instanceof Configurable) {
168                config = ((Configurable) request).getConfig();
169            }
170            if (config == null) {
171                final HttpParams params = request.getParams();
172                if (params instanceof HttpParamsNames) {
173                    if (!((HttpParamsNames) params).getNames().isEmpty()) {
174                        config = HttpClientParamConfig.getRequestConfig(params, this.defaultConfig);
175                    }
176                } else {
177                    config = HttpClientParamConfig.getRequestConfig(params, this.defaultConfig);
178                }
179            }
180            if (config != null) {
181                localcontext.setRequestConfig(config);
182            }
183            setupContext(localcontext);
184            final HttpRoute route = determineRoute(target, wrapper, localcontext);
185            return this.execChain.execute(route, wrapper, localcontext, execAware);
186        } catch (final HttpException httpException) {
187            throw new ClientProtocolException(httpException);
188        }
189    }
190
191    @Override
192    public RequestConfig getConfig() {
193        return this.defaultConfig;
194    }
195
196    @Override
197    public void close() {
198        if (this.closeables != null) {
199            for (final Closeable closeable: this.closeables) {
200                try {
201                    closeable.close();
202                } catch (final IOException ex) {
203                    this.log.error(ex.getMessage(), ex);
204                }
205            }
206        }
207    }
208
209    @Override
210    public HttpParams getParams() {
211        throw new UnsupportedOperationException();
212    }
213
214    @Override
215    public ClientConnectionManager getConnectionManager() {
216
217        return new ClientConnectionManager() {
218
219            @Override
220            public void shutdown() {
221                connManager.shutdown();
222            }
223
224            @Override
225            public ClientConnectionRequest requestConnection(
226                    final HttpRoute route, final Object state) {
227                throw new UnsupportedOperationException();
228            }
229
230            @Override
231            public void releaseConnection(
232                    final ManagedClientConnection conn,
233                    final long validDuration, final TimeUnit timeUnit) {
234                throw new UnsupportedOperationException();
235            }
236
237            @Override
238            public SchemeRegistry getSchemeRegistry() {
239                throw new UnsupportedOperationException();
240            }
241
242            @Override
243            public void closeIdleConnections(final long idletime, final TimeUnit tunit) {
244                connManager.closeIdleConnections(idletime, tunit);
245            }
246
247            @Override
248            public void closeExpiredConnections() {
249                connManager.closeExpiredConnections();
250            }
251
252        };
253
254    }
255
256}