1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.mortbay.proxy;
16
17
18 import java.io.IOException;
19 import java.io.InputStream;
20 import java.io.OutputStream;
21 import java.net.InetSocketAddress;
22 import java.net.Socket;
23 import java.util.Enumeration;
24 import java.util.HashSet;
25
26 import javax.servlet.Servlet;
27 import javax.servlet.ServletConfig;
28 import javax.servlet.ServletContext;
29 import javax.servlet.ServletException;
30 import javax.servlet.ServletRequest;
31 import javax.servlet.ServletResponse;
32 import javax.servlet.http.HttpServletRequest;
33 import javax.servlet.http.HttpServletResponse;
34
35 import org.mortbay.io.Buffer;
36 import org.mortbay.jetty.Connector;
37 import org.mortbay.jetty.Handler;
38 import org.mortbay.jetty.HttpSchemes;
39 import org.mortbay.jetty.Server;
40 import org.mortbay.jetty.bio.SocketConnector;
41 import org.mortbay.jetty.client.Address;
42 import org.mortbay.jetty.client.HttpClient;
43 import org.mortbay.jetty.client.HttpExchange;
44 import org.mortbay.jetty.handler.ContextHandlerCollection;
45 import org.mortbay.jetty.handler.DefaultHandler;
46 import org.mortbay.jetty.handler.HandlerCollection;
47 import org.mortbay.jetty.servlet.Context;
48 import org.mortbay.jetty.servlet.ServletHolder;
49 import org.mortbay.jetty.webapp.WebAppContext;
50 import org.mortbay.util.IO;
51 import org.mortbay.util.ajax.Continuation;
52 import org.mortbay.util.ajax.ContinuationSupport;
53
54
55
56
57
58
59
60
61 public class AsyncProxyServlet implements Servlet
62 {
63 HttpClient _client;
64
65 protected HashSet<String> _DontProxyHeaders = new HashSet<String>();
66 {
67 _DontProxyHeaders.add("proxy-connection");
68 _DontProxyHeaders.add("connection");
69 _DontProxyHeaders.add("keep-alive");
70 _DontProxyHeaders.add("transfer-encoding");
71 _DontProxyHeaders.add("te");
72 _DontProxyHeaders.add("trailer");
73 _DontProxyHeaders.add("proxy-authorization");
74 _DontProxyHeaders.add("proxy-authenticate");
75 _DontProxyHeaders.add("upgrade");
76 }
77
78 private ServletConfig config;
79 private ServletContext context;
80
81
82
83
84 public void init(ServletConfig config) throws ServletException
85 {
86 this.config=config;
87 this.context=config.getServletContext();
88
89 _client=new HttpClient();
90
91 _client.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
92 try
93 {
94 _client.start();
95 }
96 catch (Exception e)
97 {
98 throw new ServletException(e);
99 }
100 }
101
102
103
104
105 public ServletConfig getServletConfig()
106 {
107 return config;
108 }
109
110
111
112
113 public void service(ServletRequest req, ServletResponse res) throws ServletException,
114 IOException
115 {
116 final HttpServletRequest request = (HttpServletRequest)req;
117 final HttpServletResponse response = (HttpServletResponse)res;
118 if ("CONNECT".equalsIgnoreCase(request.getMethod()))
119 {
120 handleConnect(request,response);
121 }
122 else
123 {
124 final InputStream in=request.getInputStream();
125 final OutputStream out=response.getOutputStream();
126 final Continuation continuation = ContinuationSupport.getContinuation(request,request);
127
128
129 if (!continuation.isPending())
130 {
131 final byte[] buffer = new byte[4096];
132 String uri=request.getRequestURI();
133 if (request.getQueryString()!=null)
134 uri+="?"+request.getQueryString();
135
136
137 HttpExchange exchange = new HttpExchange()
138 {
139
140 protected void onRequestCommitted() throws IOException
141 {
142 System.err.println("onRequestCommitted()");
143 }
144
145 protected void onRequestComplete() throws IOException
146 {
147 System.err.println("onRequestComplete()");
148 }
149
150 protected void onResponseComplete() throws IOException
151 {
152 System.err.println("onResponseComplete()");
153 continuation.resume();
154 }
155
156 protected void onResponseContent(Buffer content) throws IOException
157 {
158 System.err.println("onResponseContent()");
159
160 while (content.hasContent())
161 {
162 int len=content.get(buffer,0,buffer.length);
163 out.write(buffer,0,len);
164 }
165 }
166
167 protected void onResponseHeaderComplete() throws IOException
168 {
169 System.err.println("onResponseCompleteHeader()");
170 }
171
172 protected void onResponseStatus(Buffer version, int status, Buffer reason) throws IOException
173 {
174 System.err.println("onResponseStatus("+version+","+status+","+reason+")");
175 if (reason!=null && reason.length()>0)
176 response.setStatus(status,reason.toString());
177 else
178 response.setStatus(status);
179
180 }
181
182 protected void onResponseHeader(Buffer name, Buffer value) throws IOException
183 {
184 System.err.println("onResponseHeader("+name+","+value+")");
185 String s = name.toString().toLowerCase();
186 if (!_DontProxyHeaders.contains(s))
187 response.addHeader(name.toString(),value.toString());
188 }
189
190 };
191
192 exchange.setScheme(HttpSchemes.HTTPS.equals(request.getScheme())?HttpSchemes.HTTPS_BUFFER:HttpSchemes.HTTP_BUFFER);
193 exchange.setMethod(request.getMethod());
194 exchange.setURI(uri);
195
196 exchange.setVersion(request.getProtocol());
197 Address address=new Address(request.getServerName(),request.getServerPort());
198 exchange.setAddress(address);
199
200 System.err.println("PROXY TO http://"+address.getHost()+":"+address.getPort()+uri);
201
202
203
204 String connectionHdr = request.getHeader("Connection");
205 if (connectionHdr!=null)
206 {
207 connectionHdr=connectionHdr.toLowerCase();
208 if (connectionHdr.indexOf("keep-alive")<0 &&
209 connectionHdr.indexOf("close")<0)
210 connectionHdr=null;
211 }
212
213
214 boolean xForwardedFor=false;
215 boolean hasContent=false;
216 long contentLength=-1;
217 Enumeration enm = request.getHeaderNames();
218 while (enm.hasMoreElements())
219 {
220
221 String hdr=(String)enm.nextElement();
222 String lhdr=hdr.toLowerCase();
223
224 if (_DontProxyHeaders.contains(lhdr))
225 continue;
226 if (connectionHdr!=null && connectionHdr.indexOf(lhdr)>=0)
227 continue;
228
229 if ("content-type".equals(lhdr))
230 hasContent=true;
231 if ("content-length".equals(lhdr))
232 contentLength=request.getContentLength();
233
234 Enumeration vals = request.getHeaders(hdr);
235 while (vals.hasMoreElements())
236 {
237 String val = (String)vals.nextElement();
238 if (val!=null)
239 {
240 exchange.setRequestHeader(lhdr,val);
241 xForwardedFor|="X-Forwarded-For".equalsIgnoreCase(hdr);
242 }
243 }
244 }
245
246
247 exchange.setRequestHeader("Via","1.1 (jetty)");
248 if (!xForwardedFor)
249 exchange.addRequestHeader("X-Forwarded-For",
250 request.getRemoteAddr());
251
252 if (hasContent)
253 exchange.setRequestContentSource(in);
254
255 _client.send(exchange);
256
257 continuation.suspend(30000);
258 }
259 }
260
261
262
263 }
264
265
266
267 public void handleConnect(HttpServletRequest request,
268 HttpServletResponse response)
269 throws IOException
270 {
271 String uri = request.getRequestURI();
272
273 context.log("CONNECT: "+uri);
274
275 String port = "";
276 String host = "";
277
278 int c = uri.indexOf(':');
279 if (c>=0)
280 {
281 port = uri.substring(c+1);
282 host = uri.substring(0,c);
283 if (host.indexOf('/')>0)
284 host = host.substring(host.indexOf('/')+1);
285 }
286
287
288
289
290 InetSocketAddress inetAddress = new InetSocketAddress (host, Integer.parseInt(port));
291
292
293
294
295
296
297 {
298 InputStream in=request.getInputStream();
299 OutputStream out=response.getOutputStream();
300
301 Socket socket = new Socket(inetAddress.getAddress(),inetAddress.getPort());
302 context.log("Socket: "+socket);
303
304 response.setStatus(200);
305 response.setHeader("Connection","close");
306 response.flushBuffer();
307
308
309
310 context.log("out<-in");
311 IO.copyThread(socket.getInputStream(),out);
312 context.log("in->out");
313 IO.copy(in,socket.getOutputStream());
314 }
315 }
316
317
318
319
320
321
322
323 public String getServletInfo()
324 {
325 return "Proxy Servlet";
326 }
327
328
329
330
331 public void destroy()
332 {
333
334 }
335
336
337 public static void main(String[] args)
338 throws Exception
339 {
340 Server server = new Server(8080);
341 HandlerCollection handlers = new HandlerCollection();
342 ContextHandlerCollection contexts = new ContextHandlerCollection();
343 handlers.setHandlers(new Handler[]{contexts,new DefaultHandler()});
344 server.setHandler(handlers);
345 WebAppContext webapp = new WebAppContext();
346 webapp.setContextPath("/test");
347 webapp.setResourceBase("../../webapps/test");
348 contexts.addHandler(webapp);
349 server.start();
350
351 Server proxy = new Server();
352
353 Connector connector = new SocketConnector();
354 connector.setPort(8888);
355 proxy.addConnector(connector);
356 Context context = new Context(proxy,"/",0);
357 context.addServlet(new ServletHolder(new AsyncProxyServlet()), "/");
358
359 proxy.start();
360 proxy.join();
361 }
362 }