Path: blob/master/src/jdk.httpserver/share/classes/sun/net/httpserver/ChunkedOutputStream.java
41159 views
/*1* Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.net.httpserver;2627import java.io.*;28import java.net.*;29import com.sun.net.httpserver.*;30import com.sun.net.httpserver.spi.*;3132/**33* a class which allows the caller to write an arbitrary34* number of bytes to an underlying stream.35* normal close() does not close the underlying stream36*37* This class is buffered.38*39* Each chunk is written in one go as :-40* abcd\r\nxxxxxxxxxxxxxx\r\n41*42* abcd is the chunk-size, and xxx is the chunk data43* If the length is less than 4 chars (in size) then the buffer44* is written with an offset.45* Final chunk is:46* 0\r\n\r\n47*/4849class ChunkedOutputStream extends FilterOutputStream50{51private boolean closed = false;52/* max. amount of user data per chunk */53final static int CHUNK_SIZE = 4096;54/* allow 4 bytes for chunk-size plus 4 for CRLFs */55final static int OFFSET = 6; /* initial <=4 bytes for len + CRLF */56private int pos = OFFSET;57private int count = 0;58private byte[] buf = new byte [CHUNK_SIZE+OFFSET+2];59ExchangeImpl t;6061ChunkedOutputStream (ExchangeImpl t, OutputStream src) {62super (src);63this.t = t;64}6566public void write (int b) throws IOException {67if (closed) {68throw new StreamClosedException ();69}70buf [pos++] = (byte)b;71count ++;72if (count == CHUNK_SIZE) {73writeChunk();74}75assert count < CHUNK_SIZE;76}7778public void write (byte[]b, int off, int len) throws IOException {79if (closed) {80throw new StreamClosedException ();81}82int remain = CHUNK_SIZE - count;83if (len > remain) {84System.arraycopy (b,off,buf,pos,remain);85count = CHUNK_SIZE;86writeChunk();87len -= remain;88off += remain;89while (len >= CHUNK_SIZE) {90System.arraycopy (b,off,buf,OFFSET,CHUNK_SIZE);91len -= CHUNK_SIZE;92off += CHUNK_SIZE;93count = CHUNK_SIZE;94writeChunk();95}96}97if (len > 0) {98System.arraycopy (b,off,buf,pos,len);99count += len;100pos += len;101}102if (count == CHUNK_SIZE) {103writeChunk();104}105}106107/**108* write out a chunk , and reset the pointers109* chunk does not have to be CHUNK_SIZE bytes110* count must == number of user bytes (<= CHUNK_SIZE)111*/112private void writeChunk () throws IOException {113char[] c = Integer.toHexString (count).toCharArray();114int clen = c.length;115int startByte = 4 - clen;116int i;117for (i=0; i<clen; i++) {118buf[startByte+i] = (byte)c[i];119}120buf[startByte + (i++)] = '\r';121buf[startByte + (i++)] = '\n';122buf[startByte + (i++) + count] = '\r';123buf[startByte + (i++) + count] = '\n';124out.write (buf, startByte, i+count);125count = 0;126pos = OFFSET;127}128129public void close () throws IOException {130if (closed) {131return;132}133flush();134try {135/* write an empty chunk */136writeChunk();137out.flush();138LeftOverInputStream is = t.getOriginalInputStream();139if (!is.isClosed()) {140is.close();141}142/* some clients close the connection before empty chunk is sent */143} catch (IOException e) {144145} finally {146closed = true;147}148149WriteFinishedEvent e = new WriteFinishedEvent (t);150t.getHttpContext().getServerImpl().addEvent (e);151}152153public void flush () throws IOException {154if (closed) {155throw new StreamClosedException ();156}157if (count > 0) {158writeChunk();159}160out.flush();161}162}163164165