001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Scott Ferguson
028: */
029:
030: package com.caucho.servlets;
031:
032: import com.caucho.util.L10N;
033: import com.caucho.vfs.Path;
034: import com.caucho.vfs.ReadStream;
035: import com.caucho.vfs.ReadWritePair;
036: import com.caucho.vfs.Vfs;
037: import com.caucho.vfs.WriteStream;
038: import com.caucho.config.types.*;
039:
040: import javax.servlet.GenericServlet;
041: import javax.servlet.ServletException;
042: import javax.servlet.ServletRequest;
043: import javax.servlet.ServletResponse;
044: import javax.servlet.http.HttpServletRequest;
045: import javax.servlet.http.HttpServletResponse;
046: import java.io.IOException;
047: import java.io.InputStream;
048: import java.io.OutputStream;
049: import java.io.PrintWriter;
050: import java.util.ArrayList;
051: import java.util.Enumeration;
052: import java.util.Iterator;
053: import java.util.logging.Level;
054: import java.util.logging.Logger;
055:
056: /**
057: * HTTP proxy
058: *
059: * <pre>
060: * <servlet>
061: * <servlet-name>http-proxy</servlet-name>
062: * <servlet-class>com.caucho.servlets.HttpProxyServlet</servlet-class>
063: * <init host='localhost:8081'/>
064: * </servlet>
065: * </pre>
066: */
067: public class HttpProxyServlet extends GenericServlet {
068: static protected final Logger log = Logger
069: .getLogger(HttpProxyServlet.class.getName());
070: static final L10N L = new L10N(HttpProxyServlet.class);
071:
072: private TcpPool _tcpPool = new TcpPool();
073:
074: /**
075: * Adds an address
076: */
077: public void addAddress(String address) {
078: _tcpPool.addHost(address);
079: }
080:
081: /**
082: * Adds a host
083: */
084: public void addHost(String host) {
085: _tcpPool.addHost(host);
086: }
087:
088: /**
089: * Sets the fail recover time.
090: */
091: public void setFailRecoverTime(Period period) {
092: _tcpPool.setFailRecoverTime(period);
093: }
094:
095: /**
096: * Initialize the servlet with the server's sruns.
097: */
098: public void init() throws ServletException {
099: _tcpPool.init();
100: }
101:
102: /**
103: * Handle the request.
104: */
105: public void service(ServletRequest request, ServletResponse response)
106: throws ServletException, IOException {
107: HttpServletRequest req = (HttpServletRequest) request;
108: HttpServletResponse res = (HttpServletResponse) response;
109:
110: PrintWriter out = res.getWriter();
111:
112: String uri;
113: if (req.isRequestedSessionIdFromUrl()) {
114: uri = (req.getRequestURI() + ";jsessionid=" + req
115: .getRequestedSessionId());
116: } else
117: uri = req.getRequestURI();
118:
119: if (req.getQueryString() != null)
120: uri += '?' + req.getQueryString();
121:
122: int count = _tcpPool.getServerCount();
123:
124: for (int i = 0; i < count; i++) {
125: TcpPool.Server server = _tcpPool.nextServer();
126:
127: ReadWritePair pair = null;
128:
129: try {
130: pair = server.open(uri);
131: } catch (IOException e) {
132: log.log(Level.FINE, e.toString(), e);
133: }
134:
135: if (pair == null)
136: continue;
137:
138: try {
139: if (handleRequest(req, res, server, pair))
140: return;
141:
142: server.fail();
143: } finally {
144: server.close();
145: }
146: }
147:
148: res.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
149: }
150:
151: private boolean handleRequest(HttpServletRequest req,
152: HttpServletResponse res, TcpPool.Server server,
153: ReadWritePair pair) throws ServletException, IOException {
154: String hostURL = server.getURL();
155:
156: ReadStream rs = pair.getReadStream();
157: WriteStream ws = pair.getWriteStream();
158:
159: try {
160: ws.setAttribute("method", req.getMethod());
161:
162: Enumeration e = req.getHeaderNames();
163: while (e.hasMoreElements()) {
164: String name = (String) e.nextElement();
165: String value = req.getHeader(name);
166:
167: ws.setAttribute(name, value);
168: }
169:
170: InputStream is = req.getInputStream();
171: ws.writeStream(is);
172:
173: String status = (String) rs.getAttribute("status");
174: int statusCode = 200;
175:
176: if (status != null) {
177: try {
178: statusCode = Integer.parseInt(status);
179: } catch (Throwable e1) {
180: }
181: }
182:
183: String location = null;
184: Iterator iter = rs.getAttributeNames();
185: while (iter.hasNext()) {
186: String name = (String) iter.next();
187:
188: if (name.equalsIgnoreCase("status")) {
189: } else if (name.equalsIgnoreCase("transfer-encoding")) {
190: } else if (name.equalsIgnoreCase("content-length")) {
191: } else if (name.equalsIgnoreCase("location"))
192: location = (String) rs.getAttribute("location");
193: else
194: res.addHeader(name, (String) rs.getAttribute(name));
195: }
196:
197: if (location == null) {
198: } else if (location.startsWith(hostURL)) {
199: location = location.substring(hostURL.length());
200:
201: String prefix;
202: if (req.isSecure()) {
203: if (req.getServerPort() != 443)
204: prefix = ("https://" + req.getServerName()
205: + ":" + req.getServerPort());
206: else
207: prefix = ("https://" + req.getServerName());
208: } else {
209: if (req.getServerPort() != 80)
210: prefix = ("http://" + req.getServerName() + ":" + req
211: .getServerPort());
212: else
213: prefix = ("http://" + req.getServerName());
214: }
215:
216: if (!location.startsWith("/"))
217: location = prefix + "/" + location;
218: else
219: location = prefix + location;
220: }
221:
222: if (location != null)
223: res.setHeader("Location", location);
224:
225: if (statusCode == 302 && location != null)
226: res.sendRedirect(location);
227: else if (statusCode != 200)
228: res.setStatus(statusCode);
229:
230: OutputStream os = res.getOutputStream();
231: rs.writeToStream(os);
232: } catch (IOException e1) {
233: log.log(Level.FINE, e1.toString(), e1);
234:
235: return false;
236: } finally {
237: ws.close();
238: rs.close();
239: }
240:
241: return true;
242: }
243: }
|