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