changeset 705:a85ef87f9eaa

6755625: Add HttpURLConnection.setFixedLengthStreamingMode(long) Reviewed-by: jccollet
author chegar
date Wed, 12 Nov 2008 16:38:17 +0000
parents e81b47f0b40f
children 84bd7fd5fb65
files src/share/classes/com/sun/net/ssl/internal/www/protocol/https/HttpsURLConnectionOldImpl.java src/share/classes/java/net/HttpURLConnection.java src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java src/share/classes/sun/net/www/protocol/https/HttpsURLConnectionImpl.java test/com/sun/net/httpserver/bugs/FixedLengthInputStream.java
diffstat 5 files changed, 101 insertions(+), 42 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/com/sun/net/ssl/internal/www/protocol/https/HttpsURLConnectionOldImpl.java	Tue Nov 11 09:07:58 2008 +0000
+++ b/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/src/share/classes/java/net/HttpURLConnection.java	Tue Nov 11 09:07:58 2008 +0000
+++ b/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/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java	Tue Nov 11 09:07:58 2008 +0000
+++ b/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/src/share/classes/sun/net/www/protocol/https/HttpsURLConnectionImpl.java	Tue Nov 11 09:07:58 2008 +0000
+++ b/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/test/com/sun/net/httpserver/bugs/FixedLengthInputStream.java	Tue Nov 11 09:07:58 2008 +0000
+++ b/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);
         }