Mercurial Hosting > luan
annotate src/goodjava/webserver/ChunkedOutputStream.java @ 2010:f45ed55f5c11 default tip
fix chunked encoding
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Tue, 02 Sep 2025 06:00:41 -0600 |
parents | bba3e529e346 |
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 } |