fastcgiservlet.java

来自「RESIN 3.2 最新源码」· Java 代码 · 共 856 行 · 第 1/2 页

JAVA
856
字号
/* * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved * * This file is part of Resin(R) Open Source * * Each copy or derived work must preserve the copyright notice and this * notice unmodified. * * Resin Open Source is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Resin Open Source is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty * of NON-INFRINGEMENT.  See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with Resin Open Source; if not, write to the * *   Free Software Foundation, Inc. *   59 Temple Place, Suite 330 *   Boston, MA 02111-1307  USA * * @author Scott Ferguson */package com.caucho.servlets;import com.caucho.config.types.Period;import com.caucho.log.Log;import com.caucho.server.webapp.Application;import com.caucho.util.Alarm;import com.caucho.util.CharBuffer;import com.caucho.util.FreeList;import com.caucho.util.L10N;import com.caucho.util.QDate;import com.caucho.vfs.Path;import com.caucho.vfs.ReadStream;import com.caucho.vfs.SocketStream;import com.caucho.vfs.TempBuffer;import com.caucho.vfs.WriteStream;import javax.servlet.GenericServlet;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.net.InetAddress;import java.net.Socket;import java.util.ArrayList;import java.util.Enumeration;import java.util.logging.Level;import java.util.logging.Logger;/** * Load balancing. * * <pre> * &lt;servlet-mapping url-pattern='/remote/*'> *   &lt;servlet-name>com.caucho.server.http.FastCGIServlet&lt;/servlet-name> *   &lt;init-param server-address='localhost:8086'/> * &lt;/servlet-mapping> * </pre> */public class FastCGIServlet extends GenericServlet {  static final protected Logger log = Log.open(FastCGIServlet.class);  static final L10N L = new L10N(FastCGIServlet.class);    private static final int FCGI_BEGIN_REQUEST = 1;  private static final int FCGI_ABORT_REQUEST = 2;  private static final int FCGI_END_REQUEST = 3;  private static final int FCGI_PARAMS = 4;  private static final int FCGI_STDIN = 5;  private static final int FCGI_STDOUT = 6;  private static final int FCGI_STDERR = 7;  private static final int FCGI_DATA = 8;  private static final int FCGI_GET_VALUES = 9;  private static final int FCGI_GET_VALUES_RESULT = 10;  private static final int FCGI_UNKNOWNE_TYPE = 11;  private static final int FCGI_RESPONDER = 1;  private static final int FCGI_AUTHORIZER = 2;  private static final int FCGI_FILTER = 3;  private static final int FCGI_VERSION = 1;    private static final int FCGI_KEEP_CONN = 1;    private static final int FCGI_REQUEST_COMPLETE = 0;  private static final int FCGI_CANT_MPX_CONN = 1;  private static final int FCGI_OVERLOADED = 2;  private static final int FCGI_UNKNOWN_ROLE = 3;  private static final ArrayList<Integer> _fcgiServlets    = new ArrayList<Integer>();  private int _servletId;  private FreeList<FastCGISocket> _freeSockets =    new FreeList<FastCGISocket>(8);  private String _hostAddress;  private InetAddress _hostAddr;  private int _hostPort;  protected QDate _calendar = new QDate();  private Application _app;  private long _readTimeout = 120000;  private int _maxKeepaliveCount = 250;  private long _keepaliveTimeout = 15000;  private int _idCount = 0;  /**   * Sets the host address.   */  public void setServerAddress(String hostAddress)    throws ServletException  {    _hostAddress = hostAddress;    try {      int p = hostAddress.indexOf(':');      if (p > 0) {        _hostPort = new Integer(_hostAddress.substring(p + 1)).intValue();        _hostAddr = InetAddress.getByName(_hostAddress.substring(0, p));      }    } catch (Exception e) {      throw new ServletException(e);    }  }  /**   * Sets the keepalive max.   */  public void setMaxKeepalive(int max)  {    _maxKeepaliveCount = max;  }  /**   * Sets the keepalive timeout.   */  public void setKeepaliveTimeout(Period period)  {    _keepaliveTimeout = period.getPeriod();  }  /**   * Sets the socket timeout.   */  public void setReadTimeout(Period timeout)  {    _readTimeout = timeout.getPeriod();  }  /**   * Initialize the servlet with the server's sruns.   */  public void init()    throws ServletException  {    int id = -1;        for (int i = 0; i < 0x10000; i += 1024) {      if (! _fcgiServlets.contains(new Integer(i))) {	id = i;	break;      }    }    if (id < 0)      throw new ServletException("Can't open FastCGI servlet");    _fcgiServlets.add(new Integer(id));    _servletId = id;    _app = (Application) getServletContext();    String serverAddress = getInitParameter("server-address");    if (serverAddress != null)      setServerAddress(serverAddress);        if (_hostAddress == null)      throw new ServletException("FastCGIServlet needs valid server-address");  }  /**   * Handle the request.   */  public void service(ServletRequest request, ServletResponse response)    throws ServletException, IOException  {    HttpServletRequest req = (HttpServletRequest) request;    HttpServletResponse res = (HttpServletResponse) response;    OutputStream out = res.getOutputStream();    FastCGISocket fcgiSocket = null;    do {      if (fcgiSocket != null)	fcgiSocket.close();            fcgiSocket = _freeSockets.allocate();    } while (fcgiSocket != null && ! fcgiSocket.isValid());    if (fcgiSocket != null && fcgiSocket.isValid()) {      log.finer(fcgiSocket + ": reuse()");    }    else {      if (fcgiSocket != null)	fcgiSocket.close();            try {	Socket socket = new Socket(_hostAddr, _hostPort);	if (_readTimeout > 0)	  socket.setSoTimeout((int) _readTimeout);	fcgiSocket = new FastCGISocket(nextId(), socket, _maxKeepaliveCount);      } catch (IOException e) {	log.log(Level.FINE, e.toString(), e);	throw new ServletException(L.l("Can't connect to FastCGI {0}:{1}.  Check that the FastCGI service has started.", _hostAddr, _hostPort));      }    }    boolean isOkay = false;    try {      fcgiSocket.setExpire(Alarm.getCurrentTime() + _keepaliveTimeout);	      if (handleRequest(req, res, fcgiSocket, out,			fcgiSocket.allocateKeepalive())) {	if (_freeSockets.free(fcgiSocket)) {	  log.finer(fcgiSocket + ": keepalive()");	  	  fcgiSocket = null;	}      }    } catch (Exception e) {      log.log(Level.WARNING, e.toString(), e);    } finally {      if (fcgiSocket != null)        fcgiSocket.close();    }  }  private int nextId()  {    synchronized (this) {      int id = _idCount++;      if (id <= 0 || 1024 < id) {	_idCount = 2;	id = 1;      }      return id + _servletId;    }  }  private boolean handleRequest(HttpServletRequest req,				HttpServletResponse res,				FastCGISocket fcgiSocket,				OutputStream out,				boolean keepalive)    throws ServletException, IOException  {    ReadStream rs = fcgiSocket.getReadStream();    WriteStream ws = fcgiSocket.getWriteStream();        writeHeader(fcgiSocket, ws, FCGI_BEGIN_REQUEST, 8);    int role = FCGI_RESPONDER;        ws.write(role >> 8);    ws.write(role);    ws.write(keepalive ? FCGI_KEEP_CONN : 0); // flags    for (int i = 0; i < 5; i++)      ws.write(0);    setEnvironment(fcgiSocket, ws, req);    InputStream in = req.getInputStream();    TempBuffer tempBuf = TempBuffer.allocate();    byte []buf = tempBuf.getBuffer();    int len = buf.length;    int sublen;    writeHeader(fcgiSocket, ws, FCGI_PARAMS, 0);        boolean hasStdin = false;    while ((sublen = in.read(buf, 0, len)) > 0) {      hasStdin = true;      writeHeader(fcgiSocket, ws, FCGI_STDIN, sublen);      ws.write(buf, 0, sublen);    }    TempBuffer.free(tempBuf);    tempBuf = null;    if (hasStdin)      writeHeader(fcgiSocket, ws, FCGI_STDIN, 0);    FastCGIInputStream is = new FastCGIInputStream(fcgiSocket);    int ch = parseHeaders(res, is);    if (ch >= 0)      out.write(ch);    while ((ch = is.read()) >= 0)      out.write(ch);    return ! is.isDead() && keepalive;  }  private void setEnvironment(FastCGISocket fcgi,			      WriteStream ws, HttpServletRequest req)    throws IOException  {    addHeader(fcgi, ws, "REQUEST_URI", req.getRequestURI());    addHeader(fcgi, ws, "REQUEST_METHOD", req.getMethod());        addHeader(fcgi, ws, "SERVER_SOFTWARE", "Resin/" + com.caucho.Version.VERSION);        addHeader(fcgi, ws, "SERVER_NAME", req.getServerName());    //addHeader(fcgi, ws, "SERVER_ADDR=" + req.getServerAddr());    addHeader(fcgi, ws, "SERVER_PORT", String.valueOf(req.getServerPort()));        addHeader(fcgi, ws, "REMOTE_ADDR", req.getRemoteAddr());    addHeader(fcgi, ws, "REMOTE_HOST", req.getRemoteAddr());    // addHeader(fcgi, ws, "REMOTE_PORT=" + req.getRemotePort());    if (req.getRemoteUser() != null)      addHeader(fcgi, ws, "REMOTE_USER", req.getRemoteUser());    else      addHeader(fcgi, ws, "REMOTE_USER", "");    if (req.getAuthType() != null)      addHeader(fcgi, ws, "AUTH_TYPE", req.getAuthType());        addHeader(fcgi, ws, "GATEWAY_INTERFACE", "CGI/1.1");    addHeader(fcgi, ws, "SERVER_PROTOCOL", req.getProtocol());    if (req.getQueryString() != null)      addHeader(fcgi, ws, "QUERY_STRING", req.getQueryString());    else      addHeader(fcgi, ws, "QUERY_STRING", "");    String scriptPath = req.getServletPath();    String pathInfo = req.getPathInfo();        Path appDir = _app.getAppDir();    String realPath = _app.getRealPath(scriptPath);        if (! appDir.lookup(realPath).isFile() && pathInfo != null)      scriptPath = scriptPath + pathInfo;    /*     * FastCGI (specifically quercus) uses the PATH_INFO and PATH_TRANSLATED     * for the script path.     */    log.finer("FCGI file: " + _app.getRealPath(scriptPath));    addHeader(fcgi, ws, "PATH_INFO", req.getContextPath() + scriptPath);    addHeader(fcgi, ws, "PATH_TRANSLATED", _app.getRealPath(scriptPath));        /* These are the values which would be sent to CGI.    addHeader(fcgi, ws, "SCRIPT_NAME", req.getContextPath() + scriptPath);    addHeader(fcgi, ws, "SCRIPT_FILENAME", app.getRealPath(scriptPath));        if (pathInfo != null) {      addHeader(fcgi, ws, "PATH_INFO", pathInfo);      addHeader(fcgi, ws, "PATH_TRANSLATED", req.getRealPath(pathInfo));    }    else {      addHeader(fcgi, ws, "PATH_INFO", "");      addHeader(fcgi, ws, "PATH_TRANSLATED", "");    }    */    int contentLength = req.getContentLength();    if (contentLength < 0)      addHeader(fcgi, ws, "CONTENT_LENGTH", "0");    else      addHeader(fcgi, ws, "CONTENT_LENGTH", String.valueOf(contentLength));    addHeader(fcgi, ws, "DOCUMENT_ROOT", _app.getContext("/").getRealPath("/"));    CharBuffer cb = new CharBuffer();        Enumeration e = req.getHeaderNames();    while (e.hasMoreElements()) {      String key = (String) e.nextElement();      String value = req.getHeader(key);      if (key.equalsIgnoreCase("content-length"))        addHeader(fcgi, ws, "CONTENT_LENGTH", value);      else if (key.equalsIgnoreCase("content-type"))        addHeader(fcgi, ws, "CONTENT_TYPE", value);      else if (key.equalsIgnoreCase("if-modified-since")) {      }      else if (key.equalsIgnoreCase("if-none-match")) {      }      else if (key.equalsIgnoreCase("authorization")) {      }      else if (key.equalsIgnoreCase("proxy-authorization")) {      }      else        addHeader(fcgi, ws, convertHeader(cb, key), value);    }  }  private CharBuffer convertHeader(CharBuffer cb, String key)  {    cb.clear();    cb.append("HTTP_");    

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?