From e9076296a9028294a8499a170264ab456b36658f Mon Sep 17 00:00:00 2001 From: Chris Hegarty Date: Wed, 12 Nov 2008 16:38:17 +0000 Subject: [PATCH] 6755625: Add HttpURLConnection.setFixedLengthStreamingMode(long) Reviewed-by: jccollet --- .../https/HttpsURLConnectionOldImpl.java | 4 ++ .../classes/java/net/HttpURLConnection.java | 64 ++++++++++++++++++- .../www/protocol/http/HttpURLConnection.java | 43 ++++++++----- .../https/HttpsURLConnectionImpl.java | 4 ++ .../bugs/FixedLengthInputStream.java | 28 +------- 5 files changed, 101 insertions(+), 42 deletions(-) diff --git a/jdk/src/share/classes/com/sun/net/ssl/internal/www/protocol/https/HttpsURLConnectionOldImpl.java b/jdk/src/share/classes/com/sun/net/ssl/internal/www/protocol/https/HttpsURLConnectionOldImpl.java index 8b34a2c3ceb..0e92d301f2f 100644 --- a/jdk/src/share/classes/com/sun/net/ssl/internal/www/protocol/https/HttpsURLConnectionOldImpl.java +++ b/jdk/src/share/classes/com/sun/net/ssl/internal/www/protocol/https/HttpsURLConnectionOldImpl.java @@ -497,6 +497,10 @@ public class HttpsURLConnectionOldImpl delegate.setFixedLengthStreamingMode(contentLength); } + public void setFixedLengthStreamingMode(long contentLength) { + delegate.setFixedLengthStreamingMode(contentLength); + } + public void setChunkedStreamingMode (int chunklen) { delegate.setChunkedStreamingMode(chunklen); } diff --git a/jdk/src/share/classes/java/net/HttpURLConnection.java b/jdk/src/share/classes/java/net/HttpURLConnection.java index eb21c7f3ba4..f35c3efa795 100644 --- a/jdk/src/share/classes/java/net/HttpURLConnection.java +++ b/jdk/src/share/classes/java/net/HttpURLConnection.java @@ -73,10 +73,23 @@ abstract public class HttpURLConnection extends URLConnection { * The fixed content-length when using fixed-length streaming mode. * A value of -1 means fixed-length streaming mode is disabled * for output. + * + *

NOTE: {@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 nth header field. * Some implementations may treat the 0th @@ -109,6 +122,9 @@ abstract public class HttpURLConnection extends URLConnection { * This exception can be queried for the details of the error. *

* This method must be called before the URLConnection is connected. + *

+ * NOTE: {@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 @@ abstract public class HttpURLConnection extends URLConnection { 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. + * + *

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. + * + *

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. + * + *

This method must be called before the URLConnection is connected. + * + *

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 @@ abstract public class HttpURLConnection extends URLConnection { 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; diff --git a/jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java b/jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java index 5aec18973aa..6f3250b30eb 100644 --- a/jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java +++ b/jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java @@ -435,8 +435,14 @@ public class HttpURLConnection extends java.net.HttpURLConnection { 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 @@ public class HttpURLConnection extends java.net.HttpURLConnection { 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 @@ public class HttpURLConnection extends java.net.HttpURLConnection { } private boolean streaming () { - return (fixedContentLength != -1) || (chunkLength != -1); + return (fixedContentLength != -1) || (fixedContentLengthLong != -1) || + (chunkLength != -1); } /* @@ -2619,8 +2632,8 @@ public class HttpURLConnection extends java.net.HttpURLConnection { class StreamingOutputStream extends FilterOutputStream { - int expected; - int written; + long expected; + long written; boolean closed; boolean error; IOException errorExcp; @@ -2631,10 +2644,10 @@ public class HttpURLConnection extends java.net.HttpURLConnection { * 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 class HttpURLConnection extends java.net.HttpURLConnection { 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 class HttpURLConnection extends java.net.HttpURLConnection { 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 @@ public class HttpURLConnection extends java.net.HttpURLConnection { return; } closed = true; - if (expected != -1) { + if (expected != -1L) { /* not chunked */ if (written != expected) { error = true; diff --git a/jdk/src/share/classes/sun/net/www/protocol/https/HttpsURLConnectionImpl.java b/jdk/src/share/classes/sun/net/www/protocol/https/HttpsURLConnectionImpl.java index 55b1859ba15..c2a37012822 100644 --- a/jdk/src/share/classes/sun/net/www/protocol/https/HttpsURLConnectionImpl.java +++ b/jdk/src/share/classes/sun/net/www/protocol/https/HttpsURLConnectionImpl.java @@ -527,6 +527,10 @@ public class HttpsURLConnectionImpl delegate.setFixedLengthStreamingMode(contentLength); } + public void setFixedLengthStreamingMode(long contentLength) { + delegate.setFixedLengthStreamingMode(contentLength); + } + public void setChunkedStreamingMode (int chunklen) { delegate.setChunkedStreamingMode(chunklen); } diff --git a/jdk/test/com/sun/net/httpserver/bugs/FixedLengthInputStream.java b/jdk/test/com/sun/net/httpserver/bugs/FixedLengthInputStream.java index 76a71fc120b..d5cdfdf2533 100644 --- a/jdk/test/com/sun/net/httpserver/bugs/FixedLengthInputStream.java +++ b/jdk/test/com/sun/net/httpserver/bugs/FixedLengthInputStream.java @@ -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 @@ public class FixedLengthInputStream { 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 @@ public class FixedLengthInputStream 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); }