1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 package org.metricshub.wbem.sblim.cimclient.internal.http.io;
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53 import java.io.EOFException;
54 import java.io.IOException;
55 import java.io.InputStream;
56 import java.util.logging.Level;
57 import org.metricshub.wbem.sblim.cimclient.internal.http.HttpHeader;
58 import org.metricshub.wbem.sblim.cimclient.internal.http.HttpMethod;
59 import org.metricshub.wbem.sblim.cimclient.internal.logging.LogAndTraceBroker;
60
61
62
63
64
65 public class ChunkedInputStream extends InputStream {
66 private InputStream iIn;
67
68 private String iTrailerFields;
69
70 private String iOrigin;
71
72 private long iChunkSize = 0;
73
74 private boolean iEof = false;
75
76 private HttpHeader iTrailers = new HttpHeader();
77
78 private boolean iClosed = false;
79
80 private byte[] iTmp = new byte[1];
81
82
83
84
85
86
87
88
89
90 public ChunkedInputStream(InputStream pStream, String pTrailerFields) {
91 this(pStream, pTrailerFields, null);
92 }
93
94
95
96
97
98
99
100
101
102
103
104 public ChunkedInputStream(InputStream pStream, String pTrailerFields, String pOrigin) {
105 this.iIn = pStream;
106 this.iTrailerFields = pTrailerFields;
107 this.iOrigin = pOrigin == null ? "Unknown" : pOrigin;
108 }
109
110 @Override
111 public synchronized int read() throws IOException {
112 return (read(this.iTmp, 0, 1) > 0) ? (this.iTmp[0] & 0xFF) : -1;
113 }
114
115 @Override
116 public synchronized int read(byte[] buf, int off, int len) throws IOException {
117 int total = 0;
118 if (this.iEof || this.iClosed) return -1;
119
120
121 if (this.iChunkSize == 0) {
122 String line = HttpMethod.readLine(this.iIn);
123
124
125 if ("".equals(line)) {
126
127
128
129 line = HttpMethod.readLine(this.iIn);
130
131
132 }
133
134 try {
135 this.iChunkSize = Long.parseLong(line, 16);
136 } catch (Exception e) {
137 LogAndTraceBroker.getBroker().trace(Level.FINER, "Invalid chunk size on HTTP stream", e);
138 this.iEof = true;
139 throw new IOException("Invalid chunk size");
140 }
141 }
142 if (this.iChunkSize > 0) {
143 total = this.iIn.read(buf, off, (this.iChunkSize < len) ? (int) this.iChunkSize : (int) len);
144 if (total > 0) {
145 this.iChunkSize -= total;
146 }
147 if (total == -1) {
148 LogAndTraceBroker
149 .getBroker()
150 .trace(
151 Level.FINE,
152 "Unexpected EOF trying to read " +
153 (this.iChunkSize < len ? this.iChunkSize : len) +
154 " bytes from HTTP chunk with remaining length of " +
155 this.iChunkSize
156 );
157 throw new EOFException("Unexpected EOF reading chunk");
158 }
159 } else {
160
161 this.iEof = true;
162 if (this.iTrailerFields != null && this.iTrailerFields.trim().length() > 0) {
163 try {
164 this.iTrailers = new HttpHeader(this.iIn);
165
166 this.iTrailers.examineTrailer(this.iOrigin);
167 } catch (IOException e) {
168 LogAndTraceBroker
169 .getBroker()
170 .trace(Level.FINE, "Unexpected EOF reading trailer, expected fields were " + this.iTrailerFields);
171 throw new EOFException("Unexpected EOF reading trailer");
172 }
173 }
174 }
175 return total > 0 ? total : -1;
176 }
177
178
179
180
181
182
183 public synchronized HttpHeader getTrailers() {
184 return this.iTrailers;
185 }
186
187 @Override
188 public synchronized long skip(long total) throws IOException {
189 byte[] tmp = new byte[(int) total];
190 return read(tmp, 0, (int) total);
191 }
192
193
194
195
196
197 @Override
198 public synchronized int available() {
199 return (this.iEof ? 0 : (this.iChunkSize > 0 ? (int) this.iChunkSize : 1));
200 }
201
202 @Override
203 public void close() throws IOException {
204 if (!this.iClosed) {
205 this.iClosed = true;
206 byte[] buf = new byte[512];
207 while (read(buf, 0, buf.length) > -1) {
208
209 }
210 this.iIn.close();
211 } else throw new IOException("Error while closing stream");
212 }
213 }