163 lines · 5.0 KB · Java
RawDownload
/* * Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code 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.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.net.httpserver; import java.io.*;import java.net.*;import com.sun.net.httpserver.*;import com.sun.net.httpserver.spi.*; /** * a class which allows the caller to write an arbitrary * number of bytes to an underlying stream. * normal close() does not close the underlying stream * * This class is buffered. * * Each chunk is written in one go as :- * abcd\r\nxxxxxxxxxxxxxx\r\n * * abcd is the chunk-size, and xxx is the chunk data * If the length is less than 4 chars (in size) then the buffer * is written with an offset. * Final chunk is: * 0\r\n\r\n */ class ChunkedOutputStream extends FilterOutputStream{    private boolean closed = false;    /* max. amount of user data per chunk */    final static int CHUNK_SIZE = 4096;    /* allow 4 bytes for chunk-size plus 4 for CRLFs */    final static int OFFSET = 6; /* initial <=4 bytes for len + CRLF */    private int pos = OFFSET;    private int count = 0;    private byte[] buf = new byte [CHUNK_SIZE+OFFSET+2];    ExchangeImpl t;     ChunkedOutputStream (ExchangeImpl t, OutputStream src) {        super (src);        this.t = t;    }     public void write (int b) throws IOException {        if (closed) {            throw new StreamClosedException ();        }        buf [pos++] = (byte)b;        count ++;        if (count == CHUNK_SIZE) {            writeChunk();        }        assert count < CHUNK_SIZE;    }     public void write (byte[]b, int off, int len) throws IOException {        if (closed) {            throw new StreamClosedException ();        }        int remain = CHUNK_SIZE - count;        if (len > remain) {            System.arraycopy (b,off,buf,pos,remain);            count = CHUNK_SIZE;            writeChunk();            len -= remain;            off += remain;            while (len >= CHUNK_SIZE) {                System.arraycopy (b,off,buf,OFFSET,CHUNK_SIZE);                len -= CHUNK_SIZE;                off += CHUNK_SIZE;                count = CHUNK_SIZE;                writeChunk();            }        }        if (len > 0) {            System.arraycopy (b,off,buf,pos,len);            count += len;            pos += len;        }        if (count == CHUNK_SIZE) {            writeChunk();        }    }     /**     * write out a chunk , and reset the pointers     * chunk does not have to be CHUNK_SIZE bytes     * count must == number of user bytes (<= CHUNK_SIZE)     */    private void writeChunk () throws IOException {        char[] c = Integer.toHexString (count).toCharArray();        int clen = c.length;        int startByte = 4 - clen;        int i;        for (i=0; i<clen; i++) {            buf[startByte+i] = (byte)c[i];        }        buf[startByte + (i++)] = '\r';        buf[startByte + (i++)] = '\n';        buf[startByte + (i++) + count] = '\r';        buf[startByte + (i++) + count] = '\n';        out.write (buf, startByte, i+count);        count = 0;        pos = OFFSET;    }     public void close () throws IOException {        if (closed) {            return;        }        flush();        try {            /* write an empty chunk */            writeChunk();            out.flush();            LeftOverInputStream is = t.getOriginalInputStream();            if (!is.isClosed()) {                is.close();            }        /* some clients close the connection before empty chunk is sent */        } catch (IOException e) {         } finally {            closed = true;        }         WriteFinishedEvent e = new WriteFinishedEvent (t);        t.getHttpContext().getServerImpl().addEvent (e);    }     public void flush () throws IOException {        if (closed) {            throw new StreamClosedException ();        }        if (count > 0) {            writeChunk();        }        out.flush();    }}