--- a/src/java.base/share/classes/sun/net/www/http/ChunkedOutputStream.java Fri Aug 30 13:11:16 2019 +0100
+++ b/src/java.base/share/classes/sun/net/www/http/ChunkedOutputStream.java Fri Aug 30 15:42:27 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,8 @@
package sun.net.www.http;
import java.io.*;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
/**
* OutputStream that sends the output to the underlying stream using chunked
@@ -61,6 +63,8 @@
/* header for a complete Chunk */
private byte[] completeHeader;
+ private final Lock writeLock = new ReentrantLock();
+
/* return the size of the header for a particular chunk size */
private static int getHeaderSize(int size) {
return (Integer.toHexString(size)).length() + CRLF_SIZE;
@@ -197,77 +201,92 @@
* The size of the data is of course smaller than preferredChunkSize.
*/
@Override
- public synchronized void write(byte b[], int off, int len) {
- ensureOpen();
- if ((off < 0) || (off > b.length) || (len < 0) ||
- ((off + len) > b.length) || ((off + len) < 0)) {
- throw new IndexOutOfBoundsException();
- } else if (len == 0) {
- return;
- }
-
- /* if b[] contains enough data then one loop cycle creates one complete
- * data chunk with a header, body and a footer, and then flushes the
- * chunk to the underlying stream. Otherwise, the last loop cycle
- * creates incomplete data chunk with empty header and with no footer
- * and stores this incomplete chunk in an internal buffer buf[]
- */
- int bytesToWrite = len;
- int inputIndex = off; /* the index of the byte[] currently being written */
-
- do {
- /* enough data to complete a chunk */
- if (bytesToWrite >= spaceInCurrentChunk) {
-
- /* header */
- for (int i=0; i<completeHeader.length; i++)
- buf[i] = completeHeader[i];
-
- /* data */
- System.arraycopy(b, inputIndex, buf, count, spaceInCurrentChunk);
- inputIndex += spaceInCurrentChunk;
- bytesToWrite -= spaceInCurrentChunk;
- count += spaceInCurrentChunk;
-
- /* footer */
- buf[count++] = FOOTER[0];
- buf[count++] = FOOTER[1];
- spaceInCurrentChunk = 0; //chunk is complete
-
- flush(false);
- if (checkError()){
- break;
- }
+ public void write(byte b[], int off, int len) {
+ writeLock.lock();
+ try {
+ ensureOpen();
+ if ((off < 0) || (off > b.length) || (len < 0) ||
+ ((off + len) > b.length) || ((off + len) < 0)) {
+ throw new IndexOutOfBoundsException();
+ } else if (len == 0) {
+ return;
}
- /* not enough data to build a chunk */
- else {
- /* header */
- /* do not write header if not enough bytes to build a chunk yet */
+ /* if b[] contains enough data then one loop cycle creates one complete
+ * data chunk with a header, body and a footer, and then flushes the
+ * chunk to the underlying stream. Otherwise, the last loop cycle
+ * creates incomplete data chunk with empty header and with no footer
+ * and stores this incomplete chunk in an internal buffer buf[]
+ */
+ int bytesToWrite = len;
+ int inputIndex = off; /* the index of the byte[] currently being written */
+
+ do {
+ /* enough data to complete a chunk */
+ if (bytesToWrite >= spaceInCurrentChunk) {
+
+ /* header */
+ for (int i = 0; i < completeHeader.length; i++)
+ buf[i] = completeHeader[i];
+
+ /* data */
+ System.arraycopy(b, inputIndex, buf, count, spaceInCurrentChunk);
+ inputIndex += spaceInCurrentChunk;
+ bytesToWrite -= spaceInCurrentChunk;
+ count += spaceInCurrentChunk;
- /* data */
- System.arraycopy(b, inputIndex, buf, count, bytesToWrite);
- count += bytesToWrite;
- size += bytesToWrite;
- spaceInCurrentChunk -= bytesToWrite;
- bytesToWrite = 0;
+ /* footer */
+ buf[count++] = FOOTER[0];
+ buf[count++] = FOOTER[1];
+ spaceInCurrentChunk = 0; //chunk is complete
+
+ flush(false);
+ if (checkError()) {
+ break;
+ }
+ }
- /* footer */
- /* do not write header if not enough bytes to build a chunk yet */
- }
- } while (bytesToWrite > 0);
+ /* not enough data to build a chunk */
+ else {
+ /* header */
+ /* do not write header if not enough bytes to build a chunk yet */
+
+ /* data */
+ System.arraycopy(b, inputIndex, buf, count, bytesToWrite);
+ count += bytesToWrite;
+ size += bytesToWrite;
+ spaceInCurrentChunk -= bytesToWrite;
+ bytesToWrite = 0;
+
+ /* footer */
+ /* do not write header if not enough bytes to build a chunk yet */
+ }
+ } while (bytesToWrite > 0);
+ } finally {
+ writeLock.unlock();
+ }
}
@Override
- public synchronized void write(int _b) {
- byte b[] = {(byte)_b};
- write(b, 0, 1);
+ public void write(int _b) {
+ writeLock.lock();
+ try {
+ byte b[] = {(byte) _b};
+ write(b, 0, 1);
+ } finally {
+ writeLock.unlock();
+ }
}
- public synchronized void reset() {
- count = preferedHeaderSize;
- size = 0;
- spaceInCurrentChunk = preferredChunkDataSize;
+ public void reset() {
+ writeLock.lock();
+ try {
+ count = preferedHeaderSize;
+ size = 0;
+ spaceInCurrentChunk = preferredChunkDataSize;
+ } finally {
+ writeLock.unlock();
+ }
}
public int size() {
@@ -275,26 +294,36 @@
}
@Override
- public synchronized void close() {
- ensureOpen();
+ public void close() {
+ writeLock.lock();
+ try {
+ ensureOpen();
- /* if we have buffer a chunked send it */
- if (size > 0) {
+ /* if we have buffer a chunked send it */
+ if (size > 0) {
+ flush(true);
+ }
+
+ /* send a zero length chunk */
flush(true);
+
+ /* don't close the underlying stream */
+ out = null;
+ } finally {
+ writeLock.unlock();
}
-
- /* send a zero length chunk */
- flush(true);
-
- /* don't close the underlying stream */
- out = null;
}
@Override
- public synchronized void flush() {
- ensureOpen();
- if (size > 0) {
- flush(true);
+ public void flush() {
+ writeLock.lock();
+ try {
+ ensureOpen();
+ if (size > 0) {
+ flush(true);
+ }
+ } finally {
+ writeLock.unlock();
}
}
}