This commit is contained in:
Chris Hegarty 2008-11-13 09:40:51 +00:00
commit bb833cb3e5
5 changed files with 101 additions and 42 deletions

View file

@ -497,6 +497,10 @@ public class HttpsURLConnectionOldImpl
delegate.setFixedLengthStreamingMode(contentLength); delegate.setFixedLengthStreamingMode(contentLength);
} }
public void setFixedLengthStreamingMode(long contentLength) {
delegate.setFixedLengthStreamingMode(contentLength);
}
public void setChunkedStreamingMode (int chunklen) { public void setChunkedStreamingMode (int chunklen) {
delegate.setChunkedStreamingMode(chunklen); delegate.setChunkedStreamingMode(chunklen);
} }

View file

@ -73,10 +73,23 @@ abstract public class HttpURLConnection extends URLConnection {
* The fixed content-length when using fixed-length streaming mode. * The fixed content-length when using fixed-length streaming mode.
* A value of <code>-1</code> means fixed-length streaming mode is disabled * A value of <code>-1</code> means fixed-length streaming mode is disabled
* for output. * 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 * @since 1.5
*/ */
protected int fixedContentLength = -1; 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. * Returns the key for the <code>n</code><sup>th</sup> header field.
* Some implementations may treat the <code>0</code><sup>th</sup> * Some implementations may treat the <code>0</code><sup>th</sup>
@ -109,6 +122,9 @@ abstract public class HttpURLConnection extends URLConnection {
* This exception can be queried for the details of the error. * This exception can be queried for the details of the error.
* <p> * <p>
* This method must be called before the URLConnection is connected. * 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 * @param contentLength The number of bytes which will be written
* to the OutputStream. * to the OutputStream.
@ -135,6 +151,52 @@ abstract public class HttpURLConnection extends URLConnection {
fixedContentLength = contentLength; 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; /* Default chunk size (including chunk header) if not specified;
* we want to keep this in sync with the one defined in * we want to keep this in sync with the one defined in
* sun.net.www.http.ChunkedOutputStream * sun.net.www.http.ChunkedOutputStream
@ -170,7 +232,7 @@ abstract public class HttpURLConnection extends URLConnection {
if (connected) { if (connected) {
throw new IllegalStateException ("Can't set streaming mode: already 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"); throw new IllegalStateException ("Fixed length streaming mode set");
} }
chunkLength = chunklen <=0? DEFAULT_CHUNK_SIZE : chunklen; chunkLength = chunklen <=0? DEFAULT_CHUNK_SIZE : chunklen;

View file

@ -435,8 +435,14 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
if (streaming()) { if (streaming()) {
if (chunkLength != -1) { if (chunkLength != -1) {
requests.set ("Transfer-Encoding", "chunked"); requests.set ("Transfer-Encoding", "chunked");
} else { } else { /* fixed content length */
requests.set ("Content-Length", String.valueOf(fixedContentLength)); 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) { } else if (poster != null) {
/* add Content-Length & POST/PUT data */ /* add Content-Length & POST/PUT data */
@ -871,11 +877,17 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
ps = (PrintStream)http.getOutputStream(); ps = (PrintStream)http.getOutputStream();
if (streaming()) { if (streaming()) {
if (strOutputStream == null) { if (strOutputStream == null) {
if (fixedContentLength != -1) { if (chunkLength != -1) { /* chunked */
strOutputStream = new StreamingOutputStream (ps, fixedContentLength); strOutputStream = new StreamingOutputStream(
} else if (chunkLength != -1) { new ChunkedOutputStream(ps, chunkLength), -1L);
strOutputStream = } else { /* must be fixed content length */
new StreamingOutputStream (new ChunkedOutputStream (ps, chunkLength), -1); long length = 0L;
if (fixedContentLengthLong != -1) {
length = fixedContentLengthLong;
} else if (fixedContentLength != -1) {
length = fixedContentLength;
}
strOutputStream = new StreamingOutputStream(ps, length);
} }
} }
return strOutputStream; return strOutputStream;
@ -895,7 +907,8 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
} }
private boolean streaming () { 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 { class StreamingOutputStream extends FilterOutputStream {
int expected; long expected;
int written; long written;
boolean closed; boolean closed;
boolean error; boolean error;
IOException errorExcp; IOException errorExcp;
@ -2631,10 +2644,10 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
* In the 2nd case, we make sure the expected number of * In the 2nd case, we make sure the expected number of
* of bytes are actually written * of bytes are actually written
*/ */
StreamingOutputStream (OutputStream os, int expectedLength) { StreamingOutputStream (OutputStream os, long expectedLength) {
super (os); super (os);
expected = expectedLength; expected = expectedLength;
written = 0; written = 0L;
closed = false; closed = false;
error = false; error = false;
} }
@ -2643,7 +2656,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
public void write (int b) throws IOException { public void write (int b) throws IOException {
checkError(); checkError();
written ++; written ++;
if (expected != -1 && written > expected) { if (expected != -1L && written > expected) {
throw new IOException ("too many bytes written"); throw new IOException ("too many bytes written");
} }
out.write (b); 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 { public void write (byte[] b, int off, int len) throws IOException {
checkError(); checkError();
written += len; written += len;
if (expected != -1 && written > expected) { if (expected != -1L && written > expected) {
out.close (); out.close ();
throw new IOException ("too many bytes written"); throw new IOException ("too many bytes written");
} }
@ -2691,7 +2704,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
return; return;
} }
closed = true; closed = true;
if (expected != -1) { if (expected != -1L) {
/* not chunked */ /* not chunked */
if (written != expected) { if (written != expected) {
error = true; error = true;

View file

@ -527,6 +527,10 @@ public class HttpsURLConnectionImpl
delegate.setFixedLengthStreamingMode(contentLength); delegate.setFixedLengthStreamingMode(contentLength);
} }
public void setFixedLengthStreamingMode(long contentLength) {
delegate.setFixedLengthStreamingMode(contentLength);
}
public void setChunkedStreamingMode (int chunklen) { public void setChunkedStreamingMode (int chunklen) {
delegate.setChunkedStreamingMode(chunklen); delegate.setChunkedStreamingMode(chunklen);
} }

View file

@ -23,7 +23,7 @@
/** /**
* @test * @test
* @bug 6756771 * @bug 6756771 6755625
* @summary com.sun.net.httpserver.HttpServer should handle POSTs larger than 2Gig * @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 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 { void test(String[] args) throws IOException {
HttpServer httpServer = startHttpServer(); HttpServer httpServer = startHttpServer();
int port = httpServer.getAddress().getPort(); int port = httpServer.getAddress().getPort();
try { try {
/* Uncomment & when CR 6755625 is fixed, remove socket code
URL url = new URL("http://localhost:" + port + "/flis/"); URL url = new URL("http://localhost:" + port + "/flis/");
HttpURLConnection uc = (HttpURLConnection)url.openConnection(); HttpURLConnection uc = (HttpURLConnection)url.openConnection();
uc.setDoOutput(true); uc.setDoOutput(true);
uc.setRequestMethod("POST"); uc.setRequestMethod("POST");
uc.setFixedLengthStreamingMode(POST_SIZE); uc.setFixedLengthStreamingMode(POST_SIZE);
OutputStream os = uc.getOutputStream(); 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 */ /* create a 32K byte array with data to POST */
int thirtyTwoK = 32 * 1024; int thirtyTwoK = 32 * 1024;
@ -84,18 +66,12 @@ public class FixedLengthInputStream
os.write(ba); os.write(ba);
} }
/* Uncomment & when CR 6755625 is fixed, remove socket code
os.close(); os.close();
InputStream is = uc.getInputStream(); InputStream is = uc.getInputStream();
while(is.read(ba) != -1); while(is.read(ba) != -1);
is.close(); is.close();
*/
InputStream is = socket.getInputStream(); pass();
is.read();
socket.close();
pass();
} finally { } finally {
httpServer.stop(0); httpServer.stop(0);
} }