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