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.Socket;
24 import java.net.URL;
25 import java.net.URLConnection;
26 import java.util.Enumeration;
27 import java.util.HashSet;
28
29 import javax.servlet.Servlet;
30 import javax.servlet.ServletConfig;
31 import javax.servlet.ServletContext;
32 import javax.servlet.ServletException;
33 import javax.servlet.ServletRequest;
34 import javax.servlet.ServletResponse;
35 import javax.servlet.http.HttpServletRequest;
36 import javax.servlet.http.HttpServletResponse;
37
38 import org.mortbay.util.IO;
39
40
41
42
43
44
45
46
47 public class ProxyServlet implements Servlet
48 {
49 private int _tunnelTimeoutMs=300000;
50
51 protected HashSet _DontProxyHeaders = new HashSet();
52 {
53 _DontProxyHeaders.add("proxy-connection");
54 _DontProxyHeaders.add("connection");
55 _DontProxyHeaders.add("keep-alive");
56 _DontProxyHeaders.add("transfer-encoding");
57 _DontProxyHeaders.add("te");
58 _DontProxyHeaders.add("trailer");
59 _DontProxyHeaders.add("proxy-authorization");
60 _DontProxyHeaders.add("proxy-authenticate");
61 _DontProxyHeaders.add("upgrade");
62 }
63
64 private ServletConfig config;
65 private ServletContext context;
66
67
68
69
70 public void init(ServletConfig config) throws ServletException
71 {
72 this.config=config;
73 this.context=config.getServletContext();
74 }
75
76
77
78
79 public ServletConfig getServletConfig()
80 {
81 return config;
82 }
83
84
85
86
87 public void service(ServletRequest req, ServletResponse res) throws ServletException,
88 IOException
89 {
90 HttpServletRequest request = (HttpServletRequest)req;
91 HttpServletResponse response = (HttpServletResponse)res;
92 if ("CONNECT".equalsIgnoreCase(request.getMethod()))
93 {
94 handleConnect(request,response);
95 }
96 else
97 {
98 String uri=request.getRequestURI();
99 if (request.getQueryString()!=null)
100 uri+="?"+request.getQueryString();
101 URL url = new URL(request.getScheme(),
102 request.getServerName(),
103 request.getServerPort(),
104 uri);
105
106 context.log("URL="+url);
107
108 URLConnection connection = url.openConnection();
109 connection.setAllowUserInteraction(false);
110
111
112 HttpURLConnection http = null;
113 if (connection instanceof HttpURLConnection)
114 {
115 http = (HttpURLConnection)connection;
116 http.setRequestMethod(request.getMethod());
117 http.setInstanceFollowRedirects(false);
118 }
119
120
121 String connectionHdr = request.getHeader("Connection");
122 if (connectionHdr!=null)
123 {
124 connectionHdr=connectionHdr.toLowerCase();
125 if (connectionHdr.equals("keep-alive")||
126 connectionHdr.equals("close"))
127 connectionHdr=null;
128 }
129
130
131 boolean xForwardedFor=false;
132 boolean hasContent=false;
133 Enumeration enm = request.getHeaderNames();
134 while (enm.hasMoreElements())
135 {
136
137 String hdr=(String)enm.nextElement();
138 String lhdr=hdr.toLowerCase();
139
140 if (_DontProxyHeaders.contains(lhdr))
141 continue;
142 if (connectionHdr!=null && connectionHdr.indexOf(lhdr)>=0)
143 continue;
144
145 if ("content-type".equals(lhdr))
146 hasContent=true;
147
148 Enumeration vals = request.getHeaders(hdr);
149 while (vals.hasMoreElements())
150 {
151 String val = (String)vals.nextElement();
152 if (val!=null)
153 {
154 connection.addRequestProperty(hdr,val);
155 context.log("req "+hdr+": "+val);
156 xForwardedFor|="X-Forwarded-For".equalsIgnoreCase(hdr);
157 }
158 }
159 }
160
161
162 connection.setRequestProperty("Via","1.1 (jetty)");
163 if (!xForwardedFor)
164 connection.addRequestProperty("X-Forwarded-For",
165 request.getRemoteAddr());
166
167
168 String cache_control = request.getHeader("Cache-Control");
169 if (cache_control!=null &&
170 (cache_control.indexOf("no-cache")>=0 ||
171 cache_control.indexOf("no-store")>=0))
172 connection.setUseCaches(false);
173
174
175
176 try
177 {
178 connection.setDoInput(true);
179
180
181 InputStream in=request.getInputStream();
182 if (hasContent)
183 {
184 connection.setDoOutput(true);
185 IO.copy(in,connection.getOutputStream());
186 }
187
188
189 connection.connect();
190 }
191 catch (Exception e)
192 {
193 context.log("proxy",e);
194 }
195
196 InputStream proxy_in = null;
197
198
199 int code=500;
200 if (http!=null)
201 {
202 proxy_in = http.getErrorStream();
203
204 code=http.getResponseCode();
205 response.setStatus(code, http.getResponseMessage());
206 context.log("response = "+http.getResponseCode());
207 }
208
209 if (proxy_in==null)
210 {
211 try {proxy_in=connection.getInputStream();}
212 catch (Exception e)
213 {
214 context.log("stream",e);
215 proxy_in = http.getErrorStream();
216 }
217 }
218
219
220 response.setHeader("Date",null);
221 response.setHeader("Server",null);
222
223
224 int h=0;
225 String hdr=connection.getHeaderFieldKey(h);
226 String val=connection.getHeaderField(h);
227 while(hdr!=null || val!=null)
228 {
229 String lhdr = hdr!=null?hdr.toLowerCase():null;
230 if (hdr!=null && val!=null && !_DontProxyHeaders.contains(lhdr))
231 response.addHeader(hdr,val);
232
233 context.log("res "+hdr+": "+val);
234
235 h++;
236 hdr=connection.getHeaderFieldKey(h);
237 val=connection.getHeaderField(h);
238 }
239 response.addHeader("Via","1.1 (jetty)");
240
241
242 if (proxy_in!=null)
243 IO.copy(proxy_in,response.getOutputStream());
244
245 }
246 }
247
248
249
250 public void handleConnect(HttpServletRequest request,
251 HttpServletResponse response)
252 throws IOException
253 {
254 String uri = request.getRequestURI();
255
256 context.log("CONNECT: "+uri);
257
258 String port = "";
259 String host = "";
260
261 int c = uri.indexOf(':');
262 if (c>=0)
263 {
264 port = uri.substring(c+1);
265 host = uri.substring(0,c);
266 if (host.indexOf('/')>0)
267 host = host.substring(host.indexOf('/')+1);
268 }
269
270
271
272
273 InetSocketAddress inetAddress = new InetSocketAddress (host, Integer.parseInt(port));
274
275
276
277
278
279
280 {
281 InputStream in=request.getInputStream();
282 OutputStream out=response.getOutputStream();
283
284 Socket socket = new Socket(inetAddress.getAddress(),inetAddress.getPort());
285 context.log("Socket: "+socket);
286
287 response.setStatus(200);
288 response.setHeader("Connection","close");
289 response.flushBuffer();
290
291
292
293 context.log("out<-in");
294 IO.copyThread(socket.getInputStream(),out);
295 context.log("in->out");
296 IO.copy(in,socket.getOutputStream());
297 }
298 }
299
300
301
302
303
304
305
306 public String getServletInfo()
307 {
308 return "Proxy Servlet";
309 }
310
311
312
313
314 public void destroy()
315 {
316
317 }
318 }