hmuxrequest.java

来自「RESIN 3.2 最新源码」· Java 代码 · 共 1,842 行 · 第 1/3 页

JAVA
1,842
字号
/* * 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.server.hmux;import com.caucho.hessian.io.*;import com.caucho.bam.*;import com.caucho.server.cluster.Cluster;import com.caucho.server.cluster.Server;import com.caucho.server.connection.AbstractHttpRequest;import com.caucho.server.connection.Connection;import com.caucho.server.dispatch.DispatchServer;import com.caucho.server.dispatch.Invocation;import com.caucho.server.dispatch.InvocationDecoder;import com.caucho.server.http.InvocationKey;import com.caucho.server.port.ServerRequest;import com.caucho.server.webapp.ErrorPageManager;import com.caucho.util.*;import com.caucho.vfs.ClientDisconnectException;import com.caucho.vfs.ReadStream;import com.caucho.vfs.StreamImpl;import com.caucho.vfs.WriteStream;import java.io.*;import java.net.InetAddress;import java.security.cert.CertificateFactory;import java.security.cert.X509Certificate;import java.util.*;import java.util.logging.Level;import java.util.logging.Logger;/** * Handles requests from a remote dispatcher.  For example, mod_caucho * and the IIS plugin use this protocol to talk to the backend. * * <p>Packets are straightforward: * <pre>code l2 l1 l0 contents</pre> * Where code is the code of the packet and l2-0 give 12 bits of length. * * <p>The protocol is designed to allow pipelining and buffering whenever * possible.  So most commands are not acked.  Data from the frontend (POST) * does need acks to prevent deadlocks at either end while waiting * for new data. * * <p>The overriding protocol is controlled by requests from the * frontend server. *  * <p>A ping request: * <pre> * Frontend       Backend * CSE_PING * CSE_END *                CSE_END * <pre> *  * <p>A GET request: * <pre> * Frontend       Backend * CSE_METHOD * ... * CSE_HEADER/CSE_VALUE * CSE_END *                CSE_DATA *                CSE_DATA *                CSE_END * <pre> *  * <p>Short POST: * <pre> * Frontend       Backend * CSE_METHOD * ... * CSE_HEADER/CSE_VALUE * CSE_DATA * CSE_END *                CSE_DATA *                CSE_DATA *                CSE_END * <pre> *  * <p>Long POST: * <pre> * Frontend       Backend * CSE_METHOD * ... * CSE_HEADER/CSE_VALUE * CSE_DATA *                CSE_DATA (optional) * CSE_DATA *                CSE_ACK *                CSE_DATA (optional) * CSE_DATA *                CSE_ACK * CSE_END *                CSE_DATA *                CSE_END * <pre> *  */public class HmuxRequest extends AbstractHttpRequest  implements ServerRequest{  private static final L10N L = new L10N(HmuxRequest.class);  private static final Logger log    = Logger.getLogger(HmuxRequest.class.getName());  // HMUX channel control codes  public static final int HMUX_CHANNEL =        'C';  public static final int HMUX_ACK =            'A';  public static final int HMUX_ERROR =          'E';  public static final int HMUX_YIELD =          'Y';  public static final int HMUX_QUIT =           'Q';  public static final int HMUX_EXIT =           'X';  public static final int HMUX_DATA =           'D';  public static final int HMUX_URI =            'U';  public static final int HMUX_STRING =         'S';  public static final int HMUX_HEADER =         'H';  public static final int HMUX_BINARY =         'B';  public static final int HMUX_PROTOCOL =       'P';  public static final int HMUX_META_HEADER =    'M';    // The following are HTTP codes  public static final int CSE_NULL =            '?';  public static final int CSE_PATH_INFO =       'b';  public static final int CSE_PROTOCOL =        'c';  public static final int CSE_REMOTE_USER =     'd';  public static final int CSE_QUERY_STRING =    'e';  public static final int HMUX_FLUSH  =         'f';  public static final int CSE_SERVER_PORT =     'g';  public static final int CSE_REMOTE_HOST =     'h';  public static final int CSE_REMOTE_ADDR =     'i';  public static final int CSE_REMOTE_PORT =     'j';  public static final int CSE_REAL_PATH =       'k';  public static final int CSE_SCRIPT_FILENAME = 'l';  public static final int HMUX_METHOD =         'm';  public static final int CSE_AUTH_TYPE =       'n';  public static final int CSE_URI =             'o';  public static final int CSE_CONTENT_LENGTH =  'p';  public static final int CSE_CONTENT_TYPE =    'q';  public static final int CSE_IS_SECURE =       'r';  public static final int HMUX_STATUS =         's';  public static final int CSE_CLIENT_CERT =     't';  public static final int CSE_SERVER_TYPE =     'u';  public static final int HMUX_SERVER_NAME =    'v';    public static final int CSE_SEND_HEADER =     'G';  public static final int CSE_DATA =            'D';  public static final int CSE_FLUSH =           'F';  public static final int CSE_KEEPALIVE =       'K';  public static final int CSE_ACK =             'A';  public static final int CSE_END =             'Z';  public static final int CSE_CLOSE =           'X';  // other, specialized protocols  public static final int CSE_QUERY =           'Q';  public static final int CSE_PING =            'P';  public static final int HMTP_MESSAGE =        '0';  public static final int HMTP_QUERY_GET =      '1';  public static final int HMTP_QUERY_SET =      '2';  public static final int HMTP_QUERY_RESULT =   '3';  public static final int HMTP_ERROR =          '4';  public static final int HMTP_PACKET =         '5';  public static final int HMUX_CLUSTER_PROTOCOL = 0x101;  public static final int HMUX_DISPATCH_PROTOCOL = 0x102;  public static final int HMUX_JMS_PROTOCOL = 0x103;  public enum ProtocolResult {    QUIT,    EXIT,    YIELD  };    static final int HTTP_0_9 = 0x0009;  static final int HTTP_1_0 = 0x0100;  static final int HTTP_1_1 = 0x0101;  private static final int HEADER_CAPACITY = 256;    static final CharBuffer _getCb = new CharBuffer("GET");  static final CharBuffer _headCb = new CharBuffer("HEAD");  static final CharBuffer _postCb = new CharBuffer("POST");  private final CharBuffer _method;   // "GET"  private String _methodString;       // "GET"  // private CharBuffer scheme;       // "http:"  private CharBuffer _host;            // www.caucho.com  private int _port;                   // :80  private ByteBuffer _uri;             // "/path/test.jsp/Junk"  private CharBuffer _protocol;        // "HTTP/1.0"  private int _version;  private CharBuffer _remoteAddr;  private CharBuffer _remoteHost;  private CharBuffer _serverName;  private CharBuffer _serverPort;  private CharBuffer _remotePort;    private boolean _isSecure;  private ByteBuffer _clientCert;  private CharBuffer []_headerKeys;  private CharBuffer []_headerValues;  private int _headerSize;  private byte []_lengthBuf;  private int _serverType;  // write stream from the connection  private WriteStream _rawWrite;  // servlet write stream  private WriteStream _writeStream;    // StreamImpl to break reads and writes to the underlying protocol  private ServletFilter _filter;  private int _pendingData;  private InvocationKey _invocationKey = new InvocationKey();  private CharBuffer _cb1;  private CharBuffer _cb2;  private boolean _hasRequest;  private Hessian2StreamingInput _in;  private Hessian2StreamingOutput _out;  private Server _server;  private AbstractClusterRequest _clusterRequest;  private HmuxDispatchRequest _dispatchRequest;  private Cluster _cluster;  private HmuxProtocol _hmuxProtocol;  private ErrorPageManager _errorManager = new ErrorPageManager(null);  private int _srunIndex;  public HmuxRequest(DispatchServer server,		     Connection conn,		     HmuxProtocol protocol)  {    super(server, conn);    _server = (Server) server;        _hmuxProtocol = protocol;    _response = new HmuxResponse(this);    _rawWrite = conn.getWriteStream();    _writeStream = new WriteStream();    _writeStream.setReuseBuffer(true);    // XXX: response.setIgnoreClientDisconnect(server.getIgnoreClientDisconnect());    _cluster = Cluster.getLocal();    if (_cluster != null) {      try {	Class cl = Class.forName("com.caucho.server.hmux.HmuxClusterRequest");	_clusterRequest = (AbstractClusterRequest) cl.newInstance();	_clusterRequest.setRequest(this);	_clusterRequest.setCluster(_cluster);      } catch (ClassNotFoundException e) {	log.finer(e.toString());      } catch (Throwable e) {	log.log(Level.FINER, e.toString(), e);      }    }        _dispatchRequest = new HmuxDispatchRequest(this);        _uri = new ByteBuffer();    _method = new CharBuffer();    _host = new CharBuffer();    _protocol = new CharBuffer();    _headerKeys = new CharBuffer[HEADER_CAPACITY];    _headerValues = new CharBuffer[_headerKeys.length];    for (int i = 0; i < _headerKeys.length; i++) {      _headerKeys[i] = new CharBuffer();      _headerValues[i] = new CharBuffer();    }    _remoteHost = new CharBuffer();    _remoteAddr = new CharBuffer();    _serverName = new CharBuffer();    _serverPort = new CharBuffer();    _remotePort = new CharBuffer();    _clientCert = new ByteBuffer();    _cb1 = new CharBuffer();    _cb2 = new CharBuffer();    _lengthBuf = new byte[16];    _filter = new ServletFilter();  }  public boolean isWaitForRead()  {    return true;  }  /**   * Called when the connection starts.   */  public void startConnection()  {    _in = null;    _out = null;  }  /**   * Handles a new request.  Initializes the protocol handler and   * the request streams.   *   * <p>Note: ClientDisconnectException must be rethrown to   * the caller.   */  public boolean handleRequest()    throws IOException  {    // XXX: should be moved to TcpConnection    Thread thread = Thread.currentThread();    thread.setContextClassLoader(_server.getClassLoader());        if (log.isLoggable(Level.FINE))      log.fine(dbgId() + "start request");    _filter.init(this, _rawRead, _rawWrite);    _writeStream.init(_filter);    // _writeStream.setWritePrefix(3);    _response.init(_writeStream);    _serverType = 0;    _uri.setLength(0);    boolean hasRequest = false;        try {      start();      _response.start();      try {        if (! scanHeaders()) {          killKeepalive();          return false;        }        else if (_uri.size() == 0) {          return true;	}      } catch (InterruptedIOException e) {        killKeepalive();        log.fine(dbgId() + "interrupted keepalive");        return false;      }      if (_isSecure)        getClientCertificate();      hasRequest = true;      // setStartDate();      if (_server == null || _server.isDestroyed()) {	log.fine(dbgId() + "server is closed");		try {	  _writeStream.setDisableClose(false);	  _writeStream.close();	} catch (Throwable e) {	}		try {	  _readStream.setDisableClose(false);	  _readStream.close();	} catch (Throwable e) {	}	return false;      }      _filter.setPending(_pendingData);      try {        if (_method.getLength() == 0)          throw new RuntimeException("HTTP protocol exception");                  _invocationKey.init(_isSecure,			    getHost(), getServerPort(),                            _uri.getBuffer(), _uri.getLength());        Invocation invocation;        invocation = _server.getInvocation(_invocationKey);        if (invocation == null) {          invocation = _server.createInvocation();          if (_host != null)            invocation.setHost(_host.toString());                    invocation.setPort(getServerPort());          InvocationDecoder decoder = _server.getInvocationDecoder();	  decoder.splitQueryAndUnescape(invocation,					_uri.getBuffer(),					_uri.getLength());          invocation = _server.buildInvocation(_invocationKey.clone(),					       invocation);        }	invocation = invocation.getRequestInvocation(this);	setInvocation(invocation);              invocation.service(this, _response);      } catch (ClientDisconnectException e) {        throw e;      } catch (Throwable e) {	log.log(Level.FINER, e.toString(), e);	        try {          _errorManager.sendServletError(e, this, _response);        } catch (ClientDisconnectException e1) {          throw e1;        } catch (Exception e1) {          log.log(Level.FINE, e1.toString(), e1);        }	return false;      }    } finally {      if (! hasRequest)	_response.setHeaderWritten(true);            try {	finish();	_response.finish();      } catch (ClientDisconnectException e) {        throw e;      } catch (Exception e) {	killKeepalive();        log.log(Level.FINE, dbgId() + e, e);      }      try {	_writeStream.setDisableClose(false);	_writeStream.close();      } catch (ClientDisconnectException e) {	killKeepalive();        log.log(Level.FINE, dbgId() + e, e);        throw e;      } catch (Exception e) {	killKeepalive();        log.log(Level.FINE, dbgId() + e, e);      }      try {	_readStream.setDisableClose(false);	_readStream.close();      } catch (Exception e) {	killKeepalive();        log.log(Level.FINE, dbgId() + e, e);      }    }    boolean allowKeepalive = isKeepalive();        if (log.isLoggable(Level.FINE)) {      if (allowKeepalive)	log.fine(dbgId() + "complete request - keepalive");      else	log.fine(dbgId() + "complete request");    }    return allowKeepalive;  }  /**   * Initialize the read stream from the raw stream.   */  protected boolean initStream(ReadStream readStream,                               ReadStream rawStream)    throws IOException  {    readStream.init(_filter, null);    return true;  }  private void getClientCertificate()  {    String cipher = getHeader("SSL_CIPHER");    if (cipher == null)      cipher = getHeader("HTTPS_CIPHER");    if (cipher != null)      setAttribute("javax.servlet.request.cipher_suite", cipher);        String keySize = getHeader("SSL_CIPHER_USEKEYSIZE");    if (keySize == null)      keySize = getHeader("SSL_SECRETKEYSIZE");    if (keySize != null)      setAttribute("javax.servlet.request.key_size", keySize);        if (_clientCert.size() == 0)      return;        try {      CertificateFactory cf = CertificateFactory.getInstance("X.509");      InputStream is = _clientCert.createInputStream();      Object cert = cf.generateCertificate(is);      is.close();      setAttribute("javax.servlet.request.X509Certificate", cert);      setAttribute(com.caucho.server.security.AbstractAuthenticator.LOGIN_NAME,                   ((X509Certificate) cert).getSubjectDN());    } catch (Throwable e) {      log.log(Level.FINE, e.toString(), e);    }  }  /**   * Returns true for the top-level request, but false for any include()   * or forward()   */  @Override  public boolean isTop()  {    return true;  }    protected boolean checkLogin()  {    return true;  }  /**   * Clears variables at the start of a new request.   */  @Override  protected void start()    throws IOException  {    super.start();    _method.clear();    _methodString = null;    _protocol.clear();    _version = 0;    _uri.clear();    _host.clear();    _port = 0;    _headerSize = 0;    _remoteHost.clear();    _remoteAddr.clear();    _serverName.clear();    _serverPort.clear();    _remotePort.clear();    _clientCert.clear();    _pendingData = 0;    _isSecure = _conn.isSecure();  }    /**   * Fills request parameters from the stream.   */  private boolean scanHeaders()    throws IOException  {    boolean hasURI = false;    CharBuffer cb = _cb;    boolean isLoggable = log.isLoggable(Level.FINE);    ReadStream is = _rawRead;

⌨️ 快捷键说明

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