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 javax.net.ssl.SSLSession;
34
35 import org.apache.http.ConnectionReuseStrategy;
36 import org.apache.http.HttpEntity;
37 import org.apache.http.HttpException;
38 import org.apache.http.HttpHost;
39 import org.apache.http.HttpRequest;
40 import org.apache.http.HttpRequestInterceptor;
41 import org.apache.http.HttpResponse;
42 import org.apache.http.ProtocolVersion;
43 import org.apache.http.auth.AuthSchemeRegistry;
44 import org.apache.http.auth.AuthScope;
45 import org.apache.http.auth.AuthState;
46 import org.apache.http.auth.Credentials;
47 import org.apache.http.client.params.AuthPolicy;
48 import org.apache.http.client.params.HttpClientParams;
49 import org.apache.http.client.protocol.ClientContext;
50 import org.apache.http.client.protocol.RequestClientConnControl;
51 import org.apache.http.client.protocol.RequestProxyAuthentication;
52 import org.apache.http.conn.HttpRoutedConnection;
53 import org.apache.http.conn.routing.HttpRoute;
54 import org.apache.http.entity.BufferedHttpEntity;
55 import org.apache.http.impl.DefaultConnectionReuseStrategy;
56 import org.apache.http.impl.DefaultHttpClientConnection;
57 import org.apache.http.impl.auth.BasicSchemeFactory;
58 import org.apache.http.impl.auth.DigestSchemeFactory;
59 import org.apache.http.impl.auth.KerberosSchemeFactory;
60 import org.apache.http.impl.auth.NTLMSchemeFactory;
61 import org.apache.http.impl.auth.SPNegoSchemeFactory;
62 import org.apache.http.message.BasicHttpRequest;
63 import org.apache.http.params.BasicHttpParams;
64 import org.apache.http.params.HttpParams;
65 import org.apache.http.params.HttpProtocolParams;
66 import org.apache.http.protocol.BasicHttpContext;
67 import org.apache.http.protocol.ExecutionContext;
68 import org.apache.http.protocol.HttpContext;
69 import org.apache.http.protocol.HttpProcessor;
70 import org.apache.http.protocol.HttpRequestExecutor;
71 import org.apache.http.protocol.ImmutableHttpProcessor;
72 import org.apache.http.protocol.RequestContent;
73 import org.apache.http.protocol.RequestTargetHost;
74 import org.apache.http.protocol.RequestUserAgent;
75 import org.apache.http.util.EntityUtils;
76
77 public class ProxyClient {
78
79 private final HttpProcessor httpProcessor;
80 private final HttpRequestExecutor requestExec;
81 private final ProxyAuthenticationStrategy proxyAuthStrategy;
82 private final HttpAuthenticator authenticator;
83 private final AuthState proxyAuthState;
84 private final AuthSchemeRegistry authSchemeRegistry;
85 private final ConnectionReuseStrategy reuseStrategy;
86 private final HttpParams params;
87
88 public ProxyClient(final HttpParams params) {
89 super();
90 if (params == null) {
91 throw new IllegalArgumentException("HTTP parameters may not be null");
92 }
93 this.httpProcessor = new ImmutableHttpProcessor(new HttpRequestInterceptor[] {
94 new RequestContent(),
95 new RequestTargetHost(),
96 new RequestClientConnControl(),
97 new RequestUserAgent(),
98 new RequestProxyAuthentication()
99 } );
100 this.requestExec = new HttpRequestExecutor();
101 this.proxyAuthStrategy = new ProxyAuthenticationStrategy();
102 this.authenticator = new HttpAuthenticator();
103 this.proxyAuthState = new AuthState();
104 this.authSchemeRegistry = new AuthSchemeRegistry();
105 this.authSchemeRegistry.register(AuthPolicy.BASIC, new BasicSchemeFactory());
106 this.authSchemeRegistry.register(AuthPolicy.DIGEST, new DigestSchemeFactory());
107 this.authSchemeRegistry.register(AuthPolicy.NTLM, new NTLMSchemeFactory());
108 this.authSchemeRegistry.register(AuthPolicy.SPNEGO, new SPNegoSchemeFactory());
109 this.authSchemeRegistry.register(AuthPolicy.KERBEROS, new KerberosSchemeFactory());
110 this.reuseStrategy = new DefaultConnectionReuseStrategy();
111 this.params = params;
112 }
113
114 public ProxyClient() {
115 this(new BasicHttpParams());
116 }
117
118 public HttpParams getParams() {
119 return this.params;
120 }
121
122 public AuthSchemeRegistry getAuthSchemeRegistry() {
123 return this.authSchemeRegistry;
124 }
125
126 public Socket tunnel(
127 final HttpHost proxy,
128 final HttpHost target,
129 final Credentials credentials) throws IOException, HttpException {
130 ProxyConnection conn = new ProxyConnection(new HttpRoute(proxy));
131 HttpContext context = new BasicHttpContext();
132 HttpResponse response = null;
133
134 for (;;) {
135 if (!conn.isOpen()) {
136 Socket socket = new Socket(proxy.getHostName(), proxy.getPort());
137 conn.bind(socket, this.params);
138 }
139 String host = target.getHostName();
140 int port = target.getPort();
141 if (port < 0) {
142 port = 80;
143 }
144
145 StringBuilder buffer = new StringBuilder(host.length() + 6);
146 buffer.append(host);
147 buffer.append(':');
148 buffer.append(Integer.toString(port));
149
150 String authority = buffer.toString();
151 ProtocolVersion ver = HttpProtocolParams.getVersion(this.params);
152 HttpRequest connect = new BasicHttpRequest("CONNECT", authority, ver);
153 connect.setParams(this.params);
154
155 BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
156 credsProvider.setCredentials(new AuthScope(proxy), credentials);
157
158
159 context.setAttribute(ExecutionContext.HTTP_TARGET_HOST, target);
160 context.setAttribute(ExecutionContext.HTTP_PROXY_HOST, proxy);
161 context.setAttribute(ExecutionContext.HTTP_CONNECTION, conn);
162 context.setAttribute(ExecutionContext.HTTP_REQUEST, connect);
163 context.setAttribute(ClientContext.PROXY_AUTH_STATE, this.proxyAuthState);
164 context.setAttribute(ClientContext.CREDS_PROVIDER, credsProvider);
165 context.setAttribute(ClientContext.AUTHSCHEME_REGISTRY, this.authSchemeRegistry);
166
167 this.requestExec.preProcess(connect, this.httpProcessor, context);
168
169 response = this.requestExec.execute(connect, conn, context);
170
171 response.setParams(this.params);
172 this.requestExec.postProcess(response, this.httpProcessor, context);
173
174 int status = response.getStatusLine().getStatusCode();
175 if (status < 200) {
176 throw new HttpException("Unexpected response to CONNECT request: " +
177 response.getStatusLine());
178 }
179
180 if (HttpClientParams.isAuthenticating(this.params)) {
181 if (this.authenticator.isAuthenticationRequested(proxy, response,
182 this.proxyAuthStrategy, this.proxyAuthState, context)) {
183 if (this.authenticator.authenticate(proxy, response,
184 this.proxyAuthStrategy, this.proxyAuthState, context)) {
185
186 if (this.reuseStrategy.keepAlive(response, context)) {
187
188 HttpEntity entity = response.getEntity();
189 EntityUtils.consume(entity);
190 } else {
191 conn.close();
192 }
193 } else {
194 break;
195 }
196 } else {
197 break;
198 }
199 }
200 }
201
202 int status = response.getStatusLine().getStatusCode();
203
204 if (status > 299) {
205
206
207 HttpEntity entity = response.getEntity();
208 if (entity != null) {
209 response.setEntity(new BufferedHttpEntity(entity));
210 }
211
212 conn.close();
213 throw new TunnelRefusedException("CONNECT refused by proxy: " +
214 response.getStatusLine(), response);
215 }
216 return conn.getSocket();
217 }
218
219 static class ProxyConnection extends DefaultHttpClientConnection implements HttpRoutedConnection {
220
221 private final HttpRoute route;
222
223 ProxyConnection(final HttpRoute route) {
224 super();
225 this.route = route;
226 }
227
228 public HttpRoute getRoute() {
229 return this.route;
230 }
231
232 public boolean isSecure() {
233 return false;
234 }
235
236 public SSLSession getSSLSession() {
237 return null;
238 }
239
240 @Override
241 public Socket getSocket() {
242 return super.getSocket();
243 }
244
245 }
246
247 }