6755625: Add HttpURLConnection.setFixedLengthStreamingMode(long)
Reviewed-by: jccollet
--- a/jdk/src/share/classes/com/sun/net/ssl/internal/www/protocol/https/HttpsURLConnectionOldImpl.java Tue Nov 11 09:07:58 2008 +0000
+++ b/jdk/src/share/classes/com/sun/net/ssl/internal/www/protocol/https/HttpsURLConnectionOldImpl.java Wed Nov 12 16:38:17 2008 +0000
@@ -497,6 +497,10 @@
delegate.setFixedLengthStreamingMode(contentLength);
}
+ public void setFixedLengthStreamingMode(long contentLength) {
+ delegate.setFixedLengthStreamingMode(contentLength);
+ }
+
public void setChunkedStreamingMode (int chunklen) {
delegate.setChunkedStreamingMode(chunklen);
}
--- a/jdk/src/share/classes/java/net/HttpURLConnection.java Tue Nov 11 09:07:58 2008 +0000
+++ b/jdk/src/share/classes/java/net/HttpURLConnection.java Wed Nov 12 16:38:17 2008 +0000
@@ -73,11 +73,24 @@
* The fixed content-length when using fixed-length streaming mode.
* A value of <code>-1</code> means fixed-length streaming mode is disabled
* for output.
+ *
+ * <P> <B>NOTE:</B> {@link #fixedContentLengthLong} is recommended instead
+ * of this field, as it allows larger content lengths to be set.
+ *
* @since 1.5
*/
protected int fixedContentLength = -1;
/**
+ * The fixed content-length when using fixed-length streaming mode.
+ * A value of {@code -1} means fixed-length streaming mode is disabled
+ * for output.
+ *
+ * @since 1.7
+ */
+ protected long fixedContentLengthLong = -1;
+
+ /**
* Returns the key for the <code>n</code><sup>th</sup> header field.
* Some implementations may treat the <code>0</code><sup>th</sup>
* header field as special, i.e. as the status line returned by the HTTP
@@ -109,6 +122,9 @@
* This exception can be queried for the details of the error.
* <p>
* This method must be called before the URLConnection is connected.
+ * <p>
+ * <B>NOTE:</B> {@link #setFixedLengthStreamingMode(long)} is recommended
+ * instead of this method as it allows larger content lengths to be set.
*
* @param contentLength The number of bytes which will be written
* to the OutputStream.
@@ -135,6 +151,52 @@
fixedContentLength = contentLength;
}
+ /**
+ * This method is used to enable streaming of a HTTP request body
+ * without internal buffering, when the content length is known in
+ * advance.
+ *
+ * <P> An exception will be thrown if the application attempts to write
+ * more data than the indicated content-length, or if the application
+ * closes the OutputStream before writing the indicated amount.
+ *
+ * <P> When output streaming is enabled, authentication and redirection
+ * cannot be handled automatically. A {@linkplain HttpRetryException} will
+ * be thrown when reading the response if authentication or redirection
+ * are required. This exception can be queried for the details of the
+ * error.
+ *
+ * <P> This method must be called before the URLConnection is connected.
+ *
+ * <P> The content length set by invoking this method takes precedence
+ * over any value set by {@link #setFixedLengthStreamingMode(int)}.
+ *
+ * @param contentLength
+ * The number of bytes which will be written to the OutputStream.
+ *
+ * @throws IllegalStateException
+ * if URLConnection is already connected or if a different
+ * streaming mode is already enabled.
+ *
+ * @throws IllegalArgumentException
+ * if a content length less than zero is specified.
+ *
+ * @since 1.7
+ */
+ public void setFixedLengthStreamingMode(long contentLength) {
+ if (connected) {
+ throw new IllegalStateException("Already connected");
+ }
+ if (chunkLength != -1) {
+ throw new IllegalStateException(
+ "Chunked encoding streaming mode set");
+ }
+ if (contentLength < 0) {
+ throw new IllegalArgumentException("invalid content length");
+ }
+ fixedContentLengthLong = contentLength;
+ }
+
/* Default chunk size (including chunk header) if not specified;
* we want to keep this in sync with the one defined in
* sun.net.www.http.ChunkedOutputStream
@@ -170,7 +232,7 @@
if (connected) {
throw new IllegalStateException ("Can't set streaming mode: already connected");
}
- if (fixedContentLength != -1) {
+ if (fixedContentLength != -1 || fixedContentLengthLong != -1) {
throw new IllegalStateException ("Fixed length streaming mode set");
}
chunkLength = chunklen <=0? DEFAULT_CHUNK_SIZE : chunklen;
--- a/jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java Tue Nov 11 09:07:58 2008 +0000
+++ b/jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java Wed Nov 12 16:38:17 2008 +0000
@@ -435,8 +435,14 @@
if (streaming()) {
if (chunkLength != -1) {
requests.set ("Transfer-Encoding", "chunked");
- } else {
- requests.set ("Content-Length", String.valueOf(fixedContentLength));
+ } else { /* fixed content length */
+ if (fixedContentLengthLong != -1) {
+ requests.set ("Content-Length",
+ String.valueOf(fixedContentLengthLong));
+ } else if (fixedContentLength != -1) {
+ requests.set ("Content-Length",
+ String.valueOf(fixedContentLength));
+ }
}
} else if (poster != null) {
/* add Content-Length & POST/PUT data */
@@ -871,11 +877,17 @@
ps = (PrintStream)http.getOutputStream();
if (streaming()) {
if (strOutputStream == null) {
- if (fixedContentLength != -1) {
- strOutputStream = new StreamingOutputStream (ps, fixedContentLength);
- } else if (chunkLength != -1) {
- strOutputStream =
- new StreamingOutputStream (new ChunkedOutputStream (ps, chunkLength), -1);
+ if (chunkLength != -1) { /* chunked */
+ strOutputStream = new StreamingOutputStream(
+ new ChunkedOutputStream(ps, chunkLength), -1L);
+ } else { /* must be fixed content length */
+ long length = 0L;
+ if (fixedContentLengthLong != -1) {
+ length = fixedContentLengthLong;
+ } else if (fixedContentLength != -1) {
+ length = fixedContentLength;
+ }
+ strOutputStream = new StreamingOutputStream(ps, length);
}
}
return strOutputStream;
@@ -895,7 +907,8 @@
}
private boolean streaming () {
- return (fixedContentLength != -1) || (chunkLength != -1);
+ return (fixedContentLength != -1) || (fixedContentLengthLong != -1) ||
+ (chunkLength != -1);
}
/*
@@ -2619,8 +2632,8 @@
class StreamingOutputStream extends FilterOutputStream {
- int expected;
- int written;
+ long expected;
+ long written;
boolean closed;
boolean error;
IOException errorExcp;
@@ -2631,10 +2644,10 @@
* In the 2nd case, we make sure the expected number of
* of bytes are actually written
*/
- StreamingOutputStream (OutputStream os, int expectedLength) {
+ StreamingOutputStream (OutputStream os, long expectedLength) {
super (os);
expected = expectedLength;
- written = 0;
+ written = 0L;
closed = false;
error = false;
}
@@ -2643,7 +2656,7 @@
public void write (int b) throws IOException {
checkError();
written ++;
- if (expected != -1 && written > expected) {
+ if (expected != -1L && written > expected) {
throw new IOException ("too many bytes written");
}
out.write (b);
@@ -2658,7 +2671,7 @@
public void write (byte[] b, int off, int len) throws IOException {
checkError();
written += len;
- if (expected != -1 && written > expected) {
+ if (expected != -1L && written > expected) {
out.close ();
throw new IOException ("too many bytes written");
}
@@ -2691,7 +2704,7 @@
return;
}
closed = true;
- if (expected != -1) {
+ if (expected != -1L) {
/* not chunked */
if (written != expected) {
error = true;
--- a/jdk/src/share/classes/sun/net/www/protocol/https/HttpsURLConnectionImpl.java Tue Nov 11 09:07:58 2008 +0000
+++ b/jdk/src/share/classes/sun/net/www/protocol/https/HttpsURLConnectionImpl.java Wed Nov 12 16:38:17 2008 +0000
@@ -527,6 +527,10 @@
delegate.setFixedLengthStreamingMode(contentLength);
}
+ public void setFixedLengthStreamingMode(long contentLength) {
+ delegate.setFixedLengthStreamingMode(contentLength);
+ }
+
public void setChunkedStreamingMode (int chunklen) {
delegate.setChunkedStreamingMode(chunklen);
}
--- a/jdk/test/com/sun/net/httpserver/bugs/FixedLengthInputStream.java Tue Nov 11 09:07:58 2008 +0000
+++ b/jdk/test/com/sun/net/httpserver/bugs/FixedLengthInputStream.java Wed Nov 12 16:38:17 2008 +0000
@@ -23,7 +23,7 @@
/**
* @test
- * @bug 6756771
+ * @bug 6756771 6755625
* @summary com.sun.net.httpserver.HttpServer should handle POSTs larger than 2Gig
*/
@@ -44,34 +44,16 @@
{
static final long POST_SIZE = 4L * 1024L * 1024L * 1024L; // 4Gig
- /* Remove when CR 6755625 is fixed */
- static final String requestHeaders = ((new StringBuilder())
- .append("POST /flis/ HTTP/1.1\r\n")
- .append("User-Agent: Java/1.7.0\r\n")
- .append("Host: localhost\r\n")
- .append("Accept: text/html, image/gif, image/jpeg,")
- .append( " *; q=.2, */*; q=.2\r\n")
- .append("Content-Length: 4294967296\r\n\r\n")).toString();
-
void test(String[] args) throws IOException {
HttpServer httpServer = startHttpServer();
int port = httpServer.getAddress().getPort();
try {
- /* Uncomment & when CR 6755625 is fixed, remove socket code
URL url = new URL("http://localhost:" + port + "/flis/");
HttpURLConnection uc = (HttpURLConnection)url.openConnection();
uc.setDoOutput(true);
uc.setRequestMethod("POST");
uc.setFixedLengthStreamingMode(POST_SIZE);
OutputStream os = uc.getOutputStream();
- */
-
- Socket socket = new Socket("localhost", port);
- OutputStream os = socket.getOutputStream();
- PrintStream ps = new PrintStream(os);
- debug("Request: " + requestHeaders);
- ps.print(requestHeaders);
- ps.flush();
/* create a 32K byte array with data to POST */
int thirtyTwoK = 32 * 1024;
@@ -84,18 +66,12 @@
os.write(ba);
}
- /* Uncomment & when CR 6755625 is fixed, remove socket code
os.close();
InputStream is = uc.getInputStream();
while(is.read(ba) != -1);
is.close();
- */
- InputStream is = socket.getInputStream();
- is.read();
- socket.close();
-
- pass();
+ pass();
} finally {
httpServer.stop(0);
}