1 package org.eclipse.jetty.rewrite.handler;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 import java.io.IOException;
17 import java.io.InputStream;
18 import java.io.OutputStream;
19 import java.net.MalformedURLException;
20 import java.util.Enumeration;
21 import java.util.HashSet;
22
23 import javax.servlet.http.HttpServletRequest;
24 import javax.servlet.http.HttpServletResponse;
25
26 import org.eclipse.jetty.client.HttpClient;
27 import org.eclipse.jetty.client.HttpExchange;
28 import org.eclipse.jetty.http.HttpHeaderValues;
29 import org.eclipse.jetty.http.HttpHeaders;
30 import org.eclipse.jetty.http.HttpURI;
31 import org.eclipse.jetty.http.PathMap;
32 import org.eclipse.jetty.io.Buffer;
33 import org.eclipse.jetty.io.EofException;
34 import org.eclipse.jetty.util.log.Log;
35 import org.eclipse.jetty.util.log.Logger;
36 import org.eclipse.jetty.util.thread.QueuedThreadPool;
37
38
39
40
41
42
43
44
45
46
47
48
49
50 public class ProxyRule extends PatternRule
51 {
52 private static final Logger _log = Log.getLogger(ProxyRule.class);
53
54 private HttpClient _client;
55 private String _hostHeader;
56 private String _proxyTo;
57
58 private int _connectorType = 2;
59 private String _maxThreads;
60 private String _maxConnections;
61 private String _timeout;
62 private String _idleTimeout;
63 private String _requestHeaderSize;
64 private String _requestBufferSize;
65 private String _responseHeaderSize;
66 private String _responseBufferSize;
67
68 private HashSet<String> _DontProxyHeaders = new HashSet<String>();
69 {
70 _DontProxyHeaders.add("proxy-connection");
71 _DontProxyHeaders.add("connection");
72 _DontProxyHeaders.add("keep-alive");
73 _DontProxyHeaders.add("transfer-encoding");
74 _DontProxyHeaders.add("te");
75 _DontProxyHeaders.add("trailer");
76 _DontProxyHeaders.add("proxy-authorization");
77 _DontProxyHeaders.add("proxy-authenticate");
78 _DontProxyHeaders.add("upgrade");
79 }
80
81
82 public ProxyRule()
83 {
84 _handling = true;
85 _terminating = true;
86 }
87
88
89 private void initializeClient() throws Exception
90 {
91 _client = new HttpClient();
92 _client.setConnectorType(_connectorType);
93
94 if ( _maxThreads != null )
95 {
96 _client.setThreadPool(new QueuedThreadPool(Integer.parseInt(_maxThreads)));
97 }
98 else
99 {
100 _client.setThreadPool(new QueuedThreadPool());
101 }
102
103 if ( _maxConnections != null )
104 {
105 _client.setMaxConnectionsPerAddress(Integer.parseInt(_maxConnections));
106 }
107
108 if ( _timeout != null )
109 {
110 _client.setTimeout(Long.parseLong(_timeout));
111 }
112
113 if ( _idleTimeout != null )
114 {
115 _client.setIdleTimeout(Long.parseLong(_idleTimeout));
116 }
117
118 if ( _requestBufferSize != null )
119 {
120 _client.setRequestBufferSize(Integer.parseInt(_requestBufferSize));
121 }
122
123 if ( _requestHeaderSize != null )
124 {
125 _client.setRequestHeaderSize(Integer.parseInt(_requestHeaderSize));
126 }
127
128 if ( _responseBufferSize != null )
129 {
130 _client.setResponseBufferSize(Integer.parseInt(_responseBufferSize));
131 }
132
133 if ( _responseHeaderSize != null )
134 {
135 _client.setResponseHeaderSize(Integer.parseInt(_responseHeaderSize));
136 }
137
138 _client.start();
139 }
140
141
142 private HttpURI proxyHttpURI(String uri) throws MalformedURLException
143 {
144 return new HttpURI(_proxyTo + uri);
145 }
146
147
148 @Override
149 protected String apply(String target, HttpServletRequest request, final HttpServletResponse response) throws IOException
150 {
151 synchronized (this)
152 {
153 if (_client == null)
154 {
155 try
156 {
157 initializeClient();
158 }
159 catch (Exception e)
160 {
161 throw new IOException("Unable to proxy: " + e.getMessage());
162 }
163 }
164 }
165
166 final int debug = _log.isDebugEnabled()?request.hashCode():0;
167
168 final InputStream in = request.getInputStream();
169 final OutputStream out = response.getOutputStream();
170
171 HttpURI url = createUrl(request,debug);
172
173 if (url == null)
174 {
175 response.sendError(HttpServletResponse.SC_FORBIDDEN);
176 return target;
177 }
178
179 HttpExchange exchange = new HttpExchange()
180 {
181 @Override
182 protected void onRequestCommitted() throws IOException
183 {
184 }
185
186 @Override
187 protected void onRequestComplete() throws IOException
188 {
189 }
190
191 @Override
192 protected void onResponseComplete() throws IOException
193 {
194 if (debug != 0)
195 _log.debug(debug + " complete");
196 }
197
198 @Override
199 protected void onResponseContent(Buffer content) throws IOException
200 {
201 if (debug != 0)
202 _log.debug(debug + " content" + content.length());
203 content.writeTo(out);
204 }
205
206 @Override
207 protected void onResponseHeaderComplete() throws IOException
208 {
209 }
210
211 @SuppressWarnings("deprecation")
212 @Override
213 protected void onResponseStatus(Buffer version, int status, Buffer reason) throws IOException
214 {
215 if (debug != 0)
216 _log.debug(debug + " " + version + " " + status + " " + reason);
217
218 if (reason != null && reason.length() > 0)
219 response.setStatus(status,reason.toString());
220 else
221 response.setStatus(status);
222 }
223
224 @Override
225 protected void onResponseHeader(Buffer name, Buffer value) throws IOException
226 {
227 String s = name.toString().toLowerCase();
228 if (!_DontProxyHeaders.contains(s) || (HttpHeaders.CONNECTION_BUFFER.equals(name) && HttpHeaderValues.CLOSE_BUFFER.equals(value)))
229 {
230 if (debug != 0)
231 _log.debug(debug + " " + name + ": " + value);
232
233 response.addHeader(name.toString(),value.toString());
234 }
235 else if (debug != 0)
236 _log.debug(debug + " " + name + "! " + value);
237 }
238
239 @Override
240 protected void onConnectionFailed(Throwable ex)
241 {
242 _log.warn(ex.toString());
243 _log.debug(ex);
244 if (!response.isCommitted())
245 {
246 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
247 }
248 }
249
250 @Override
251 protected void onException(Throwable ex)
252 {
253 if (ex instanceof EofException)
254 {
255 _log.ignore(ex);
256 return;
257 }
258 _log.warn(ex.toString());
259 _log.debug(ex);
260 if (!response.isCommitted())
261 {
262 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
263 }
264 }
265
266 @Override
267 protected void onExpire()
268 {
269 if (!response.isCommitted())
270 {
271 response.setStatus(HttpServletResponse.SC_GATEWAY_TIMEOUT);
272 }
273 }
274
275 };
276
277 exchange.setMethod(request.getMethod());
278 exchange.setURL(url.toString());
279 exchange.setVersion(request.getProtocol());
280
281 if (debug != 0)
282 {
283 _log.debug("{} {} {} {}", debug ,request.getMethod(), url, request.getProtocol());
284 }
285
286 boolean hasContent = createHeaders(request,debug,exchange);
287
288 if (hasContent)
289 {
290 exchange.setRequestContentSource(in);
291 }
292
293
294
295
296 long ctimeout = (_client.getTimeout() > exchange.getTimeout())?_client.getTimeout():exchange.getTimeout();
297 exchange.setTimeout(ctimeout);
298
299 _client.send(exchange);
300
301 try
302 {
303 exchange.waitForDone();
304 }
305 catch (InterruptedException e)
306 {
307 _log.info("Exception while waiting for response on proxied request", e);
308 }
309 return target;
310 }
311
312
313 private HttpURI createUrl(HttpServletRequest request, final int debug) throws MalformedURLException
314 {
315 String uri = request.getRequestURI();
316
317 if (request.getQueryString() != null)
318 {
319 uri += "?" + request.getQueryString();
320 }
321
322 uri = PathMap.pathInfo(_pattern,uri);
323
324 if(uri==null)
325 {
326 uri = "/";
327 }
328
329 HttpURI url = proxyHttpURI(uri);
330
331 if (debug != 0)
332 {
333 _log.debug(debug + " proxy " + uri + "-->" + url);
334 }
335
336 return url;
337 }
338
339
340 private boolean createHeaders(final HttpServletRequest request, final int debug, HttpExchange exchange)
341 {
342
343 String connectionHdr = request.getHeader("Connection");
344 if (connectionHdr != null)
345 {
346 connectionHdr = connectionHdr.toLowerCase();
347 if (connectionHdr.indexOf("keep-alive") < 0 && connectionHdr.indexOf("close") < 0)
348 {
349 connectionHdr = null;
350 }
351 }
352
353
354 if (_hostHeader != null)
355 {
356 exchange.setRequestHeader("Host",_hostHeader);
357 }
358
359
360 boolean xForwardedFor = false;
361 boolean hasContent = false;
362 long contentLength = -1;
363 Enumeration<?> enm = request.getHeaderNames();
364 while (enm.hasMoreElements())
365 {
366
367 String hdr = (String)enm.nextElement();
368 String lhdr = hdr.toLowerCase();
369
370 if (_DontProxyHeaders.contains(lhdr))
371 continue;
372 if (connectionHdr != null && connectionHdr.indexOf(lhdr) >= 0)
373 continue;
374 if (_hostHeader != null && "host".equals(lhdr))
375 continue;
376
377 if ("content-type".equals(lhdr))
378 hasContent = true;
379 else if ("content-length".equals(lhdr))
380 {
381 contentLength = request.getContentLength();
382 exchange.setRequestHeader(HttpHeaders.CONTENT_LENGTH,Long.toString(contentLength));
383 if (contentLength > 0)
384 hasContent = true;
385 }
386 else if ("x-forwarded-for".equals(lhdr))
387 xForwardedFor = true;
388
389 Enumeration<?> vals = request.getHeaders(hdr);
390 while (vals.hasMoreElements())
391 {
392 String val = (String)vals.nextElement();
393 if (val != null)
394 {
395 if (debug != 0)
396 _log.debug("{} {} {}",debug,hdr,val);
397
398 exchange.setRequestHeader(hdr,val);
399 }
400 }
401 }
402
403
404 exchange.setRequestHeader("Via","1.1 (jetty)");
405 if (!xForwardedFor)
406 {
407 exchange.addRequestHeader("X-Forwarded-For",request.getRemoteAddr());
408 exchange.addRequestHeader("X-Forwarded-Proto",request.getScheme());
409 exchange.addRequestHeader("X-Forwarded-Host",request.getServerName());
410 exchange.addRequestHeader("X-Forwarded-Server",request.getLocalName());
411 }
412 return hasContent;
413 }
414
415
416 public void setProxyTo(String proxyTo)
417 {
418 this._proxyTo = proxyTo;
419 }
420
421
422 public void setMaxThreads(String maxThreads)
423 {
424 this._maxThreads = maxThreads;
425 }
426
427
428 public void setMaxConnections(String maxConnections)
429 {
430 _maxConnections = maxConnections;
431 }
432
433
434 public void setTimeout(String timeout)
435 {
436 _timeout = timeout;
437 }
438
439
440 public void setIdleTimeout(String idleTimeout)
441 {
442 _idleTimeout = idleTimeout;
443 }
444
445
446 public void setRequestHeaderSize(String requestHeaderSize)
447 {
448 _requestHeaderSize = requestHeaderSize;
449 }
450
451
452 public void setRequestBufferSize(String requestBufferSize)
453 {
454 _requestBufferSize = requestBufferSize;
455 }
456
457
458 public void setResponseHeaderSize(String responseHeaderSize)
459 {
460 _responseHeaderSize = responseHeaderSize;
461 }
462
463
464 public void setResponseBufferSize(String responseBufferSize)
465 {
466 _responseBufferSize = responseBufferSize;
467 }
468
469
470 public void addDontProxyHeaders(String dontProxyHeader)
471 {
472 _DontProxyHeaders.add(dontProxyHeader);
473 }
474
475
476
477
478
479
480
481
482 public void setConnectorType( int connectorType )
483 {
484 _connectorType = connectorType;
485 }
486
487 }