httprequest.java

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

JAVA
1,500
字号
/* * 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.http;import com.caucho.log.Log;import com.caucho.server.cluster.Server;import com.caucho.server.connection.AbstractHttpRequest;import com.caucho.server.connection.Connection;import com.caucho.server.connection.ConnectionController;import com.caucho.server.dispatch.BadRequestException;import com.caucho.server.dispatch.DispatchServer;import com.caucho.server.dispatch.Invocation;import com.caucho.server.dispatch.InvocationDecoder;import com.caucho.server.port.ServerRequest;import com.caucho.server.port.TcpServerRequest;import com.caucho.server.port.TcpConnection;import com.caucho.server.cluster.*;import com.caucho.server.webapp.*;import com.caucho.util.CharBuffer;import com.caucho.util.CharSegment;import com.caucho.vfs.ClientDisconnectException;import com.caucho.vfs.QSocket;import com.caucho.vfs.ReadStream;import com.caucho.vfs.TempBuffer;import java.io.IOException;import java.io.InterruptedIOException;import java.security.cert.X509Certificate;import java.util.ArrayList;import java.util.Collections;import java.util.Enumeration;import java.util.logging.Level;import java.util.logging.Logger;/** * Handles a new request from an HTTP connection. */public class HttpRequest extends AbstractHttpRequest  implements TcpServerRequest{  static final Logger log = Logger.getLogger(HttpRequest.class.getName());  static final int HTTP_0_9 = 0x0009;  static final int HTTP_1_0 = 0x0100;  static final int HTTP_1_1 = 0x0101;  static final CharBuffer _getCb = new CharBuffer("GET");  static final CharBuffer _headCb = new CharBuffer("HEAD");  static final CharBuffer _postCb = new CharBuffer("POST");  static final char []_hostCb = "Host".toCharArray();  static final char []_userAgentCb = "User-Agent".toCharArray();  static final CharBuffer _http11Cb = new CharBuffer("HTTP/1.1");  static final CharBuffer _http10Cb = new CharBuffer("HTTP/1.0");  private String _scheme;           // "http:" or "https:"  private boolean _isSecure;  private CharBuffer _method;       // "GET"  private String _methodString;  private CharBuffer _uriHost;      // www.caucho.com:8080  private CharSequence _host;  private CharBuffer _hostBuffer = new CharBuffer();  private final byte []_uri;              // "/path/test.jsp/Junk?query=7"  private int _uriLength;  private int _urlLengthMax = 8192;  private CharBuffer _protocol;     // "HTTP/1.0"  private int _version;  private final InvocationKey _invocationKey = new InvocationKey();  private final char []_headerBuffer;  private CharSegment []_headerKeys;  private CharSegment []_headerValues;  private int _headerCapacity = 256;  private int _headerSize;  private ChunkedInputStream _chunkedInputStream = new ChunkedInputStream();  private ContentLengthStream _contentLengthStream = new ContentLengthStream();  private ErrorPageManager _errorManager = new ErrorPageManager(null);  private boolean _initAttributes;  /**   * Creates a new HttpRequest.  New connections reuse the request.   *   * @param server the owning server.   */  public HttpRequest(DispatchServer server, Connection conn)  {    super(server, conn);    _response = new HttpResponse(this);    _response.init(conn.getWriteStream());    if (server instanceof Server)      _urlLengthMax = ((Server) server).getUrlLengthMax();    // XXX: response.setIgnoreClientDisconnect(server.getIgnoreClientDisconnect());    _uri = new byte[_urlLengthMax];    _method = new CharBuffer();    _uriHost = new CharBuffer();    _protocol = new CharBuffer();    if (TempBuffer.isSmallmem()) {      _headerBuffer = new char[4 * 1024];      _headerCapacity = 64;    }    else {      _headerBuffer = new char[16 * 1024];      _headerCapacity = 256;    }        _headerSize = 0;    _headerKeys = new CharSegment[_headerCapacity];    _headerValues = new CharSegment[_headerCapacity];    for (int i = 0; i < _headerCapacity; i++) {      _headerKeys[i] = new CharSegment();      _headerValues[i] = new CharSegment();    }  }  /**   * Return true if the request waits for a read before beginning.   */  public final boolean isWaitForRead()  {    return true;  }    /**   * Handles a new HTTP request.   *   * <p>Note: ClientDisconnectException must be rethrown to   * the caller.   *   * @return true if the connection should stay open (keepalive)   */  public boolean handleRequest()    throws IOException  {    boolean hasRequest = false;    try {      start();      _response.start();      try {	try {	  if (! readRequest(_rawRead)) {	    if (log.isLoggable(Level.FINE))	      log.fine(dbgId() + "read timeout");	    return false;	  }	  setStartTime();	  hasRequest = true;	  _isSecure = _conn.isSecure() || _conn.getLocalPort() == 443;	  if (_protocol.length() == 0)	    _protocol.append("HTTP/0.9");	  if (log.isLoggable(Level.FINE)) {	    log.fine(dbgId() + _method + " " +		     new String(_uri, 0, _uriLength) + " " + _protocol);	    log.fine(dbgId() + "Remote-IP: " + _conn.getRemoteHost() + ":" + _conn.getRemotePort());	  }	  parseHeaders(_rawRead);	  if (getVersion() >= HTTP_1_1 && isForce10()) {	    _protocol.clear();	    _protocol.append("HTTP/1.0");	    _version = HTTP_1_0;	  }	} catch (ClientDisconnectException e) {	  throw e;	} catch (Throwable e) {	  log.log(Level.FINER, e.toString(), e);	  throw new BadRequestException(String.valueOf(e));	}	CharSequence host = getHost();	if (host == null && getVersion() >= HTTP_1_1)	  throw new BadRequestException("HTTP/1.1 requires host");	String ipHost = _conn.getVirtualHost();	if (ipHost != null)	  host = ipHost;	_invocationKey.init(_isSecure,			    host, _conn.getLocalPort(),			    _uri, _uriLength);	Invocation invocation;	invocation = _server.getInvocation(_invocationKey);	if (invocation == null) {	  invocation = _server.createInvocation();	  invocation.setSecure(_isSecure);	  if (host != null) {	    String hostName = host.toString().toLowerCase();	    invocation.setHost(hostName);	    invocation.setPort(_conn.getLocalPort());	    // Default host name if the host doesn't have a canonical	    // name	    int p = hostName.indexOf(':');	    if (p > 0)	      invocation.setHostName(hostName.substring(0, p));	    else	      invocation.setHostName(hostName);	  }	  InvocationDecoder decoder = _server.getInvocationDecoder();	  decoder.splitQueryAndUnescape(invocation, _uri, _uriLength);	  if (_server.isModified()) {	    _server.logModified(log);	    _invocation = invocation;	    if (_server instanceof Server)	      _invocation.setWebApp(((Server) _server).getDefaultWebApp());	    restartServer();	    return false;	  }	  invocation = _server.buildInvocation(_invocationKey.clone(),					       invocation);	}	invocation = invocation.getRequestInvocation(this);	setInvocation(invocation);	invocation.service(this, _response);      } finally {	finish();      }    } catch (ClientDisconnectException e) {      _response.killCache();      throw e;    } catch (Throwable e) {      log.log(Level.FINE, e.toString(), e);      _response.killCache();      killKeepalive();      try {        _errorManager.sendServletError(e, this, _response);      } catch (ClientDisconnectException e1) {        throw e1;      } catch (Throwable e1) {        log.log(Level.FINE, e1.toString(), e1);      }      if (_server instanceof Server) {	WebApp webApp = ((Server) _server).getDefaultWebApp();	if (webApp != null)	  webApp.accessLog(this, _response);      }      return false;    } finally {      if (hasRequest)        _response.finish();      else	super.finish();    }    if (log.isLoggable(Level.FINE)) {      log.fine(dbgId() +               (isKeepalive() ? "keepalive" : "no-keepalive"));    }    return isKeepalive();  }    /**   * Handles a comet-style resume.   *   * @return true if the connection should stay open (keepalive)   */  @Override  public boolean handleResume()    throws IOException  {    boolean isResume = false;    ConnectionController controller = null;        try {      try {	setStartTime();		Connection conn = getConnection();	controller = conn.getController();	if (controller == null) {	  killKeepalive();	}	else if (_invocation.doResume(this, _response)) {	  controller = null;	  isResume = true;	}	else	  killKeepalive();      } finally {	finish();	if (controller != null)	  controller.close();      }    } catch (ClientDisconnectException e) {      _response.killCache();      isResume = false;      throw e;    } catch (Throwable e) {      log.log(Level.FINE, e.toString(), e);      isResume = false;      _response.killCache();      killKeepalive();      return false;    } finally {      _response.finish();    }    if (log.isLoggable(Level.FINE)) {      log.fine(dbgId() +               (isKeepalive() ? "keepalive" : "no-keepalive"));    }    return isResume && controller == null;  }  /**   * There are some bogus clients that can't deal with HTTP/1.1 even   * though they advertise it.   */  private boolean isForce10()  {    return false;  }  /**   * Returns true for the top-level request, but false for any include()   * or forward()   */  public boolean isTop()  {    return true;  }  protected boolean checkLogin()  {    return true;  }  /**   * Clear the request variables in preparation for a new request.   *   * @param s the read stream for the request   */  protected void start()    throws IOException  {    super.start();    _method.clear();    _methodString = null;    _protocol.clear();    _uriLength = 0;    _uriHost.clear();    _host = null;    _headerSize = 0;    _initAttributes = false;  }  /**   * Returns true for a secure connection.   */  public boolean isSecure()  {    return _isSecure;  }  /**   * Read the first line of a request:   *   * GET [http://www.caucho.com[:80]]/path [HTTP/1.x]   *   * @return true if the request is valid   */  private boolean readRequest(ReadStream s)    throws IOException  {    int i = 0;    byte []readBuffer = s.getBuffer();    int readOffset = s.getOffset();    int readLength = s.getLength();    int ch;    if (readOffset >= readLength) {      try {        if ((readLength = s.fillBuffer()) < 0)          return false;      } catch (InterruptedIOException e) {        log.fine(dbgId() + "keepalive timeout");        return false;      }      readOffset = 0;    }    ch = readBuffer[readOffset++];    // conn.setAccessTime(getDate());    // skip leading whitespace    while (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') {      if (readOffset >= readLength) {        if ((readLength = s.fillBuffer()) < 0)          return false;        readOffset = 0;      }      ch = readBuffer[readOffset++];    }    char []buffer = _method.getBuffer();    int length = buffer.length;    int offset = 0;    // scan method    while (true) {      if (length <= offset) {      }      else if (ch >= 'a' && ch <= 'z')	buffer[offset++] = ((char) (ch + 'A' - 'a'));      else if (ch > ' ')	buffer[offset++] = (char) ch;      else	break;      if (readLength <= readOffset) {        if ((readLength = s.fillBuffer()) < 0)          return false;        readOffset = 0;      }      ch = readBuffer[readOffset++];    }

⌨️ 快捷键说明

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