?? chunkedoutputstream.java
字號(hào):
// ChunkedOutputStream - an OutputStream that implements HTTP/1.1 chunking//// Copyright (C)1996,1998 by Jef Poskanzer <jef@acme.com>. All rights reserved.//// Redistribution and use in source and binary forms, with or without// modification, are permitted provided that the following conditions// are met:// 1. Redistributions of source code must retain the above copyright// notice, this list of conditions and the following disclaimer.// 2. Redistributions in binary form must reproduce the above copyright// notice, this list of conditions and the following disclaimer in the// documentation and/or other materials provided with the distribution.//// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF// SUCH DAMAGE.//// Visit the ACME Labs Java page for up-to-date versions of this and other// fine Java utilities: http://www.acme.com/java/package Acme.Serve.servlet.http;import java.io.*;import java.util.*;import Acme.Serve.servlet.*;/// An OutputStream that implements HTTP/1.1 chunking.// <P>// This class lets a Servlet send its response data as an HTTP/1.1 chunked// stream. Chunked streams are a way to send arbitrary-length data without// having to know beforehand how much you're going to send. They are// introduced by a "Transfer-Encoding: chunked" header, so you have to// set that header when you make one of these streams.// <P>// Sample usage:// <BLOCKQUOTE><PRE><CODE>// res.setHeader( "Transfer-Encoding", "chunked" );// OutputStream out = res.getOutputStream();// ChunkedOutputStream chunkOut = new ChunkedOutputStream( out );// (write data to chunkOut instead of out)// (optionally set footers)// chunkOut.done();// </CODE></PRE></BLOCKQUOTE>// <P>// Every time the stream gets flushed, a chunk is sent. When done()// is called, an empty chunk is sent, marking the end of the chunked// stream as per the chunking spec.// <P>// <A HREF="/resources/classes/Acme/Serve/servlet/http/ChunkedOutputStream.java">Fetch the software.</A><BR>// <A HREF="/resources/classes/Acme.tar.gz">Fetch the entire Acme package.</A>public class ChunkedOutputStream extends BufferedOutputStream { /// Make a ChunkedOutputStream with a default buffer size. // @param out the underlying output stream public ChunkedOutputStream( OutputStream out ) { super( out ); } /// Make a ChunkedOutputStream with a specified buffer size. // @param out the underlying output stream // @param size the buffer size public ChunkedOutputStream( OutputStream out, int size ) { super( out, size ); } /// Flush the stream. This will write any buffered output // bytes as a chunk. // @exception IOException if an I/O error occurred public synchronized void flush() throws IOException { if ( count != 0 ) { writeBuf( buf, 0, count ); count = 0; } } private Vector footerNames = new Vector(); private Vector footerValues = new Vector(); /// Set a footer. Footers are much like HTTP headers, except that // they come at the end of the data instead of at the beginning. public void setFooter( String name, String value ) { footerNames.addElement( name ); footerValues.addElement( value ); } /// Indicate the end of the chunked data by sending a zero-length chunk, // possible including footers. // @exception IOException if an I/O error occurred public void done() throws IOException { flush(); PrintStream pout = new PrintStream( out ); pout.println( "0" ); if ( footerNames.size() > 0 ) { // Send footers. for ( int i = 0; i < footerNames.size(); ++i ) { String name = (String) footerNames.elementAt( i ); String value = (String) footerValues.elementAt( i ); pout.println( name + ": " + value ); } } footerNames = null; footerValues = null; pout.println( "" ); pout.flush(); } /// Make sure that calling close() terminates the chunked stream. public void close() throws IOException { if ( footerNames != null ) done(); super.close(); } /// Write a sub-array of bytes. // <P> // The only reason we have to override the BufferedOutputStream version // of this is that it writes the array directly to the output stream // if doesn't fit in the buffer. So we make it use our own chunk-write // routine instead. Otherwise this is identical to the parent-class // version. // @param b the data to be written // @param off the start offset in the data // @param len the number of bytes that are written // @exception IOException if an I/O error occurred public synchronized void write( byte b[], int off, int len ) throws IOException { int avail = buf.length - count; if ( len <= avail ) { System.arraycopy( b, off, buf, count, len ); count += len; return; } flush(); writeBuf( b, off, len ); } private static final byte[] crlf = { 13, 10 }; /// The only routine that actually writes to the output stream. // This is where chunking semantics are implemented. // @exception IOException if an I/O error occurred private void writeBuf( byte b[], int off, int len ) throws IOException { // Write the chunk length as a hex number. String lenStr = Integer.toString( len, 16 ); byte[] lenBytes = lenStr.getBytes(); out.write( lenBytes ); // Write a CRLF. out.write( crlf ); // Write the data. if ( len != 0 ) out.write( b, off, len ); // Write a CRLF. out.write( crlf ); // And flush the real stream. out.flush(); } }
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -