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 + -
显示快捷键?