1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.mortbay.servlet;
17
18 import java.io.IOException;
19 import java.io.InputStream;
20 import java.io.OutputStream;
21 import java.net.HttpURLConnection;
22 import java.net.InetSocketAddress;
23 import java.net.MalformedURLException;
24 import java.net.Socket;
25 import java.net.URL;
26 import java.net.URLConnection;
27 import java.util.Enumeration;
28 import java.util.HashSet;
29
30 import javax.servlet.Servlet;
31 import javax.servlet.ServletConfig;
32 import javax.servlet.ServletContext;
33 import javax.servlet.ServletException;
34 import javax.servlet.ServletRequest;
35 import javax.servlet.ServletResponse;
36 import javax.servlet.UnavailableException;
37 import javax.servlet.http.HttpServletRequest;
38 import javax.servlet.http.HttpServletResponse;
39
40 import org.mortbay.util.IO;
41
42
43
44
45
46
47
48
49
50
51 public class ProxyServlet implements Servlet
52 {
53
54 protected HashSet _DontProxyHeaders = new HashSet();
55 {
56 _DontProxyHeaders.add("proxy-connection");
57 _DontProxyHeaders.add("connection");
58 _DontProxyHeaders.add("keep-alive");
59 _DontProxyHeaders.add("transfer-encoding");
60 _DontProxyHeaders.add("te");
61 _DontProxyHeaders.add("trailer");
62 _DontProxyHeaders.add("proxy-authorization");
63 _DontProxyHeaders.add("proxy-authenticate");
64 _DontProxyHeaders.add("upgrade");
65 }
66
67 protected ServletConfig _config;
68 protected ServletContext _context;
69
70
71
72
73 public void init(ServletConfig config) throws ServletException
74 {
75 this._config=config;
76 this._context=config.getServletContext();
77 }
78
79
80
81
82 public ServletConfig getServletConfig()
83 {
84 return _config;
85 }
86
87
88
89
90 public void service(ServletRequest req, ServletResponse res) throws ServletException,
91 IOException
92 {
93 HttpServletRequest request = (HttpServletRequest)req;
94 HttpServletResponse response = (HttpServletResponse)res;
95 if ("CONNECT".equalsIgnoreCase(request.getMethod()))
96 {
97 handleConnect(request,response);
98 }
99 else
100 {
101 String uri=request.getRequestURI();
102 if (request.getQueryString()!=null)
103 uri+="?"+request.getQueryString();
104
105 URL url=proxyHttpURL(request.getScheme(),
106 request.getServerName(),
107 request.getServerPort(),
108 uri);
109
110
111 URLConnection connection = url.openConnection();
112 connection.setAllowUserInteraction(false);
113
114
115 HttpURLConnection http = null;
116 if (connection instanceof HttpURLConnection)
117 {
118 http = (HttpURLConnection)connection;
119 http.setRequestMethod(request.getMethod());
120 http.setInstanceFollowRedirects(false);
121 }
122
123
124 String connectionHdr = request.getHeader("Connection");
125 if (connectionHdr!=null)
126 {
127 connectionHdr=connectionHdr.toLowerCase();
128 if (connectionHdr.equals("keep-alive")||
129 connectionHdr.equals("close"))
130 connectionHdr=null;
131 }
132
133
134 boolean xForwardedFor=false;
135 boolean hasContent=false;
136 Enumeration enm = request.getHeaderNames();
137 while (enm.hasMoreElements())
138 {
139
140 String hdr=(String)enm.nextElement();
141 String lhdr=hdr.toLowerCase();
142
143 if (_DontProxyHeaders.contains(lhdr))
144 continue;
145 if (connectionHdr!=null && connectionHdr.indexOf(lhdr)>=0)
146 continue;
147
148 if ("content-type".equals(lhdr))
149 hasContent=true;
150
151 Enumeration vals = request.getHeaders(hdr);
152 while (vals.hasMoreElements())
153 {
154 String val = (String)vals.nextElement();
155 if (val!=null)
156 {
157 connection.addRequestProperty(hdr,val);
158 xForwardedFor|="X-Forwarded-For".equalsIgnoreCase(hdr);
159 }
160 }
161 }
162
163
164 connection.setRequestProperty("Via","1.1 (jetty)");
165 if (!xForwardedFor)
166 {
167 connection.addRequestProperty("X-Forwarded-For",
168 request.getRemoteAddr());
169 connection.addRequestProperty("X-Forwarded-Proto",
170 request.getScheme());
171 connection.addRequestProperty("X-Forwarded-Host",
172 request.getServerName());
173 connection.addRequestProperty("X-Forwarded-Server",
174 request.getLocalName());
175 }
176
177
178 String cache_control = request.getHeader("Cache-Control");
179 if (cache_control!=null &&
180 (cache_control.indexOf("no-cache")>=0 ||
181 cache_control.indexOf("no-store")>=0))
182 connection.setUseCaches(false);
183
184
185
186 try
187 {
188 connection.setDoInput(true);
189
190
191 InputStream in=request.getInputStream();
192 if (hasContent)
193 {
194 connection.setDoOutput(true);
195 IO.copy(in,connection.getOutputStream());
196 }
197
198
199 connection.connect();
200 }
201 catch (Exception e)
202 {
203 _context.log("proxy",e);
204 }
205
206 InputStream proxy_in = null;
207
208
209 int code=500;
210 if (http!=null)
211 {
212 proxy_in = http.getErrorStream();
213
214 code=http.getResponseCode();
215 response.setStatus(code, http.getResponseMessage());
216 }
217
218 if (proxy_in==null)
219 {
220 try {proxy_in=connection.getInputStream();}
221 catch (Exception e)
222 {
223 _context.log("stream",e);
224 proxy_in = http.getErrorStream();
225 }
226 }
227
228
229 response.setHeader("Date",null);
230 response.setHeader("Server",null);
231
232
233 int h=0;
234 String hdr=connection.getHeaderFieldKey(h);
235 String val=connection.getHeaderField(h);
236 while(hdr!=null || val!=null)
237 {
238 String lhdr = hdr!=null?hdr.toLowerCase():null;
239 if (hdr!=null && val!=null && !_DontProxyHeaders.contains(lhdr))
240 response.addHeader(hdr,val);
241
242 h++;
243 hdr=connection.getHeaderFieldKey(h);
244 val=connection.getHeaderField(h);
245 }
246 response.addHeader("Via","1.1 (jetty)");
247
248
249 if (proxy_in!=null)
250 IO.copy(proxy_in,response.getOutputStream());
251
252 }
253 }
254
255
256
257
258
259
260
261
262
263
264
265
266 protected URL proxyHttpURL(String scheme, String serverName, int serverPort, String uri)
267 throws MalformedURLException
268 {
269 return new URL(scheme,serverName,serverPort,uri);
270 }
271
272
273 public void handleConnect(HttpServletRequest request,
274 HttpServletResponse response)
275 throws IOException
276 {
277 String uri = request.getRequestURI();
278
279 String port = "";
280 String host = "";
281
282 int c = uri.indexOf(':');
283 if (c>=0)
284 {
285 port = uri.substring(c+1);
286 host = uri.substring(0,c);
287 if (host.indexOf('/')>0)
288 host = host.substring(host.indexOf('/')+1);
289 }
290
291
292
293
294 InetSocketAddress inetAddress = new InetSocketAddress (host, Integer.parseInt(port));
295
296
297
298
299
300
301 {
302 InputStream in=request.getInputStream();
303 OutputStream out=response.getOutputStream();
304
305 Socket socket = new Socket(inetAddress.getAddress(),inetAddress.getPort());
306
307 response.setStatus(200);
308 response.setHeader("Connection","close");
309 response.flushBuffer();
310
311 IO.copyThread(socket.getInputStream(),out);
312 IO.copy(in,socket.getOutputStream());
313 }
314 }
315
316
317
318
319
320
321
322 public String getServletInfo()
323 {
324 return "Proxy Servlet";
325 }
326
327
328
329
330 public void destroy()
331 {
332
333 }
334
335
336
337
338
339
340
341
342
343
344
345
346 public static class Transparent extends ProxyServlet
347 {
348 String _prefix;
349 String _proxyTo;
350
351 public Transparent()
352 {
353 }
354
355 public Transparent(String prefix,String server, int port)
356 {
357 _prefix=prefix;
358 _proxyTo="http://"+server+":"+port;
359 }
360
361 public void init(ServletConfig config) throws ServletException
362 {
363 if (config.getInitParameter("ProxyTo")!=null)
364 _proxyTo=config.getInitParameter("ProxyTo");
365 if (config.getInitParameter("Prefix")!=null)
366 _prefix=config.getInitParameter("Prefix");
367 if (_proxyTo==null)
368 throw new UnavailableException("No ProxyTo");
369 super.init(config);
370
371 _context.log("Transparent ProxyServlet @ "+(_prefix==null?"-":_prefix)+ " to "+_proxyTo);
372
373 }
374
375 protected URL proxyHttpURL(final String scheme, final String serverName, int serverPort, final String uri) throws MalformedURLException
376 {
377 if (_prefix!=null && !uri.startsWith(_prefix))
378 return null;
379
380 if (_prefix!=null)
381 return new URL(_proxyTo+uri.substring(_prefix.length()));
382 return new URL(_proxyTo+uri);
383 }
384 }
385
386 }