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