responsestream.java

来自「RESIN 3.2 最新源码」· Java 代码 · 共 811 行 · 第 1/2 页

JAVA
811
字号
/* * 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.log.Log;import com.caucho.server.webapp.WebApp;import com.caucho.util.L10N;import com.caucho.vfs.ClientDisconnectException;import com.caucho.vfs.WriteStream;import javax.servlet.ServletContext;import java.io.IOException;import java.io.OutputStream;import java.util.*;import java.util.logging.Level;import java.util.logging.Logger;class ResponseStream extends ToByteResponseStream {  static final Logger log = Logger.getLogger(ResponseStream.class.getName());    static final L10N L = new L10N(ResponseStream.class);  private static final int _tailChunkedLength = 7;  private static final byte []_tailChunked =    new byte[] {'\r', '\n', '0', '\r', '\n', '\r', '\n'};    private final AbstractHttpResponse _response;    private WriteStream _next;    private OutputStream _cacheStream;  private long _cacheMaxLength;  // used for the direct copy and caching  private int _bufferStartOffset;    private boolean _chunkedEncoding;    private int _bufferSize;  private boolean _disableAutoFlush;    // bytes actually written  private int _contentLength;  // True for the first chunk  private boolean _isFirst;  private boolean _isDisconnected;  private boolean _isCommitted;  private boolean _allowFlush = true;  private boolean _isHead = false;  private boolean _isClosed = false;    private final byte []_buffer = new byte[16];  ResponseStream(AbstractHttpResponse response)  {    _response = response;  }  public void init(WriteStream next)  {    _next = next;  }    /**   * initializes the Response stream at the beginning of a request.   */  public void start()  {    super.start();        _chunkedEncoding = false;    _contentLength = 0;    _allowFlush = true;    _disableAutoFlush = false;    _isClosed = false;    _isHead = false;    _cacheStream = null;    _isDisconnected = false;    _isCommitted = false;    _isFirst = true;    _bufferStartOffset = 0;  }  /**   * Returns true for a Caucho response stream.   */  public boolean isCauchoResponseStream()  {    return true;  }  /**   * Sets the underlying cache stream for a cached request.   *   * @param cache the cache stream.   */  public void setByteCacheStream(OutputStream cacheStream)  {    _cacheStream = cacheStream;        CauchoRequest req = _response.getRequest();    WebApp app = req.getWebApp();    _cacheMaxLength = app.getCacheMaxLength();  }  /**   * Response stream is a writable stream.   */  public boolean canWrite()  {    return true;  }  void setFlush(boolean flush)  {    _allowFlush = flush;  }  public void setAutoFlush(boolean isAutoFlush)  {    setDisableAutoFlush(! isAutoFlush);  }  void setDisableAutoFlush(boolean disable)  {    _disableAutoFlush = disable;  }  public void setHead()  {    _isHead = true;    _bufferSize = 0;  }  public final boolean isHead()  {    return _isHead;  }  public int getContentLength()  {    return _contentLength;  }  public void setBufferSize(int size)  {    if (isCommitted())      throw new IllegalStateException(L.l("Buffer size cannot be set after commit"));    super.setBufferSize(size);  }  public boolean isCommitted()  {    // jsp/17ec    return _isCommitted || _isClosed;  }  public void clear()    throws IOException  {    clearBuffer();        if (_isCommitted)      throw new IOException(L.l("can't clear response after writing headers"));  }    public void clearBuffer()  {    super.clearBuffer();    if (! _isCommitted) {      // jsp/15la      _isFirst = true;      _bufferStartOffset = 0;      _response.setHeaderWritten(false);    }    _next.setBufferOffset(_bufferStartOffset);  }  /**   * Clear the closed state, because of the NOT_MODIFIED   */  public void clearClosed()  {    _isClosed = false;  }  private void writeHeaders(int length)    throws IOException  {    _chunkedEncoding = _response.writeHeaders(_next, length);  }  /**   * Returns the byte buffer.   */  public byte []getBuffer()    throws IOException  {    flushBuffer();    return _next.getBuffer();  }  /**   * Returns the byte offset.   */  public int getBufferOffset()    throws IOException  {    byte []buffer;    int offset;    flushBuffer();    offset = _next.getBufferOffset();    if (! _chunkedEncoding) {      _bufferStartOffset = offset;      return offset;    }    else if (_bufferStartOffset > 0) {      return offset;    }    // chunked allocates 8 bytes for the chunk header    buffer = _next.getBuffer();    if (buffer.length - offset < 8) {      _isCommitted = true;      _next.flushBuffer();            buffer = _next.getBuffer();      offset = _next.getBufferOffset();    }    _bufferStartOffset = offset + 8;    _next.setBufferOffset(offset + 8);    return _bufferStartOffset;  }  /**   * Sets the next buffer   */  public byte []nextBuffer(int offset)    throws IOException  {    if (_isClosed)      return _next.getBuffer();        _isCommitted = true;        int startOffset = _bufferStartOffset;    _bufferStartOffset = 0;    int length = offset - startOffset;    long lengthHeader = _response.getContentLengthHeader();    if (lengthHeader > 0 && lengthHeader < _contentLength + length) {      lengthException(_next.getBuffer(), startOffset, length, lengthHeader);      length = (int) (lengthHeader - _contentLength);      offset = startOffset + length;    }    _contentLength += length;    try {      if (_isHead) {	return _next.getBuffer();      }      else if (_chunkedEncoding) {	if (length == 0)	  throw new IllegalStateException();      	byte []buffer = _next.getBuffer();	writeChunk(buffer, startOffset, length);	buffer = _next.nextBuffer(offset);	      	if (log.isLoggable(Level.FINE))	  log.fine(dbgId() + "write-chunk(" + offset + ")");	_bufferStartOffset = 8 + _next.getBufferOffset();	_next.setBufferOffset(_bufferStartOffset);	return buffer;      }      else {	if (_cacheStream != null)	  writeCache(_next.getBuffer(), startOffset, length);		byte []buffer = _next.nextBuffer(offset);	      	if (log.isLoggable(Level.FINE))	  log.fine(dbgId() + "write-chunk(" + offset + ")");	return buffer;      }    } catch (ClientDisconnectException e) {      _response.killCache();      if (_response.isIgnoreClientDisconnect()) {        _isDisconnected = true;	return _next.getBuffer();      }      else        throw e;    } catch (IOException e) {      _response.killCache();            throw e;    }  }  /**   * Sets the byte offset.   */  public void setBufferOffset(int offset)    throws IOException  {    if (_isClosed)      return;        int startOffset = _bufferStartOffset;    if (offset == startOffset)      return;        int length = offset - startOffset;    long lengthHeader = _response.getContentLengthHeader();    if (lengthHeader > 0 && lengthHeader < _contentLength + length) {      lengthException(_next.getBuffer(), startOffset, length, lengthHeader);      length = (int) (lengthHeader - _contentLength);      offset = startOffset + length;    }    _contentLength += length;        if (_cacheStream != null && ! _chunkedEncoding) {      _bufferStartOffset = offset;      writeCache(_next.getBuffer(), startOffset, length);    }    if (log.isLoggable(Level.FINE))      log.fine(dbgId() +  "write-chunk(" + length + ")");    if (! _isHead) {      _next.setBufferOffset(offset);    }  }  /**   * Writes the next chunk of data to the response stream.   *   * @param buf the buffer containing the data   * @param offset start offset into the buffer   * @param length length of the data in the buffer   */  protected void writeNext(byte []buf, int offset, int length,			   boolean isFinished)    throws IOException  {    try {      if (_isClosed)	return;      if (_disableAutoFlush && ! isFinished)	throw new IOException(L.l("auto-flushing has been disabled"));            boolean isFirst = _isFirst;      _isFirst = false;      if (! isFirst) {

⌨️ 快捷键说明

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