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