You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by gh...@apache.org on 2006/05/17 12:23:02 UTC
svn commit: r407212 - in
/incubator/harmony/enhanced/classlib/trunk/modules/luni/src:
main/java/java/net/
main/java/org/apache/harmony/luni/internal/net/www/protocol/http/
main/java/org/apache/harmony/luni/util/ test/java/tests/api/java/net/
Author: gharley
Date: Wed May 17 03:22:57 2006
New Revision: 407212
URL: http://svn.apache.org/viewcvs?rev=407212&view=rev
Log:
HARMONY 328 : Java 5 Enhancement: 2 new methods in java.net.HttpURLConnection
Modified:
incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/net/HttpURLConnection.java
incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/HttpURLConnection.java
incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/org/apache/harmony/luni/util/ExternalMessages.properties
incubator/harmony/enhanced/classlib/trunk/modules/luni/src/test/java/tests/api/java/net/HttpURLConnectionTest.java
Modified: incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/net/HttpURLConnection.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/net/HttpURLConnection.java?rev=407212&r1=407211&r2=407212&view=diff
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/net/HttpURLConnection.java (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/net/HttpURLConnection.java Wed May 17 03:22:57 2006
@@ -1,4 +1,4 @@
-/* Copyright 1998, 2005 The Apache Software Foundation or its licensors, as applicable
+/* Copyright 1998, 2006 The Apache Software Foundation or its licensors, as applicable
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@
import java.net.ProtocolException;
import java.net.URL;
+import org.apache.harmony.luni.util.Msg;
/**
* This abstract subclass of <code>URLConnection</code> defines method for
@@ -42,6 +43,12 @@
protected boolean instanceFollowRedirects = followRedirects;
private static boolean followRedirects = true;
+
+ protected int chunkLength = -1;
+
+ protected int fixedContentLength = -1;
+
+ private final static int DEFAULT_CHUNK_LENGTH = 1024;
// 2XX: generally "OK"
// 3XX: relocation/redirect
@@ -447,4 +454,57 @@
public long getHeaderFieldDate(String field, long defaultValue) {
return super.getHeaderFieldDate(field, defaultValue);
}
+
+
+ /**
+ * If length of a HTTP request body is known ahead, sets fixed length to
+ * enable streaming without buffering. Sets after connection will cause an
+ * exception.
+ *
+ * @see <code>setChunkedStreamingMode</code>
+ * @param contentLength
+ * the fixed length of the HTTP request body
+ * @throws IllegalStateException
+ * if already connected or other mode already set
+ * @throws IllegalArgumentException
+ * if contentLength is less than zero
+ */
+ public void setFixedLengthStreamingMode(int contentLength) {
+ if (super.connected) {
+ throw new IllegalStateException(Msg.getString("K0079"));
+ }
+ if (0 < chunkLength) {
+ throw new IllegalStateException(Msg.getString("KA003"));
+ }
+ if (0 > contentLength) {
+ throw new IllegalArgumentException(Msg.getString("K0051"));
+ }
+ this.fixedContentLength = contentLength;
+ }
+
+ /**
+ * If length of a HTTP request body is NOT known ahead, enable chunked
+ * transfer encoding to enable streaming without buffering. Notice that not
+ * all http servers support this mode. Sets after connection will cause an
+ * exception.
+ *
+ * @see <code>setFixedLengthStreamingMode</code>
+ * @param chunklen
+ * the length of a chunk
+ * @throws IllegalStateException
+ * if already connected or other mode already set
+ */
+ public void setChunkedStreamingMode(int chunklen) {
+ if (super.connected) {
+ throw new IllegalStateException(Msg.getString("K0079"));
+ }
+ if (0 <= fixedContentLength) {
+ throw new IllegalStateException(Msg.getString("KA003"));
+ }
+ if (0 >= chunklen) {
+ chunkLength = DEFAULT_CHUNK_LENGTH;
+ } else {
+ chunkLength = chunklen;
+ }
+ }
}
Modified: incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/HttpURLConnection.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/HttpURLConnection.java?rev=407212&r1=407211&r2=407212&view=diff
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/HttpURLConnection.java (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/HttpURLConnection.java Wed May 17 03:22:57 2006
@@ -238,21 +238,56 @@
}
private class HttpOutputStream extends OutputStream {
+
static final int MAX = 1024;
- ByteArrayOutputStream cache = new ByteArrayOutputStream(MAX + 7);
+ int cacheLength;
+
+ int defaultCacheSize = MAX;
+
+ ByteArrayOutputStream cache;
boolean writeToSocket, closed = false;
int limit;
public HttpOutputStream() {
+ cacheLength = defaultCacheSize;
+ cache = new ByteArrayOutputStream(cacheLength);
limit = -1;
}
public HttpOutputStream(int limit) {
writeToSocket = true;
this.limit = limit;
+ if (limit > 0){
+ cacheLength = limit;
+ } else {
+ // chunkLength must be larger than 3
+ defaultCacheSize = chunkLength > 3 ? chunkLength : MAX;
+ cacheLength = calculateChunkDataLength();
+ }
+ cache = new ByteArrayOutputStream(cacheLength);
+ }
+
+ // calculates the exact size of chunk data, chunk data size is chunk
+ // size minus chunk head (which writes chunk data size in HEX and
+ // "\r\n") size. For example, a string "abcd" use chunk whose size is 5
+ // must be writen to socket as "2\r\nab","2\r\ncd" ...
+ private int calculateChunkDataLength() {
+ // chunk head size is the hex string length of the cache size plus 2
+ // (which is the length of "\r\n"), it must be suitable
+ // to express the size of chunk data, as short as possible.
+ // Notices that according to RI, if chunklength is 19, chunk head
+ // length is 4 (expressed as "10\r\n"), chunk data length is 16
+ // (which real sum is 20,not 19); while if chunklength is 18, chunk
+ // head length is 3. Thus the cacheSize = chunkdataSize +
+ // sizeof(string length of chunk head in HEX) + sizeof("\r\n");
+ int bitSize = Integer.toHexString(defaultCacheSize).length();
+ // here is the calculated head size, not real size (for 19, it
+ // counts 3, not real size 4)
+ int headSize = (Integer.toHexString(defaultCacheSize - bitSize - 2).length()) + 2;
+ return defaultCacheSize - headSize;
}
private void output(String output) throws IOException {
@@ -265,19 +300,14 @@
if (limit < 0) {
if (size > 0) {
output(Integer.toHexString(size) + "\r\n");
- cache.write('\r');
- cache.write('\n');
+ socketOut.write(cache.toByteArray());
+ cache.reset();
+ output("\r\n");
}
if (close) {
- cache.write('0');
- cache.write('\r');
- cache.write('\n');
- cache.write('\r');
- cache.write('\n');
+ output("0\r\n\r\n");
}
}
- socketOut.write(cache.toByteArray());
- cache.reset();
}
}
@@ -310,8 +340,9 @@
limit--;
}
cache.write(data);
- if (writeToSocket && cache.size() >= MAX)
+ if (writeToSocket && cache.size() >= cacheLength){
sendCache(false);
+ }
}
public synchronized void write(byte[] buffer, int offset, int count)
@@ -329,17 +360,31 @@
if (count > limit)
throw new IOException(Msg.getString("K00b2"));
limit -= count;
- }
- if (!writeToSocket || cache.size() + count < MAX) {
cache.write(buffer, offset, count);
+ if (limit == 0){
+ socketOut.write(cache.toByteArray());
+ }
} else {
- if (limit < 0)
- output(Integer.toHexString(count + cache.size()) + "\r\n");
- socketOut.write(cache.toByteArray());
- cache.reset();
- socketOut.write(buffer, offset, count);
- if (limit < 0)
+ if (!writeToSocket || cache.size() + count < cacheLength) {
+ cache.write(buffer, offset, count);
+ } else {
+ output(Integer.toHexString(cacheLength) + "\r\n");
+ int writeNum = cacheLength - cache.size();
+ cache.write(buffer, offset, writeNum);
+ socketOut.write(cache.toByteArray());
output("\r\n");
+ cache.reset();
+ int left = count - writeNum;
+ int position = offset + writeNum;
+ while (left > cacheLength) {
+ output(Integer.toHexString(cacheLength) + "\r\n");
+ socketOut.write(buffer, position, cacheLength);
+ output("\r\n");
+ left = left - cacheLength;
+ position = position + cacheLength;
+ }
+ cache.write(buffer, position, left);
+ }
}
}
@@ -670,6 +715,14 @@
limit = -1;
}
}
+ // if user has set chunk/fixedLength mode, use that value
+ if (chunkLength > 0) {
+ sendChunked = true;
+ limit = -1;
+ }
+ if (fixedContentLength >= 0) {
+ limit = fixedContentLength;
+ }
if ((httpVersion > 0 && sendChunked) || limit >= 0) {
os = new HttpOutputStream(limit);
doRequest();
@@ -895,6 +948,7 @@
output.append("Transfer-Encoding: chunked\r\n");
}
+ boolean hasContentLength = false;
// then the user-specified request headers, if any
for (int i = 0; i < reqHeader.length(); i++) {
String key = reqHeader.getKey(i);
@@ -909,10 +963,26 @@
* duplicates are allowed under certain conditions see
* http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
*/
- output.append(reqHeader.get(i));
+ if (lKey.equals("content-length")) {
+ hasContentLength = true;
+ // if both setFixedLengthStreamingMode and
+ // content-length are set, use fixedContentLength
+ // first
+ output
+ .append((fixedContentLength >= 0) ? String
+ .valueOf(fixedContentLength)
+ : reqHeader.get(i));
+ } else {
+ output.append(reqHeader.get(i));
+ }
output.append("\r\n");
}
}
+ }
+ if (fixedContentLength >= 0 && !hasContentLength) {
+ output.append("content-length: ");
+ output.append(String.valueOf(fixedContentLength));
+ output.append("\r\n");
}
// end the headers
output.append("\r\n");
Modified: incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/org/apache/harmony/luni/util/ExternalMessages.properties
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/org/apache/harmony/luni/util/ExternalMessages.properties?rev=407212&r1=407211&r2=407212&view=diff
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/org/apache/harmony/luni/util/ExternalMessages.properties (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/org/apache/harmony/luni/util/ExternalMessages.properties Wed May 17 03:22:57 2006
@@ -1,4 +1,4 @@
-# Copyright 2000, 2005 The Apache Software Foundation or its licensors, as applicable
+# Copyright 2000, 2006 The Apache Software Foundation or its licensors, as applicable
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -287,3 +287,4 @@
KA000=Line too long
KA001=Argument must not be null
KA002=Unshared read of back reference
+KA003=different mode already set
\ No newline at end of file
Modified: incubator/harmony/enhanced/classlib/trunk/modules/luni/src/test/java/tests/api/java/net/HttpURLConnectionTest.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/classlib/trunk/modules/luni/src/test/java/tests/api/java/net/HttpURLConnectionTest.java?rev=407212&r1=407211&r2=407212&view=diff
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/luni/src/test/java/tests/api/java/net/HttpURLConnectionTest.java (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/luni/src/test/java/tests/api/java/net/HttpURLConnectionTest.java Wed May 17 03:22:57 2006
@@ -222,6 +222,185 @@
}
}
+ /**
+ * @tests java.net.HttpURLConnection#setFixedLengthStreamingMode_I()
+ */
+ public void test_setFixedLengthStreamingModeI() throws Exception {
+ url = new URL("http://"
+ + Support_Configuration.InetTestAddress);
+ uc = (HttpURLConnection) url.openConnection();
+ try {
+ uc.setFixedLengthStreamingMode(-1);
+ fail("should throw IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // correct
+ }
+ uc.setFixedLengthStreamingMode(0);
+ uc.setFixedLengthStreamingMode(1);
+ try {
+ uc.setChunkedStreamingMode(1);
+ fail("should throw IllegalStateException");
+ } catch (IllegalStateException e) {
+ // correct
+ }
+ uc.connect();
+ try {
+ uc.setFixedLengthStreamingMode(-1);
+ fail("should throw IllegalStateException");
+ } catch (IllegalStateException e) {
+ // correct
+ }
+ try {
+ uc.setChunkedStreamingMode(-1);
+ fail("should throw IllegalStateException");
+ } catch (IllegalStateException e) {
+ // correct
+ }
+ MockHttpConnection mock = new MockHttpConnection(url);
+ assertEquals(-1, mock.getFixedLength());
+ mock.setFixedLengthStreamingMode(0);
+ assertEquals(0, mock.getFixedLength());
+ mock.setFixedLengthStreamingMode(1);
+ assertEquals(1, mock.getFixedLength());
+ mock.setFixedLengthStreamingMode(0);
+ assertEquals(0, mock.getFixedLength());
+ }
+
+ /**
+ * @tests java.net.HttpURLConnection#setChunkedStreamingMode_I()
+ */
+ public void test_setChunkedStreamingModeI() throws Exception {
+ url = new URL("http://"
+ + Support_Configuration.InetTestAddress);
+ uc = (HttpURLConnection) url.openConnection();
+ uc.setChunkedStreamingMode(0);
+ uc.setChunkedStreamingMode(-1);
+ uc.setChunkedStreamingMode(-2);
+
+ try {
+ uc.setFixedLengthStreamingMode(-1);
+ fail("should throw IllegalStateException");
+ } catch (IllegalStateException e) {
+ // correct
+ }
+ try {
+ uc.setFixedLengthStreamingMode(1);
+ fail("should throw IllegalStateException");
+ } catch (IllegalStateException e) {
+ // correct
+ }
+ uc.connect();
+ try {
+ uc.setFixedLengthStreamingMode(-1);
+ fail("should throw IllegalStateException");
+ } catch (IllegalStateException e) {
+ // correct
+ }
+ try {
+ uc.setChunkedStreamingMode(1);
+ fail("should throw IllegalStateException");
+ } catch (IllegalStateException e) {
+ // correct
+ }
+ MockHttpConnection mock = new MockHttpConnection(url);
+ assertEquals(-1, mock.getChunkLength());
+ mock.setChunkedStreamingMode(-1);
+ int defaultChunk = mock.getChunkLength();
+ assertTrue(defaultChunk > 0);
+ mock.setChunkedStreamingMode(0);
+ assertEquals(mock.getChunkLength(), defaultChunk);
+ mock.setChunkedStreamingMode(1);
+ assertEquals(1, mock.getChunkLength());
+ }
+
+ class MockHttpConnection extends HttpURLConnection {
+
+ protected MockHttpConnection(URL url) {
+ super(url);
+ }
+
+ public void disconnect() {
+ // do nothing
+ }
+
+ public boolean usingProxy() {
+ return false;
+ }
+
+ public void connect() throws IOException {
+ // do nothing
+ }
+
+ public int getChunkLength() {
+ return super.chunkLength;
+ }
+
+ public int getFixedLength() {
+ return super.fixedContentLength;
+ }
+
+ }
+
+ /**
+ * @tests java.net.HttpURLConnection#setFixedLengthStreamingMode_I()
+ */
+ public void test_setFixedLengthStreamingModeI_effect() throws Exception {
+ String posted = "just a test";
+ URL u = new URL("http://"
+ + Support_Configuration.InetTestAddress);
+ java.net.HttpURLConnection conn = (java.net.HttpURLConnection) u
+ .openConnection();
+ conn.setDoOutput(true);
+ conn.setRequestMethod("POST");
+ conn.setFixedLengthStreamingMode(posted.length() - 1);
+ assertNull(conn.getRequestProperty("Content-length"));
+ conn.setRequestProperty("Content-length", String.valueOf(posted
+ .length()));
+ assertEquals(String.valueOf(posted.length()), conn
+ .getRequestProperty("Content-length"));
+ OutputStream out = conn.getOutputStream();
+ try {
+ out.write(posted.getBytes());
+ fail("should throw IOException");
+ } catch (IOException e) {
+ // correct, too many bytes written
+ }
+ try {
+ out.close();
+ fail("should throw IOException");
+ } catch (IOException e) {
+ // correct, too many bytes written
+ }
+ }
+
+ /**
+ * @tests java.net.HttpURLConnection#setChunkedStreamingMode_I()
+ */
+ public void test_setChunkedStreamingModeI_effect() throws Exception {
+ String posted = "just a test";
+ // for test, use half length of the string
+ int chunkSize = posted.length() / 2;
+ URL u = new URL("http://"
+ + Support_Configuration.InetTestAddress);
+ java.net.HttpURLConnection conn = (java.net.HttpURLConnection) u
+ .openConnection();
+ conn.setDoOutput(true);
+ conn.setRequestMethod("POST");
+ conn.setChunkedStreamingMode(chunkSize);
+ assertNull(conn.getRequestProperty("Transfer-Encoding"));
+ // does not take effect
+ conn.setRequestProperty("Content-length", String.valueOf(posted
+ .length() - 1));
+ assertEquals(conn.getRequestProperty("Content-length"), String
+ .valueOf(posted.length() - 1));
+ OutputStream out = conn.getOutputStream();
+ // no error occurs
+ out.write(posted.getBytes());
+ out.close();
+ // no assert here, pass if no exception thrown
+ assertTrue(conn.getResponseCode() > 0);
+ }
+
protected void setUp() {
try {
url = new URL(Support_Resources
@@ -234,8 +413,5 @@
protected void tearDown() {
uc.disconnect();
- }
-
- protected void doneSuite() {
}
}