Use Java 11 InputStream::readAllBytes to read String entities
Signed-off-by: jansupol <jan.supol@oracle.com>
diff --git a/core-common/src/main/java/org/glassfish/jersey/message/internal/ReaderWriter.java b/core-common/src/main/java/org/glassfish/jersey/message/internal/ReaderWriter.java
index 362dd2f..64c58f3 100644
--- a/core-common/src/main/java/org/glassfish/jersey/message/internal/ReaderWriter.java
+++ b/core-common/src/main/java/org/glassfish/jersey/message/internal/ReaderWriter.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2022 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -19,13 +19,15 @@
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
-import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.nio.charset.Charset;
import java.security.AccessController;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -134,7 +136,7 @@
* @throws IOException if there is an error reading from the input stream.
*/
public static String readFromAsString(InputStream in, MediaType type) throws IOException {
- return readFromAsString(new InputStreamReader(in, getCharset(type)));
+ return new String(readAllBytes(in), getCharset(type));
}
/**
@@ -154,6 +156,73 @@
}
return sb.toString();
}
+ /**
+ * The maximum size of array to allocate.
+ * Some VMs reserve some header words in an array.
+ * Attempts to allocate larger arrays may result in
+ * OutOfMemoryError: Requested array size exceeds VM limit
+ */
+ private static final int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;
+
+ /**
+ * Java 9+ InputStream::readAllBytes
+ * TODO Replace when Java 8 not any longer supported (3.1+)
+ */
+ private static byte[] readAllBytes(InputStream inputStream) throws IOException {
+ List<byte[]> bufs = null;
+ byte[] result = null;
+ int total = 0;
+ int remaining = Integer.MAX_VALUE;
+ int n;
+ do {
+ byte[] buf = new byte[Math.min(remaining, BUFFER_SIZE)];
+ int nread = 0;
+
+ // read to EOF which may read more or less than buffer size
+ while ((n = inputStream.read(buf, nread,
+ Math.min(buf.length - nread, remaining))) > 0) {
+ nread += n;
+ remaining -= n;
+ }
+
+ if (nread > 0) {
+ if (MAX_BUFFER_SIZE - total < nread) {
+ throw new OutOfMemoryError("Required array size too large");
+ }
+ total += nread;
+ if (result == null) {
+ result = buf;
+ } else {
+ if (bufs == null) {
+ bufs = new ArrayList<>();
+ bufs.add(result);
+ }
+ bufs.add(buf);
+ }
+ }
+ // if the last call to read returned -1 or the number of bytes
+ // requested have been read then break
+ } while (n >= 0 && remaining > 0);
+
+ if (bufs == null) {
+ if (result == null) {
+ return new byte[0];
+ }
+ return result.length == total ? result : Arrays.copyOf(result, total);
+ }
+
+ result = new byte[total];
+ int offset = 0;
+ remaining = total;
+ for (byte[] b : bufs) {
+ int count = Math.min(b.length, remaining);
+ System.arraycopy(b, 0, result, offset, count);
+ offset += count;
+ remaining -= count;
+ }
+
+ return result;
+ }
/**
* Convert a string to bytes and write those bytes to an output stream.