httpresponse.java
来自「RESIN 3.2 最新源码」· Java 代码 · 共 473 行
JAVA
473 行
/* * 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.server.cluster.Server;import com.caucho.server.connection.*;import com.caucho.server.port.*;import com.caucho.server.webapp.WebApp;import com.caucho.util.Alarm;import com.caucho.util.CharBuffer;import com.caucho.vfs.WriteStream;import javax.servlet.http.Cookie;import java.io.IOException;import java.util.logging.Level;public class HttpResponse extends AbstractHttpResponse{ static final byte []_http10ok = "HTTP/1.0 200 OK".getBytes(); static final byte []_http11ok = "HTTP/1.1 200 OK".getBytes(); static final byte []_contentLengthBytes = "\r\nContent-Length: ".getBytes(); static final byte []_contentTypeBytes = "\r\nContent-Type: ".getBytes(); static final byte []_textHtmlBytes = "\r\nContent-Type: text/html".getBytes(); static final byte []_charsetBytes = "; charset=".getBytes(); static final byte []_textHtmlLatin1Bytes = "\r\nContent-Type: text/html; charset=iso-8859-1".getBytes(); static final byte []_connectionCloseBytes = "\r\nConnection: close".getBytes(); final byte []_resinServerBytes; static final char []_connectionCb = "Connection".toCharArray(); static final CharBuffer _closeCb = new CharBuffer("Close"); private final HttpRequest _request; private final byte []_dateBuffer = new byte[256]; private int _dateBufferLength; private final CharBuffer _dateCharBuffer = new CharBuffer(); private long _lastDate; /** * Creates a new HTTP-protocol response. * * @param request the matching request object. */ HttpResponse(HttpRequest request) { super(request); _request = request; Server server = (Server) request.getDispatchServer(); _resinServerBytes = ("\r\nServer: " + server.getServerHeader()).getBytes(); } /** * Switch to raw socket mode. */ public void switchToRaw() throws IOException { clearBuffer(); setStatus(101); finish(); // don't need to flush since it'll close anyway } /** * Switch to raw socket mode. */ public WriteStream getRawOutput() throws IOException { return _rawWrite; } /** * Upgrade protocol */ @Override public TcpDuplexController upgradeProtocol(TcpDuplexHandler handler) { TcpDuplexController controller = new TcpDuplexController((TcpServerRequest) getOriginalRequest(), handler); setStatus(101); setContentLength(0); if (log.isLoggable(Level.FINE)) log.fine(this + " upgrade HTTP to " + handler); return controller; } /** * Return true for the top request. */ @Override public boolean isTop() { if (! (_request instanceof AbstractHttpRequest)) return false; else { return ((AbstractHttpRequest) _request).isTop(); } } /** * Writes the 100 continue response. */ protected void writeContinueInt(WriteStream os) throws IOException { os.print("HTTP/1.1 100 Continue"); if (! containsHeader("Server")) os.write(_resinServerBytes, 0, _resinServerBytes.length); os.print("\r\nContent-Length: 0"); long now = Alarm.getCurrentTime(); if (_lastDate + 1000 < now) { fillDate(now); } os.write(_dateBuffer, 0, _dateBufferLength); os.flush(); } /** * Implementation to write the HTTP headers. If the length is positive, * it's a small request where the buffer contains the entire request, * so the length is already known. * * @param os the output stream to write the headers to. * @param length if non-negative, the length of the entire request. * * @return true if the data in the request should use chunked encoding. */ protected boolean writeHeadersInt(WriteStream os, int length, boolean isHead) throws IOException { boolean isChunked = false; int version = _request.getVersion(); boolean debug = log.isLoggable(Level.FINE); if (version < HttpRequest.HTTP_1_0) { _request.killKeepalive(); return false; } String contentType = _contentType; int statusCode = _statusCode; if (statusCode == 200) { if (version < HttpRequest.HTTP_1_1) os.write(_http10ok, 0, _http10ok.length); else os.write(_http11ok, 0, _http11ok.length); } else { if (version < HttpRequest.HTTP_1_1) os.print("HTTP/1.0 "); else os.print("HTTP/1.1 "); os.write((statusCode / 100) % 10 + '0'); os.write((statusCode / 10) % 10 + '0'); os.write(statusCode % 10 + '0'); os.write(' '); os.print(_statusMessage); } if (debug) { log.fine(_request.dbgId() + "HTTP/1.1 " + _statusCode + " " + _statusMessage); } if (! containsHeader("Server")) os.write(_resinServerBytes, 0, _resinServerBytes.length); if (statusCode >= 400) { removeHeader("ETag"); removeHeader("Last-Modified"); } else if (statusCode == SC_NOT_MODIFIED || statusCode == SC_NO_CONTENT) { // php/1b0k contentType = null; } else if (_isNoCache) { // server/1b15 removeHeader("ETag"); removeHeader("Last-Modified"); // even in case of 302, this may be needed for filters which // automatically set cache headers setHeader("Expires", "Thu, 01 Dec 1994 16:00:00 GMT"); os.print("\r\nCache-Control: no-cache"); if (debug) { log.fine(_request.dbgId() + "" + "Expires: Thu, 01 Dec 1994 16:00:00 GMT"); } } else if (! isPrivateCache()) { } else if (HttpRequest.HTTP_1_1 <= version) { // technically, this could be private="Set-Cookie,Set-Cookie2" // but caches don't recognize it, so there's no real extra value os.print("\r\nCache-Control: private"); if (debug) log.fine(_request.dbgId() + "Cache-Control: private"); } else if (! containsHeader("Cache-Control")) { setHeader("Expires", "Thu, 01 Dec 1994 16:00:00 GMT"); os.print("\r\nCache-Control: no-cache"); if (debug) { log.fine(_request.dbgId() + "" + "Expires: Thu, 01 Dec 1994 16:00:00 GMT"); } } int size = _headerKeys.size(); for (int i = 0; i < size; i++) { String key = (String) _headerKeys.get(i); os.write('\r'); os.write('\n'); os.print(key); os.write(':'); os.write(' '); os.print((String) _headerValues.get(i)); if (debug) { log.fine(_request.dbgId() + "" + key + ": " + _headerValues.get(i)); } } long now = Alarm.getCurrentTime(); size = _cookiesOut.size(); for (int i = 0; i < _cookiesOut.size(); i++) { Cookie cookie = _cookiesOut.get(i); int cookieVersion = cookie.getVersion(); CharBuffer cb = _cb; // XXX: fillCookie(cb, cookie, now, cookieVersion, false); os.print("\r\nSet-Cookie: "); os.print(cb.getBuffer(), 0, cb.getLength()); if (cookieVersion > 0) { fillCookie(cb, cookie, now, cookieVersion, true); os.print("\r\nSet-Cookie2: "); os.print(cb.getBuffer(), 0, cb.getLength()); } if (debug) log.fine(_request.dbgId() + "Set-Cookie: " + cb); } if (contentType == null) { } else if (! contentType.equals("text/html")) { os.write(_contentTypeBytes, 0, _contentTypeBytes.length); os.print(contentType); if (_charEncoding != null) { os.write(_charsetBytes, 0, _charsetBytes.length); os.print(_charEncoding); if (debug) { log.fine(_request.dbgId() + "Content-Type: " + contentType + "; charset=" + _charEncoding); } } else { WebApp webApp = _request.getWebApp(); String charEncoding = (webApp != null ? webApp.getCharacterEncoding() : null); if (charEncoding != null) { os.write(_charsetBytes, 0, _charsetBytes.length); os.print(charEncoding); if (debug) { log.fine(_request.dbgId() + "Content-Type: " + contentType + "; charset=" + _charEncoding); } } else { if (debug) { log.fine(_request.dbgId() + "Content-Type: " + contentType); } } } } else if (_charEncoding != null) { os.write(_textHtmlBytes, 0, _textHtmlBytes.length); os.write(_charsetBytes, 0, _charsetBytes.length); os.print(_charEncoding); if (debug) { log.fine(_request.dbgId() + "Content-Type: text/html; charset=" + _charEncoding); } } else { WebApp webApp = _request.getWebApp(); String charEncoding = (webApp != null ? webApp.getCharacterEncoding() : null); os.write(_textHtmlBytes, 0, _textHtmlBytes.length); if (charEncoding != null) { os.write(_charsetBytes, 0, _charsetBytes.length); os.print(charEncoding); if (debug) { log.fine(_request.dbgId() + "Content-Type: text/html; charset=" + charEncoding); } } else { if (debug) { log.fine(_request.dbgId() + "Content-Type: text/html"); } } } boolean hasContentLength = false; if (_contentLength >= 0) { os.write(_contentLengthBytes, 0, _contentLengthBytes.length); os.print(_contentLength); hasContentLength = true; if (debug) log.fine(_request.dbgId() + "Content-Length: " + _contentLength); } else if (statusCode == SC_NOT_MODIFIED || statusCode == SC_NO_CONTENT) { hasContentLength = true; os.write(_contentLengthBytes, 0, _contentLengthBytes.length); os.print(0); if (debug) log.fine(_request.dbgId() + "Content-Length: 0"); } else if (length >= 0) { os.write(_contentLengthBytes, 0, _contentLengthBytes.length); os.print(length); hasContentLength = true; if (debug) log.fine(_request.dbgId() + "Content-Length: " + length); } if (version < HttpRequest.HTTP_1_1) { _request.killKeepalive(); } else { /* XXX: the request processing already processed this header CharSegment conn = _request.getHeaderBuffer(_connectionCb, _connectionCb.length); if (conn != null && conn.equalsIgnoreCase(_closeCb)) { _request.killKeepalive(); } else */ if (! _request.allowKeepalive()) { os.write(_connectionCloseBytes, 0, _connectionCloseBytes.length); _request.killKeepalive(); if (debug) log.fine(_request.dbgId() + "Connection: close"); } } if (HttpRequest.HTTP_1_1 <= version && ! hasContentLength && ! isHead) { os.print("\r\nTransfer-Encoding: chunked"); isChunked = true; if (debug) log.fine(_request.dbgId() + "Transfer-Encoding: chunked"); } if (_lastDate / 1000 != now / 1000) { fillDate(now); } if (isChunked) os.write(_dateBuffer, 0, _dateBufferLength - 2); else os.write(_dateBuffer, 0, _dateBufferLength); return isChunked; } private void fillDate(long now) { if (_lastDate / 60000 == now / 60000) { _lastDate = now; int sec = (int) (now / 1000 % 60); int s2 = '0' + (sec / 10); int s1 = '0' + (sec % 10); _dateBuffer[31] = (byte) s2; _dateBuffer[32] = (byte) s1; return; } _lastDate = now; _calendar.setGMTTime(now); _dateCharBuffer.clear(); _dateCharBuffer.append("\r\nDate: "); _calendar.printDate(_dateCharBuffer); char []cb = _dateCharBuffer.getBuffer(); int len = _dateCharBuffer.getLength(); for (int i = len - 1; i >= 0; i--) _dateBuffer[i] = (byte) cb[i]; _dateBuffer[len] = (byte) '\r'; _dateBuffer[len + 1] = (byte) '\n'; _dateBuffer[len + 2] = (byte) '\r'; _dateBuffer[len + 3] = (byte) '\n'; _dateBufferLength = len + 4; } public String toString() { return "HttpResponse" + _request.dbgId(); }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?