2
* $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/examples/org/apache/http/examples/ElementalHttpServer.java $
4
* $Date: 2008-10-07 21:13:28 +0200 (Tue, 07 Oct 2008) $
6
* ====================================================================
7
* Licensed to the Apache Software Foundation (ASF) under one
8
* or more contributor license agreements. See the NOTICE file
9
* distributed with this work for additional information
10
* regarding copyright ownership. The ASF licenses this file
11
* to you under the Apache License, Version 2.0 (the
12
* "License"); you may not use this file except in compliance
13
* with the License. You may obtain a copy of the License at
15
* http://www.apache.org/licenses/LICENSE-2.0
17
* Unless required by applicable law or agreed to in writing,
18
* software distributed under the License is distributed on an
19
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20
* KIND, either express or implied. See the License for the
21
* specific language governing permissions and limitations
23
* ====================================================================
25
* This software consists of voluntary contributions made by many
26
* individuals on behalf of the Apache Software Foundation. For more
27
* information on the Apache Software Foundation, please see
28
* <http://www.apache.org/>.
32
package org.apache.http.examples;
34
import java.io.IOException;
35
import java.io.InterruptedIOException;
36
import java.net.ServerSocket;
37
import java.net.Socket;
39
import org.apache.http.ConnectionClosedException;
40
import org.apache.http.ConnectionReuseStrategy;
41
import org.apache.http.HttpClientConnection;
42
import org.apache.http.HttpException;
43
import org.apache.http.HttpHost;
44
import org.apache.http.HttpRequest;
45
import org.apache.http.HttpResponse;
46
import org.apache.http.HttpServerConnection;
47
import org.apache.http.impl.DefaultConnectionReuseStrategy;
48
import org.apache.http.impl.DefaultHttpClientConnection;
49
import org.apache.http.impl.DefaultHttpResponseFactory;
50
import org.apache.http.impl.DefaultHttpServerConnection;
51
import org.apache.http.params.BasicHttpParams;
52
import org.apache.http.params.CoreConnectionPNames;
53
import org.apache.http.params.CoreProtocolPNames;
54
import org.apache.http.params.HttpParams;
55
import org.apache.http.protocol.BasicHttpContext;
56
import org.apache.http.protocol.BasicHttpProcessor;
57
import org.apache.http.protocol.ExecutionContext;
58
import org.apache.http.protocol.HTTP;
59
import org.apache.http.protocol.HttpContext;
60
import org.apache.http.protocol.HttpProcessor;
61
import org.apache.http.protocol.HttpRequestExecutor;
62
import org.apache.http.protocol.HttpRequestHandler;
63
import org.apache.http.protocol.HttpRequestHandlerRegistry;
64
import org.apache.http.protocol.HttpService;
65
import org.apache.http.protocol.RequestConnControl;
66
import org.apache.http.protocol.RequestContent;
67
import org.apache.http.protocol.RequestExpectContinue;
68
import org.apache.http.protocol.RequestTargetHost;
69
import org.apache.http.protocol.RequestUserAgent;
70
import org.apache.http.protocol.ResponseConnControl;
71
import org.apache.http.protocol.ResponseContent;
72
import org.apache.http.protocol.ResponseDate;
73
import org.apache.http.protocol.ResponseServer;
76
* Rudimentary HTTP/1.1 reverse proxy.
78
* Please note the purpose of this application is demonstrate the usage of HttpCore APIs.
79
* It is NOT intended to demonstrate the most efficient way of building an HTTP reverse proxy.
82
* @version $Revision: $
84
public class ElementalReverseProxy {
86
private static final String HTTP_IN_CONN = "http.proxy.in-conn";
87
private static final String HTTP_OUT_CONN = "http.proxy.out-conn";
88
private static final String HTTP_CONN_KEEPALIVE = "http.proxy.conn-keepalive";
90
public static void main(String[] args) throws Exception {
91
if (args.length < 1) {
92
System.err.println("Please specified target hostname and port");
95
String hostname = args[0];
97
if (args.length > 1) {
98
port = Integer.parseInt(args[1]);
100
HttpHost target = new HttpHost(hostname, port);
102
Thread t = new RequestListenerThread(8888, target);
107
static class ProxyHandler implements HttpRequestHandler {
109
private final HttpHost target;
110
private final HttpProcessor httpproc;
111
private final HttpRequestExecutor httpexecutor;
112
private final ConnectionReuseStrategy connStrategy;
115
final HttpHost target,
116
final HttpProcessor httpproc,
117
final HttpRequestExecutor httpexecutor) {
119
this.target = target;
120
this.httpproc = httpproc;
121
this.httpexecutor = httpexecutor;
122
this.connStrategy = new DefaultConnectionReuseStrategy();
126
final HttpRequest request,
127
final HttpResponse response,
128
final HttpContext context) throws HttpException, IOException {
130
HttpClientConnection conn = (HttpClientConnection) context.getAttribute(
133
context.setAttribute(ExecutionContext.HTTP_CONNECTION, conn);
134
context.setAttribute(ExecutionContext.HTTP_TARGET_HOST, this.target);
136
System.out.println(">> Request URI: " + request.getRequestLine().getUri());
138
// Remove hop-by-hop headers
139
request.removeHeaders(HTTP.CONTENT_LEN);
140
request.removeHeaders(HTTP.TRANSFER_ENCODING);
141
request.removeHeaders(HTTP.CONN_DIRECTIVE);
142
request.removeHeaders("Keep-Alive");
143
request.removeHeaders("Proxy-Authenticate");
144
request.removeHeaders("TE");
145
request.removeHeaders("Trailers");
146
request.removeHeaders("Upgrade");
148
this.httpexecutor.preProcess(request, this.httpproc, context);
149
HttpResponse targetResponse = this.httpexecutor.execute(request, conn, context);
150
this.httpexecutor.postProcess(response, this.httpproc, context);
152
// Remove hop-by-hop headers
153
targetResponse.removeHeaders(HTTP.CONTENT_LEN);
154
targetResponse.removeHeaders(HTTP.TRANSFER_ENCODING);
155
targetResponse.removeHeaders(HTTP.CONN_DIRECTIVE);
156
targetResponse.removeHeaders("Keep-Alive");
157
targetResponse.removeHeaders("TE");
158
targetResponse.removeHeaders("Trailers");
159
targetResponse.removeHeaders("Upgrade");
161
response.setStatusLine(targetResponse.getStatusLine());
162
response.setHeaders(targetResponse.getAllHeaders());
163
response.setEntity(targetResponse.getEntity());
165
System.out.println("<< Response: " + response.getStatusLine());
167
boolean keepalive = this.connStrategy.keepAlive(response, context);
168
context.setAttribute(HTTP_CONN_KEEPALIVE, new Boolean(keepalive));
173
static class RequestListenerThread extends Thread {
175
private final HttpHost target;
176
private final ServerSocket serversocket;
177
private final HttpParams params;
178
private final HttpService httpService;
180
public RequestListenerThread(int port, final HttpHost target) throws IOException {
181
this.target = target;
182
this.serversocket = new ServerSocket(port);
183
this.params = new BasicHttpParams();
185
.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 5000)
186
.setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 * 1024)
187
.setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false)
188
.setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true)
189
.setParameter(CoreProtocolPNames.ORIGIN_SERVER, "HttpComponents/1.1");
191
// Set up HTTP protocol processor for incoming connections
192
BasicHttpProcessor inhttpproc = new BasicHttpProcessor();
193
inhttpproc.addInterceptor(new ResponseDate());
194
inhttpproc.addInterceptor(new ResponseServer());
195
inhttpproc.addInterceptor(new ResponseContent());
196
inhttpproc.addInterceptor(new ResponseConnControl());
198
// Set up HTTP protocol processor for outgoing connections
199
BasicHttpProcessor outhttpproc = new BasicHttpProcessor();
200
outhttpproc.addInterceptor(new RequestContent());
201
outhttpproc.addInterceptor(new RequestTargetHost());
202
outhttpproc.addInterceptor(new RequestConnControl());
203
outhttpproc.addInterceptor(new RequestUserAgent());
204
outhttpproc.addInterceptor(new RequestExpectContinue());
206
// Set up outgoing request executor
207
HttpRequestExecutor httpexecutor = new HttpRequestExecutor();
209
// Set up incoming request handler
210
HttpRequestHandlerRegistry reqistry = new HttpRequestHandlerRegistry();
211
reqistry.register("*", new ProxyHandler(
216
// Set up the HTTP service
217
this.httpService = new HttpService(
219
new DefaultConnectionReuseStrategy(),
220
new DefaultHttpResponseFactory());
221
this.httpService.setParams(this.params);
222
this.httpService.setHandlerResolver(reqistry);
226
System.out.println("Listening on port " + this.serversocket.getLocalPort());
227
while (!Thread.interrupted()) {
229
// Set up incoming HTTP connection
230
Socket insocket = this.serversocket.accept();
231
DefaultHttpServerConnection inconn = new DefaultHttpServerConnection();
232
System.out.println("Incoming connection from " + insocket.getInetAddress());
233
inconn.bind(insocket, this.params);
235
// Set up outgoing HTTP connection
236
Socket outsocket = new Socket(this.target.getHostName(), this.target.getPort());
237
DefaultHttpClientConnection outconn = new DefaultHttpClientConnection();
238
outconn.bind(outsocket, this.params);
239
System.out.println("Outgoing connection to " + outsocket.getInetAddress());
241
// Start worker thread
242
Thread t = new ProxyThread(this.httpService, inconn, outconn);
245
} catch (InterruptedIOException ex) {
247
} catch (IOException e) {
248
System.err.println("I/O error initialising connection thread: "
256
static class ProxyThread extends Thread {
258
private final HttpService httpservice;
259
private final HttpServerConnection inconn;
260
private final HttpClientConnection outconn;
263
final HttpService httpservice,
264
final HttpServerConnection inconn,
265
final HttpClientConnection outconn) {
267
this.httpservice = httpservice;
268
this.inconn = inconn;
269
this.outconn = outconn;
273
System.out.println("New connection thread");
274
HttpContext context = new BasicHttpContext(null);
276
// Bind connection objects to the execution context
277
context.setAttribute(HTTP_IN_CONN, this.inconn);
278
context.setAttribute(HTTP_OUT_CONN, this.outconn);
281
while (!Thread.interrupted()) {
282
if (!this.inconn.isOpen()) {
283
this.outconn.close();
287
this.httpservice.handleRequest(this.inconn, context);
289
Boolean keepalive = (Boolean) context.getAttribute(HTTP_CONN_KEEPALIVE);
290
if (!Boolean.TRUE.equals(keepalive)) {
291
this.outconn.close();
296
} catch (ConnectionClosedException ex) {
297
System.err.println("Client closed connection");
298
} catch (IOException ex) {
299
System.err.println("I/O error: " + ex.getMessage());
300
} catch (HttpException ex) {
301
System.err.println("Unrecoverable HTTP protocol violation: " + ex.getMessage());
304
this.inconn.shutdown();
305
} catch (IOException ignore) {}
307
this.outconn.shutdown();
308
} catch (IOException ignore) {}