Mercurial Hosting > luan
comparison src/goodjava/webserver/ChunkedOutputStream.java @ 2008:bba3e529e346 default tip
chunked encoding
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Wed, 27 Aug 2025 01:14:17 -0600 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
2007:408f7dd7e503 | 2008:bba3e529e346 |
---|---|
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"); | |
22 response.body = new ChunkedInputStream(); | |
23 } | |
24 | |
25 @Override public synchronized void close() { | |
26 if( status == OPEN ) { | |
27 status = CLOSING; | |
28 notifyAll(); | |
29 } | |
30 } | |
31 | |
32 @Override public synchronized void write(int b) { | |
33 super.write(b); | |
34 notifyAll(); | |
35 } | |
36 | |
37 @Override public synchronized void write(byte b[], int off, int len) { | |
38 super.write(b,off,len); | |
39 notifyAll(); | |
40 } | |
41 | |
42 @Override public synchronized void reset() { | |
43 super.reset(); | |
44 i = 0; | |
45 } | |
46 | |
47 private class ChunkedInputStream extends InputStream { | |
48 | |
49 @Override public int read() { | |
50 throw new UnsupportedOperationException(); | |
51 } | |
52 | |
53 @Override public int read(byte[] b,int off,int len) throws IOException { | |
54 synchronized(ChunkedOutputStream.this) { | |
55 if( i == count ) { | |
56 if( status == CLOSED ) | |
57 return -1; | |
58 if( status == CLOSING ) { | |
59 System.arraycopy(end,0,b,off,end.length); | |
60 status = CLOSED; | |
61 return end.length; | |
62 } | |
63 try { | |
64 ChunkedOutputStream.this.wait(); | |
65 } catch(InterruptedException e) { | |
66 throw new RuntimeException(e); | |
67 } | |
68 return read(b,off,len); | |
69 } | |
70 int offOld = off; | |
71 int left = count - i; | |
72 int extra = Integer.toHexString(left).length() + 4; | |
73 int n = Math.min( len - extra, left ); | |
74 byte[] hex = Integer.toHexString(n).getBytes(); | |
75 System.arraycopy( hex, 0, b, off, hex.length ); | |
76 off += hex.length; | |
77 b[off++] = '\r'; b[off++] = '\n'; | |
78 System.arraycopy(buf,i,b,off,n); | |
79 off += n; | |
80 b[off++] = '\r'; b[off++] = '\n'; | |
81 i += n; | |
82 if( i == count ) | |
83 ChunkedOutputStream.this.reset(); | |
84 return off - offOld; | |
85 } | |
86 } | |
87 } | |
88 } |