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