Mercurial Hosting > luan
annotate src/goodjava/webserver/ChunkedOutputStream.java @ 2018:5203eb9b0e02
http utf-8
| author | Franklin Schmidt <fschmidt@gmail.com> |
|---|---|
| date | Fri, 03 Oct 2025 16:45:33 -0600 |
| parents | f45ed55f5c11 |
| children |
| rev | line source |
|---|---|
| 2008 | 1 package goodjava.webserver; |
| 2 | |
| 3 import java.io.ByteArrayOutputStream; | |
| 4 import java.io.InputStream; | |
| 5 import java.io.IOException; | |
| 6 | |
| 7 | |
| 8 public class ChunkedOutputStream extends ByteArrayOutputStream { | |
| 9 private static final byte[] end = "0\r\n\r\n".getBytes(); | |
| 10 private static final int OPEN = 1; | |
| 11 private static final int CLOSING = 2; | |
| 12 private static final int CLOSED = 3; | |
| 13 | |
| 14 private final Response response; | |
| 15 private int status = OPEN; | |
| 16 private int i = 0; | |
| 17 | |
| 18 public ChunkedOutputStream(Response response) { | |
| 19 if(response==null) throw new NullPointerException(); | |
| 20 this.response = response; | |
| 21 response.headers.put("Transfer-Encoding","chunked"); | |
|
2010
f45ed55f5c11
fix chunked encoding
Franklin Schmidt <fschmidt@gmail.com>
parents:
2008
diff
changeset
|
22 response.headers.put("X-Accel-Buffering","no"); |
| 2008 | 23 response.body = new ChunkedInputStream(); |
| 24 } | |
| 25 | |
| 26 @Override public synchronized void close() { | |
| 27 if( status == OPEN ) { | |
| 28 status = CLOSING; | |
| 29 notifyAll(); | |
| 30 } | |
| 31 } | |
| 32 | |
| 33 @Override public synchronized void write(int b) { | |
| 34 super.write(b); | |
| 35 notifyAll(); | |
| 36 } | |
| 37 | |
| 38 @Override public synchronized void write(byte b[], int off, int len) { | |
| 39 super.write(b,off,len); | |
| 40 notifyAll(); | |
| 41 } | |
| 42 | |
| 43 @Override public synchronized void reset() { | |
| 44 super.reset(); | |
| 45 i = 0; | |
| 46 } | |
| 47 | |
| 48 private class ChunkedInputStream extends InputStream { | |
| 49 | |
| 50 @Override public int read() { | |
| 51 throw new UnsupportedOperationException(); | |
| 52 } | |
| 53 | |
| 54 @Override public int read(byte[] b,int off,int len) throws IOException { | |
| 55 synchronized(ChunkedOutputStream.this) { | |
| 56 if( i == count ) { | |
| 57 if( status == CLOSED ) | |
| 58 return -1; | |
| 59 if( status == CLOSING ) { | |
| 60 System.arraycopy(end,0,b,off,end.length); | |
| 61 status = CLOSED; | |
| 62 return end.length; | |
| 63 } | |
| 64 try { | |
| 65 ChunkedOutputStream.this.wait(); | |
| 66 } catch(InterruptedException e) { | |
| 67 throw new RuntimeException(e); | |
| 68 } | |
| 69 return read(b,off,len); | |
| 70 } | |
| 71 int offOld = off; | |
| 72 int left = count - i; | |
| 73 int extra = Integer.toHexString(left).length() + 4; | |
| 74 int n = Math.min( len - extra, left ); | |
| 75 byte[] hex = Integer.toHexString(n).getBytes(); | |
| 76 System.arraycopy( hex, 0, b, off, hex.length ); | |
| 77 off += hex.length; | |
| 78 b[off++] = '\r'; b[off++] = '\n'; | |
| 79 System.arraycopy(buf,i,b,off,n); | |
| 80 off += n; | |
| 81 b[off++] = '\r'; b[off++] = '\n'; | |
| 82 i += n; | |
| 83 if( i == count ) | |
| 84 ChunkedOutputStream.this.reset(); | |
| 85 return off - offOld; | |
| 86 } | |
| 87 } | |
| 88 } | |
| 89 } |
