src/java.base/share/classes/sun/net/www/http/ChunkedOutputStream.java
branchJDK-8229867-branch
changeset 57968 8595871a5446
parent 47216 71c04702a3d5
--- 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();
         }
     }
 }