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