001: // ========================================================================
002: // $Id: ProxyServlet.java 800 2006-08-20 00:01:46Z gregw $
003: // Copyright 2004-2004 Mort Bay Consulting Pty. Ltd.
004: // ------------------------------------------------------------------------
005: // Licensed under the Apache License, Version 2.0 (the "License");
006: // you may not use this file except in compliance with the License.
007: // You may obtain a copy of the License at
008: // http://www.apache.org/licenses/LICENSE-2.0
009: // Unless required by applicable law or agreed to in writing, software
010: // distributed under the License is distributed on an "AS IS" BASIS,
011: // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012: // See the License for the specific language governing permissions and
013: // limitations under the License.
014: // ========================================================================
015:
016: package org.mortbay.servlet;
017:
018: import java.io.IOException;
019: import java.io.InputStream;
020: import java.io.OutputStream;
021: import java.net.HttpURLConnection;
022: import java.net.InetSocketAddress;
023: import java.net.Socket;
024: import java.net.URL;
025: import java.net.URLConnection;
026: import java.util.Enumeration;
027: import java.util.HashSet;
028:
029: import javax.servlet.Servlet;
030: import javax.servlet.ServletConfig;
031: import javax.servlet.ServletContext;
032: import javax.servlet.ServletException;
033: import javax.servlet.ServletRequest;
034: import javax.servlet.ServletResponse;
035: import javax.servlet.http.HttpServletRequest;
036: import javax.servlet.http.HttpServletResponse;
037:
038: import org.mortbay.util.IO;
039:
040: /**
041: * EXPERIMENTAL Proxy servlet.
042: * @author gregw
043: *
044: */
045: public class ProxyServlet implements Servlet {
046: private int _tunnelTimeoutMs = 300000;
047:
048: protected HashSet _DontProxyHeaders = new HashSet();
049: {
050: _DontProxyHeaders.add("proxy-connection");
051: _DontProxyHeaders.add("connection");
052: _DontProxyHeaders.add("keep-alive");
053: _DontProxyHeaders.add("transfer-encoding");
054: _DontProxyHeaders.add("te");
055: _DontProxyHeaders.add("trailer");
056: _DontProxyHeaders.add("proxy-authorization");
057: _DontProxyHeaders.add("proxy-authenticate");
058: _DontProxyHeaders.add("upgrade");
059: }
060:
061: private ServletConfig config;
062: private ServletContext context;
063:
064: /* (non-Javadoc)
065: * @see javax.servlet.Servlet#init(javax.servlet.ServletConfig)
066: */
067: public void init(ServletConfig config) throws ServletException {
068: this .config = config;
069: this .context = config.getServletContext();
070: }
071:
072: /* (non-Javadoc)
073: * @see javax.servlet.Servlet#getServletConfig()
074: */
075: public ServletConfig getServletConfig() {
076: return config;
077: }
078:
079: /* (non-Javadoc)
080: * @see javax.servlet.Servlet#service(javax.servlet.ServletRequest, javax.servlet.ServletResponse)
081: */
082: public void service(ServletRequest req, ServletResponse res)
083: throws ServletException, IOException {
084: HttpServletRequest request = (HttpServletRequest) req;
085: HttpServletResponse response = (HttpServletResponse) res;
086: if ("CONNECT".equalsIgnoreCase(request.getMethod())) {
087: handleConnect(request, response);
088: } else {
089: String uri = request.getRequestURI();
090: if (request.getQueryString() != null)
091: uri += "?" + request.getQueryString();
092: URL url = new URL(request.getScheme(), request
093: .getServerName(), request.getServerPort(), uri);
094:
095: context.log("URL=" + url);
096:
097: URLConnection connection = url.openConnection();
098: connection.setAllowUserInteraction(false);
099:
100: // Set method
101: HttpURLConnection http = null;
102: if (connection instanceof HttpURLConnection) {
103: http = (HttpURLConnection) connection;
104: http.setRequestMethod(request.getMethod());
105: http.setInstanceFollowRedirects(false);
106: }
107:
108: // check connection header
109: String connectionHdr = request.getHeader("Connection");
110: if (connectionHdr != null) {
111: connectionHdr = connectionHdr.toLowerCase();
112: if (connectionHdr.equals("keep-alive")
113: || connectionHdr.equals("close"))
114: connectionHdr = null;
115: }
116:
117: // copy headers
118: boolean xForwardedFor = false;
119: boolean hasContent = false;
120: Enumeration enm = request.getHeaderNames();
121: while (enm.hasMoreElements()) {
122: // TODO could be better than this!
123: String hdr = (String) enm.nextElement();
124: String lhdr = hdr.toLowerCase();
125:
126: if (_DontProxyHeaders.contains(lhdr))
127: continue;
128: if (connectionHdr != null
129: && connectionHdr.indexOf(lhdr) >= 0)
130: continue;
131:
132: if ("content-type".equals(lhdr))
133: hasContent = true;
134:
135: Enumeration vals = request.getHeaders(hdr);
136: while (vals.hasMoreElements()) {
137: String val = (String) vals.nextElement();
138: if (val != null) {
139: connection.addRequestProperty(hdr, val);
140: context.log("req " + hdr + ": " + val);
141: xForwardedFor |= "X-Forwarded-For"
142: .equalsIgnoreCase(hdr);
143: }
144: }
145: }
146:
147: // Proxy headers
148: connection.setRequestProperty("Via", "1.1 (jetty)");
149: if (!xForwardedFor)
150: connection.addRequestProperty("X-Forwarded-For",
151: request.getRemoteAddr());
152:
153: // a little bit of cache control
154: String cache_control = request.getHeader("Cache-Control");
155: if (cache_control != null
156: && (cache_control.indexOf("no-cache") >= 0 || cache_control
157: .indexOf("no-store") >= 0))
158: connection.setUseCaches(false);
159:
160: // customize Connection
161:
162: try {
163: connection.setDoInput(true);
164:
165: // do input thang!
166: InputStream in = request.getInputStream();
167: if (hasContent) {
168: connection.setDoOutput(true);
169: IO.copy(in, connection.getOutputStream());
170: }
171:
172: // Connect
173: connection.connect();
174: } catch (Exception e) {
175: context.log("proxy", e);
176: }
177:
178: InputStream proxy_in = null;
179:
180: // handler status codes etc.
181: int code = 500;
182: if (http != null) {
183: proxy_in = http.getErrorStream();
184:
185: code = http.getResponseCode();
186: response.setStatus(code, http.getResponseMessage());
187: context.log("response = " + http.getResponseCode());
188: }
189:
190: if (proxy_in == null) {
191: try {
192: proxy_in = connection.getInputStream();
193: } catch (Exception e) {
194: context.log("stream", e);
195: proxy_in = http.getErrorStream();
196: }
197: }
198:
199: // clear response defaults.
200: response.setHeader("Date", null);
201: response.setHeader("Server", null);
202:
203: // set response headers
204: int h = 0;
205: String hdr = connection.getHeaderFieldKey(h);
206: String val = connection.getHeaderField(h);
207: while (hdr != null || val != null) {
208: String lhdr = hdr != null ? hdr.toLowerCase() : null;
209: if (hdr != null && val != null
210: && !_DontProxyHeaders.contains(lhdr))
211: response.addHeader(hdr, val);
212:
213: context.log("res " + hdr + ": " + val);
214:
215: h++;
216: hdr = connection.getHeaderFieldKey(h);
217: val = connection.getHeaderField(h);
218: }
219: response.addHeader("Via", "1.1 (jetty)");
220:
221: // Handle
222: if (proxy_in != null)
223: IO.copy(proxy_in, response.getOutputStream());
224:
225: }
226: }
227:
228: /* ------------------------------------------------------------ */
229: public void handleConnect(HttpServletRequest request,
230: HttpServletResponse response) throws IOException {
231: String uri = request.getRequestURI();
232:
233: context.log("CONNECT: " + uri);
234:
235: String port = "";
236: String host = "";
237:
238: int c = uri.indexOf(':');
239: if (c >= 0) {
240: port = uri.substring(c + 1);
241: host = uri.substring(0, c);
242: if (host.indexOf('/') > 0)
243: host = host.substring(host.indexOf('/') + 1);
244: }
245:
246: InetSocketAddress inetAddress = new InetSocketAddress(host,
247: Integer.parseInt(port));
248:
249: //if (isForbidden(HttpMessage.__SSL_SCHEME,addrPort.getHost(),addrPort.getPort(),false))
250: //{
251: // sendForbid(request,response,uri);
252: //}
253: //else
254: {
255: InputStream in = request.getInputStream();
256: OutputStream out = response.getOutputStream();
257:
258: Socket socket = new Socket(inetAddress.getAddress(),
259: inetAddress.getPort());
260: context.log("Socket: " + socket);
261:
262: response.setStatus(200);
263: response.setHeader("Connection", "close");
264: response.flushBuffer();
265:
266: context.log("out<-in");
267: IO.copyThread(socket.getInputStream(), out);
268: context.log("in->out");
269: IO.copy(in, socket.getOutputStream());
270: }
271: }
272:
273: /* (non-Javadoc)
274: * @see javax.servlet.Servlet#getServletInfo()
275: */
276: public String getServletInfo() {
277: return "Proxy Servlet";
278: }
279:
280: /* (non-Javadoc)
281: * @see javax.servlet.Servlet#destroy()
282: */
283: public void destroy() {
284:
285: }
286: }
|