abstracthttpresponse.java
来自「RESIN 3.2 最新源码」· Java 代码 · 共 2,408 行 · 第 1/4 页
JAVA
2,408 行
/* * 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.connection;import com.caucho.server.cache.AbstractCacheEntry;import com.caucho.server.cache.AbstractCacheFilterChain;import com.caucho.server.dispatch.BadRequestException;import com.caucho.server.dispatch.InvocationDecoder;import com.caucho.server.session.CookieImpl;import com.caucho.server.session.SessionImpl;import com.caucho.server.session.SessionManager;import com.caucho.server.util.CauchoSystem;import com.caucho.server.webapp.ErrorPageManager;import com.caucho.server.webapp.WebApp;import com.caucho.util.Alarm;import com.caucho.util.CaseInsensitiveIntMap;import com.caucho.util.CharBuffer;import com.caucho.util.HTTPUtil;import com.caucho.util.L10N;import com.caucho.util.QDate;import com.caucho.vfs.ClientDisconnectException;import com.caucho.vfs.FlushBuffer;import com.caucho.vfs.TempBuffer;import com.caucho.vfs.WriteStream;import com.caucho.xml.XmlChar;import javax.servlet.ServletOutputStream;import javax.servlet.ServletResponse;import javax.servlet.http.Cookie;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import java.io.IOException;import java.io.OutputStream;import java.io.PrintWriter;import java.io.Writer;import java.util.ArrayList;import java.util.HashMap;import java.util.Locale;import java.util.logging.Level;import java.util.logging.Logger;/** * Encapsulates the servlet response, controlling response headers and the * response stream. */abstract public class AbstractHttpResponse implements CauchoResponse { static final protected Logger log = Logger.getLogger(AbstractHttpResponse.class.getName()); static final L10N L = new L10N(AbstractHttpResponse.class); static final HashMap<String,String> _errors; protected static final CaseInsensitiveIntMap _headerCodes; protected static final int HEADER_CACHE_CONTROL = 1; protected static final int HEADER_CONTENT_TYPE = HEADER_CACHE_CONTROL + 1; protected static final int HEADER_CONTENT_LENGTH = HEADER_CONTENT_TYPE + 1; protected static final int HEADER_DATE = HEADER_CONTENT_LENGTH + 1; protected static final int HEADER_SERVER = HEADER_DATE + 1; protected static final int HEADER_CONNECTION = HEADER_SERVER + 1; protected CauchoRequest _originalRequest; protected CauchoRequest _request; protected int _statusCode; protected String _statusMessage; protected String _contentType; protected String _contentPrefix; protected String _charEncoding; protected boolean _hasCharEncoding; protected final ArrayList<String> _headerKeys = new ArrayList<String>(); protected final ArrayList<String> _headerValues = new ArrayList<String>(); protected final ArrayList<String> _footerKeys = new ArrayList<String>(); protected final ArrayList<String> _footerValues = new ArrayList<String>(); protected final ArrayList<Cookie> _cookiesOut = new ArrayList<Cookie>(); private final AbstractResponseStream _originalResponseStream; private final ServletOutputStreamImpl _responseOutputStream; private final ResponseWriter _responsePrintWriter; private AbstractResponseStream _responseStream; // the raw output stream. protected WriteStream _rawWrite; // any stream that needs flusing before getting the writer. private FlushBuffer _flushBuffer; private boolean _isHeaderWritten; private boolean _isChunked; protected final QDate _calendar = new QDate(false); protected final CharBuffer _cb = new CharBuffer(); protected final char [] _headerBuffer = new char[256]; private String _sessionId; private boolean _hasSessionCookie; private Locale _locale; protected boolean _disableHeaders; protected boolean _disableCaching; protected long _contentLength; protected boolean _isClosed; protected boolean _hasSentLog; protected boolean _hasWriter; protected boolean _hasOutputStream; private AbstractCacheFilterChain _cacheInvocation; // the cache entry for a match/if-modified-since private AbstractCacheEntry _matchCacheEntry; // the new cache for a request getting filled private AbstractCacheEntry _newCacheEntry; private OutputStream _cacheStream; private Writer _cacheWriter; protected boolean _isNoCache; private boolean _allowCache; private boolean _isPrivateCache; private boolean _hasCacheControl; protected boolean _isTopCache; protected boolean _forbidForward; protected boolean _hasError; private boolean _isCacheHit; private final TempBuffer _tempBuffer = TempBuffer.allocate(); protected AbstractHttpResponse() { _originalResponseStream = createResponseStream(); _responseOutputStream = new ServletOutputStreamImpl(); _responsePrintWriter = new ResponseWriter(); _responseOutputStream.init(_originalResponseStream); _responsePrintWriter.init(_originalResponseStream); } protected AbstractResponseStream createResponseStream() { return new ResponseStream(this); } protected AbstractHttpResponse(CauchoRequest request) { this(); _request = request; _originalRequest = request; _responseOutputStream.init(_originalResponseStream); _responsePrintWriter.init(_originalResponseStream); } /** * If set true, client disconnect exceptions are no propagated to the * server code. */ public boolean isIgnoreClientDisconnect() { if (! (_originalRequest instanceof AbstractHttpRequest)) return true; else { return ((AbstractHttpRequest) _originalRequest).isIgnoreClientDisconnect(); } } /** * Return true for the top request. */ public boolean isTop() { if (! (_request instanceof AbstractHttpRequest)) return false; else { return ((AbstractHttpRequest) _request).isTop(); } } /** * Returns the next response. */ public ServletResponse getResponse() { return null; } /** * Initialize the response for a new request. * * @param stream the underlying output stream. */ public void init(WriteStream stream) { _rawWrite = stream; if (_originalResponseStream instanceof ResponseStream) ((ResponseStream) _originalResponseStream).init(_rawWrite); } /** * Initialize the response for a new request. * * @param request the matching request. */ public void init(CauchoRequest request) { _request = request; _originalRequest = request; } /** * Returns the corresponding request. */ public CauchoRequest getRequest() { return _request; } /** * Sets the corresponding request. */ public void setRequest(CauchoRequest req) { _request = req; if (_originalRequest == null) _originalRequest = req; } /** * Returns the corresponding original */ public CauchoRequest getOriginalRequest() { return _originalRequest; } /** * Closes the request. */ public void close() throws IOException { finish(true); // getStream().flush(); } /** * Returns true for closed requests. */ public boolean isClosed() { return _isClosed; } /** * Initializes the Response at the beginning of the request. */ public void start() throws IOException { _statusCode = 200; _statusMessage = "OK"; _headerKeys.clear(); _headerValues.clear(); _footerKeys.clear(); _footerValues.clear(); _hasSessionCookie = false; _cookiesOut.clear(); _isHeaderWritten = false; _isChunked = false; _charEncoding = null; _hasCharEncoding = false; _contentType = null; _contentPrefix = null; _locale = null; if (_originalResponseStream instanceof ResponseStream) ((ResponseStream) _originalResponseStream).init(_rawWrite); _flushBuffer = null; _contentLength = -1; _disableHeaders = false; _disableCaching = false; _isClosed = false; _hasSentLog = false; _hasWriter = false; _hasOutputStream = false; _cacheInvocation = null; _matchCacheEntry = null; _newCacheEntry = null; _cacheStream = null; _cacheWriter = null; _isPrivateCache = false; _hasCacheControl = false; _allowCache = true; _isNoCache = false; _isTopCache = false; _isCacheHit = false; _sessionId = null; _forbidForward = false; _originalResponseStream.start(); _responseStream = _originalResponseStream; _responseOutputStream.init(_responseStream); _responsePrintWriter.init(_responseStream); } /** * For a HEAD request, the response stream should write no data. */ void setHead() { _originalResponseStream.setHead(); } /** * For a HEAD request, the response stream should write no data. */ protected final boolean isHead() { return _originalResponseStream.isHead(); } /** * Set true for a cache hit. */ public void setCacheHit(boolean isHit) { _isCacheHit = isHit; } /** * Set true for a cache hit. */ public boolean isCacheHit() { return _isCacheHit; } /** * When set to true, RequestDispatcher.forward() is disallowed on * this stream. */ public void setForbidForward(boolean forbid) { _forbidForward = forbid; } /** * Returns true if RequestDispatcher.forward() is disallowed on * this stream. */ public boolean getForbidForward() { return _forbidForward; } /** * Set to true while processing an error. */ public void setHasError(boolean hasError) { _hasError = hasError; } /** * Returns true if we're processing an error. */ public boolean hasError() { return _hasError; } /** * Sets the cache entry so we can use it if the servlet returns * not_modified response. * * @param entry the saved cache entry */ public void setMatchCacheEntry(AbstractCacheEntry entry) { _matchCacheEntry = entry; } /** * Sets the cache invocation to indicate that the response might be * cacheable. */ public void setCacheInvocation(AbstractCacheFilterChain cacheInvocation) { AbstractCacheFilterChain oldCache = _cacheInvocation; _cacheInvocation = null; AbstractCacheEntry oldEntry = _newCacheEntry; _newCacheEntry = null; if (oldEntry != null) oldCache.killCaching(oldEntry); _cacheInvocation = cacheInvocation; } public void setTopCache(boolean isTopCache) { _isTopCache = isTopCache; } public void setStatus(int code) { setStatus(code, null); } public void setStatus(int code, String message) { if (code < 0) code = 500; if (message != null) { } else if (code == SC_OK) message = "OK"; else if (code == SC_NOT_MODIFIED) message = "Not Modified"; else if (message == null) { message = (String) _errors.get(String.valueOf(code)); if (message == null) message = L.l("Internal Server Error"); } // server/2h0g if (code != SC_OK && code != SC_NOT_MODIFIED) killCache(); _statusCode = code; _statusMessage = message; } public int getStatusCode() { return _statusCode; } public void sendError(int code) throws IOException { sendError(code, null); } /** * Sends an HTTP error to the browser. * * @param code the HTTP error code * @param value a string message */ public void sendError(int code, String value) throws IOException { if (code == SC_NOT_MODIFIED && _matchCacheEntry != null) { setStatus(code, value); if (handleNotModified(_isTopCache)) return; } if (isCommitted()) throw new IllegalStateException(L.l("sendError() forbidden after buffer has been committed.")); //_currentWriter = null; //setStream(_originalStream); resetBuffer(); if (code != SC_NOT_MODIFIED) killCache(); /* XXX: if we've already got an error, won't this just mask it? if (responseStream.isCommitted()) throw new IllegalStateException("response can't sendError() after commit"); */ WebApp app = getRequest().getWebApp(); ErrorPageManager errorManager = null; if (app != null) errorManager = app.getErrorPageManager(); setStatus(code, value); try { if (code == SC_NOT_MODIFIED || code == SC_NO_CONTENT) { finish(); return; } else if (errorManager != null) { errorManager.sendError(getOriginalRequest(), this, code, _statusMessage); // _request.killKeepalive(); // close, but don't force a flush // XXX: finish(false); finish(); return; } setContentType("text/html"); ServletOutputStream s = getOutputStream(); s.println("<html>"); if (! isCommitted()) { s.print("<head><title>"); s.print(code); s.print(" "); s.print(_statusMessage); s.println("</title></head>"); } s.println("<body>"); s.print("<h1>"); s.print(code); s.print(" "); s.print(_statusMessage); s.println("</h1>"); if (code == HttpServletResponse.SC_NOT_FOUND) { s.println(L.l("{0} was not found on this server.", HTTPUtil.encodeString(getRequest().getPageURI()))); } else if (code == HttpServletResponse.SC_SERVICE_UNAVAILABLE) { s.println(L.l("The server is temporarily unavailable due to maintenance downtime or excessive load.")); } String version = null; if (app == null) { } else if (app.getServer() != null && app.getServer().getServerHeader() != null) { version = app.getServer().getServerHeader(); } else if (CauchoSystem.isTesting()) { } else version = com.caucho.Version.FULL_VERSION; if (version != null) { s.println("<p /><hr />"); s.println("<small>"); s.println(version); s.println("</small>"); } s.println("</body></html>"); } catch (Exception e) { log.log(Level.FINE, e.toString(), e); }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?