195 * chunk of preferredChunkSize size the data get stored as an incomplete |
199 * chunk of preferredChunkSize size the data get stored as an incomplete |
196 * chunk of a following format: {space for data length}{CRLF}{data} |
200 * chunk of a following format: {space for data length}{CRLF}{data} |
197 * The size of the data is of course smaller than preferredChunkSize. |
201 * The size of the data is of course smaller than preferredChunkSize. |
198 */ |
202 */ |
199 @Override |
203 @Override |
200 public synchronized void write(byte b[], int off, int len) { |
204 public void write(byte b[], int off, int len) { |
201 ensureOpen(); |
205 writeLock.lock(); |
202 if ((off < 0) || (off > b.length) || (len < 0) || |
206 try { |
203 ((off + len) > b.length) || ((off + len) < 0)) { |
207 ensureOpen(); |
204 throw new IndexOutOfBoundsException(); |
208 if ((off < 0) || (off > b.length) || (len < 0) || |
205 } else if (len == 0) { |
209 ((off + len) > b.length) || ((off + len) < 0)) { |
206 return; |
210 throw new IndexOutOfBoundsException(); |
207 } |
211 } else if (len == 0) { |
208 |
212 return; |
209 /* if b[] contains enough data then one loop cycle creates one complete |
213 } |
210 * data chunk with a header, body and a footer, and then flushes the |
214 |
211 * chunk to the underlying stream. Otherwise, the last loop cycle |
215 /* if b[] contains enough data then one loop cycle creates one complete |
212 * creates incomplete data chunk with empty header and with no footer |
216 * data chunk with a header, body and a footer, and then flushes the |
213 * and stores this incomplete chunk in an internal buffer buf[] |
217 * chunk to the underlying stream. Otherwise, the last loop cycle |
214 */ |
218 * creates incomplete data chunk with empty header and with no footer |
215 int bytesToWrite = len; |
219 * and stores this incomplete chunk in an internal buffer buf[] |
216 int inputIndex = off; /* the index of the byte[] currently being written */ |
220 */ |
217 |
221 int bytesToWrite = len; |
218 do { |
222 int inputIndex = off; /* the index of the byte[] currently being written */ |
219 /* enough data to complete a chunk */ |
223 |
220 if (bytesToWrite >= spaceInCurrentChunk) { |
224 do { |
221 |
225 /* enough data to complete a chunk */ |
222 /* header */ |
226 if (bytesToWrite >= spaceInCurrentChunk) { |
223 for (int i=0; i<completeHeader.length; i++) |
227 |
224 buf[i] = completeHeader[i]; |
228 /* header */ |
225 |
229 for (int i = 0; i < completeHeader.length; i++) |
226 /* data */ |
230 buf[i] = completeHeader[i]; |
227 System.arraycopy(b, inputIndex, buf, count, spaceInCurrentChunk); |
231 |
228 inputIndex += spaceInCurrentChunk; |
232 /* data */ |
229 bytesToWrite -= spaceInCurrentChunk; |
233 System.arraycopy(b, inputIndex, buf, count, spaceInCurrentChunk); |
230 count += spaceInCurrentChunk; |
234 inputIndex += spaceInCurrentChunk; |
231 |
235 bytesToWrite -= spaceInCurrentChunk; |
232 /* footer */ |
236 count += spaceInCurrentChunk; |
233 buf[count++] = FOOTER[0]; |
237 |
234 buf[count++] = FOOTER[1]; |
238 /* footer */ |
235 spaceInCurrentChunk = 0; //chunk is complete |
239 buf[count++] = FOOTER[0]; |
236 |
240 buf[count++] = FOOTER[1]; |
237 flush(false); |
241 spaceInCurrentChunk = 0; //chunk is complete |
238 if (checkError()){ |
242 |
239 break; |
243 flush(false); |
|
244 if (checkError()) { |
|
245 break; |
|
246 } |
240 } |
247 } |
241 } |
248 |
242 |
249 /* not enough data to build a chunk */ |
243 /* not enough data to build a chunk */ |
250 else { |
244 else { |
251 /* header */ |
245 /* header */ |
252 /* do not write header if not enough bytes to build a chunk yet */ |
246 /* do not write header if not enough bytes to build a chunk yet */ |
253 |
247 |
254 /* data */ |
248 /* data */ |
255 System.arraycopy(b, inputIndex, buf, count, bytesToWrite); |
249 System.arraycopy(b, inputIndex, buf, count, bytesToWrite); |
256 count += bytesToWrite; |
250 count += bytesToWrite; |
257 size += bytesToWrite; |
251 size += bytesToWrite; |
258 spaceInCurrentChunk -= bytesToWrite; |
252 spaceInCurrentChunk -= bytesToWrite; |
259 bytesToWrite = 0; |
253 bytesToWrite = 0; |
260 |
254 |
261 /* footer */ |
255 /* footer */ |
262 /* do not write header if not enough bytes to build a chunk yet */ |
256 /* do not write header if not enough bytes to build a chunk yet */ |
263 } |
257 } |
264 } while (bytesToWrite > 0); |
258 } while (bytesToWrite > 0); |
265 } finally { |
259 } |
266 writeLock.unlock(); |
260 |
267 } |
261 @Override |
268 } |
262 public synchronized void write(int _b) { |
269 |
263 byte b[] = {(byte)_b}; |
270 @Override |
264 write(b, 0, 1); |
271 public void write(int _b) { |
265 } |
272 writeLock.lock(); |
266 |
273 try { |
267 public synchronized void reset() { |
274 byte b[] = {(byte) _b}; |
268 count = preferedHeaderSize; |
275 write(b, 0, 1); |
269 size = 0; |
276 } finally { |
270 spaceInCurrentChunk = preferredChunkDataSize; |
277 writeLock.unlock(); |
|
278 } |
|
279 } |
|
280 |
|
281 public void reset() { |
|
282 writeLock.lock(); |
|
283 try { |
|
284 count = preferedHeaderSize; |
|
285 size = 0; |
|
286 spaceInCurrentChunk = preferredChunkDataSize; |
|
287 } finally { |
|
288 writeLock.unlock(); |
|
289 } |
271 } |
290 } |
272 |
291 |
273 public int size() { |
292 public int size() { |
274 return size; |
293 return size; |
275 } |
294 } |
276 |
295 |
277 @Override |
296 @Override |
278 public synchronized void close() { |
297 public void close() { |
279 ensureOpen(); |
298 writeLock.lock(); |
280 |
299 try { |
281 /* if we have buffer a chunked send it */ |
300 ensureOpen(); |
282 if (size > 0) { |
301 |
|
302 /* if we have buffer a chunked send it */ |
|
303 if (size > 0) { |
|
304 flush(true); |
|
305 } |
|
306 |
|
307 /* send a zero length chunk */ |
283 flush(true); |
308 flush(true); |
284 } |
309 |
285 |
310 /* don't close the underlying stream */ |
286 /* send a zero length chunk */ |
311 out = null; |
287 flush(true); |
312 } finally { |
288 |
313 writeLock.unlock(); |
289 /* don't close the underlying stream */ |
314 } |
290 out = null; |
315 } |
291 } |
316 |
292 |
317 @Override |
293 @Override |
318 public void flush() { |
294 public synchronized void flush() { |
319 writeLock.lock(); |
295 ensureOpen(); |
320 try { |
296 if (size > 0) { |
321 ensureOpen(); |
297 flush(true); |
322 if (size > 0) { |
|
323 flush(true); |
|
324 } |
|
325 } finally { |
|
326 writeLock.unlock(); |
298 } |
327 } |
299 } |
328 } |
300 } |
329 } |