1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package org.apache.http.impl.client;
29
30 import java.io.IOException;
31 import java.net.Socket;
32
33 import org.apache.http.ConnectionReuseStrategy;
34 import org.apache.http.HttpEntity;
35 import org.apache.http.HttpException;
36 import org.apache.http.HttpHost;
37 import org.apache.http.HttpRequest;
38 import org.apache.http.HttpResponse;
39 import org.apache.http.HttpVersion;
40 import org.apache.http.auth.AUTH;
41 import org.apache.http.auth.AuthSchemeRegistry;
42 import org.apache.http.auth.AuthScope;
43 import org.apache.http.auth.AuthState;
44 import org.apache.http.auth.Credentials;
45 import org.apache.http.client.config.AuthSchemes;
46 import org.apache.http.client.config.RequestConfig;
47 import org.apache.http.client.params.HttpClientParamConfig;
48 import org.apache.http.client.protocol.HttpClientContext;
49 import org.apache.http.client.protocol.RequestClientConnControl;
50 import org.apache.http.config.ConnectionConfig;
51 import org.apache.http.conn.HttpConnectionFactory;
52 import org.apache.http.conn.ManagedHttpClientConnection;
53 import org.apache.http.conn.routing.HttpRoute;
54 import org.apache.http.conn.routing.RouteInfo.LayerType;
55 import org.apache.http.conn.routing.RouteInfo.TunnelType;
56 import org.apache.http.entity.BufferedHttpEntity;
57 import org.apache.http.impl.DefaultConnectionReuseStrategy;
58 import org.apache.http.impl.auth.BasicSchemeFactory;
59 import org.apache.http.impl.auth.DigestSchemeFactory;
60 import org.apache.http.impl.auth.HttpAuthenticator;
61 import org.apache.http.impl.auth.KerberosSchemeFactory;
62 import org.apache.http.impl.auth.NTLMSchemeFactory;
63 import org.apache.http.impl.auth.SPNegoSchemeFactory;
64 import org.apache.http.impl.conn.ManagedHttpClientConnectionFactory;
65 import org.apache.http.impl.execchain.TunnelRefusedException;
66 import org.apache.http.message.BasicHttpRequest;
67 import org.apache.http.params.BasicHttpParams;
68 import org.apache.http.params.HttpParamConfig;
69 import org.apache.http.params.HttpParams;
70 import org.apache.http.protocol.BasicHttpContext;
71 import org.apache.http.protocol.HttpContext;
72 import org.apache.http.protocol.HttpCoreContext;
73 import org.apache.http.protocol.HttpProcessor;
74 import org.apache.http.protocol.HttpRequestExecutor;
75 import org.apache.http.protocol.ImmutableHttpProcessor;
76 import org.apache.http.protocol.RequestTargetHost;
77 import org.apache.http.protocol.RequestUserAgent;
78 import org.apache.http.util.Args;
79 import org.apache.http.util.EntityUtils;
80
81
82
83
84 @SuppressWarnings("deprecation")
85 public class ProxyClient {
86
87 private final HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connFactory;
88 private final ConnectionConfig connectionConfig;
89 private final RequestConfig requestConfig;
90 private final HttpProcessor httpProcessor;
91 private final HttpRequestExecutor requestExec;
92 private final ProxyAuthenticationStrategy proxyAuthStrategy;
93 private final HttpAuthenticator authenticator;
94 private final AuthState proxyAuthState;
95 private final AuthSchemeRegistry authSchemeRegistry;
96 private final ConnectionReuseStrategy reuseStrategy;
97
98
99
100
101 public ProxyClient(
102 final HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connFactory,
103 final ConnectionConfig connectionConfig,
104 final RequestConfig requestConfig) {
105 super();
106 this.connFactory = connFactory != null ? connFactory : ManagedHttpClientConnectionFactory.INSTANCE;
107 this.connectionConfig = connectionConfig != null ? connectionConfig : ConnectionConfig.DEFAULT;
108 this.requestConfig = requestConfig != null ? requestConfig : RequestConfig.DEFAULT;
109 this.httpProcessor = new ImmutableHttpProcessor(
110 new RequestTargetHost(), new RequestClientConnControl(), new RequestUserAgent());
111 this.requestExec = new HttpRequestExecutor();
112 this.proxyAuthStrategy = new ProxyAuthenticationStrategy();
113 this.authenticator = new HttpAuthenticator();
114 this.proxyAuthState = new AuthState();
115 this.authSchemeRegistry = new AuthSchemeRegistry();
116 this.authSchemeRegistry.register(AuthSchemes.BASIC, new BasicSchemeFactory());
117 this.authSchemeRegistry.register(AuthSchemes.DIGEST, new DigestSchemeFactory());
118 this.authSchemeRegistry.register(AuthSchemes.NTLM, new NTLMSchemeFactory());
119 this.authSchemeRegistry.register(AuthSchemes.SPNEGO, new SPNegoSchemeFactory());
120 this.authSchemeRegistry.register(AuthSchemes.KERBEROS, new KerberosSchemeFactory());
121 this.reuseStrategy = new DefaultConnectionReuseStrategy();
122 }
123
124
125
126
127 @Deprecated
128 public ProxyClient(final HttpParams params) {
129 this(null,
130 HttpParamConfig.getConnectionConfig(params),
131 HttpClientParamConfig.getRequestConfig(params));
132 }
133
134
135
136
137 public ProxyClient(final RequestConfig requestConfig) {
138 this(null, null, requestConfig);
139 }
140
141 public ProxyClient() {
142 this(null, null, null);
143 }
144
145
146
147
148 @Deprecated
149 public HttpParams getParams() {
150 return new BasicHttpParams();
151 }
152
153
154
155
156 @Deprecated
157 public AuthSchemeRegistry getAuthSchemeRegistry() {
158 return this.authSchemeRegistry;
159 }
160
161 public Socket tunnel(
162 final HttpHost proxy,
163 final HttpHost target,
164 final Credentials credentials) throws IOException, HttpException {
165 Args.notNull(proxy, "Proxy host");
166 Args.notNull(target, "Target host");
167 Args.notNull(credentials, "Credentials");
168 HttpHost host = target;
169 if (host.getPort() <= 0) {
170 host = new HttpHost(host.getHostName(), 80, host.getSchemeName());
171 }
172 final HttpRouteg/HttpRoute.html#HttpRoute">HttpRoute route = new HttpRoute(
173 host,
174 this.requestConfig.getLocalAddress(),
175 proxy, false, TunnelType.TUNNELLED, LayerType.PLAIN);
176
177 final ManagedHttpClientConnection conn = this.connFactory.create(
178 route, this.connectionConfig);
179 final HttpContext context = new BasicHttpContext();
180 HttpResponse response;
181
182 final HttpRequest connect = new BasicHttpRequest(
183 "CONNECT", host.toHostString(), HttpVersion.HTTP_1_1);
184
185 final BasicCredentialsProviderer.html#BasicCredentialsProvider">BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
186 credsProvider.setCredentials(new AuthScope(proxy), credentials);
187
188
189 context.setAttribute(HttpCoreContext.HTTP_TARGET_HOST, target);
190 context.setAttribute(HttpCoreContext.HTTP_CONNECTION, conn);
191 context.setAttribute(HttpCoreContext.HTTP_REQUEST, connect);
192 context.setAttribute(HttpClientContext.HTTP_ROUTE, route);
193 context.setAttribute(HttpClientContext.PROXY_AUTH_STATE, this.proxyAuthState);
194 context.setAttribute(HttpClientContext.CREDS_PROVIDER, credsProvider);
195 context.setAttribute(HttpClientContext.AUTHSCHEME_REGISTRY, this.authSchemeRegistry);
196 context.setAttribute(HttpClientContext.REQUEST_CONFIG, this.requestConfig);
197
198 this.requestExec.preProcess(connect, this.httpProcessor, context);
199
200 for (;;) {
201 if (!conn.isOpen()) {
202 final Socket socket = new Socket(proxy.getHostName(), proxy.getPort());
203 conn.bind(socket);
204 }
205
206 this.authenticator.generateAuthResponse(connect, this.proxyAuthState, context);
207
208 response = this.requestExec.execute(connect, conn, context);
209
210 final int status = response.getStatusLine().getStatusCode();
211 if (status < 200) {
212 throw new HttpException("Unexpected response to CONNECT request: " +
213 response.getStatusLine());
214 }
215 if (this.authenticator.isAuthenticationRequested(proxy, response,
216 this.proxyAuthStrategy, this.proxyAuthState, context)) {
217 if (this.authenticator.handleAuthChallenge(proxy, response,
218 this.proxyAuthStrategy, this.proxyAuthState, context)) {
219
220 if (this.reuseStrategy.keepAlive(response, context)) {
221
222 final HttpEntity entity = response.getEntity();
223 EntityUtils.consume(entity);
224 } else {
225 conn.close();
226 }
227
228 connect.removeHeaders(AUTH.PROXY_AUTH_RESP);
229 } else {
230 break;
231 }
232 } else {
233 break;
234 }
235 }
236
237 final int status = response.getStatusLine().getStatusCode();
238
239 if (status > 299) {
240
241
242 final HttpEntity entity = response.getEntity();
243 if (entity != null) {
244 response.setEntity(new BufferedHttpEntity(entity));
245 }
246
247 conn.close();
248 throw new TunnelRefusedException("CONNECT refused by proxy: " +
249 response.getStatusLine(), response);
250 }
251 return conn.getSocket();
252 }
253
254 }