blob: bb517ccd678286d5aa0a577bcc5880b90a585f83 [file] [log] [blame]
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package java.net;
import java.net.*;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicInteger;
import tests.support.Support_PortManager;
import tests.support.Support_TestWebServer;
public class URLConnectionTest extends junit.framework.TestCase {
private int mPort;
private Support_TestWebServer mServer;
@Override
public void setUp() throws Exception {
super.setUp();
mPort = Support_PortManager.getNextPort();
mServer = new Support_TestWebServer();
mServer.initServer(mPort, true);
}
@Override
public void tearDown() throws Exception {
super.tearDown();
mServer.close();
}
private String readFirstLine() throws Exception {
URLConnection connection = new URL("http://localhost:" + mPort + "/test1").openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String result = in.readLine();
in.close();
return result;
}
// Check that if we don't read to the end of a response, the next request on the
// recycled connection doesn't get the unread tail of the first request's response.
// http://code.google.com/p/android/issues/detail?id=2939
public void test_2939() throws Exception {
mServer.setChunked(true);
mServer.setMaxChunkSize(8);
assertTrue(readFirstLine().equals("<html>"));
assertTrue(readFirstLine().equals("<html>"));
}
enum UploadKind { CHUNKED, FIXED_LENGTH };
enum WriteKind { BYTE_BY_BYTE, SMALL_BUFFERS, LARGE_BUFFERS };
public void test_chunkedUpload_byteByByte() throws Exception {
doUpload(UploadKind.CHUNKED, WriteKind.BYTE_BY_BYTE);
}
public void test_chunkedUpload_smallBuffers() throws Exception {
doUpload(UploadKind.CHUNKED, WriteKind.SMALL_BUFFERS);
}
public void test_chunkedUpload_largeBuffers() throws Exception {
doUpload(UploadKind.CHUNKED, WriteKind.LARGE_BUFFERS);
}
public void test_fixedLengthUpload_byteByByte() throws Exception {
doUpload(UploadKind.FIXED_LENGTH, WriteKind.BYTE_BY_BYTE);
}
public void test_fixedLengthUpload_smallBuffers() throws Exception {
doUpload(UploadKind.FIXED_LENGTH, WriteKind.SMALL_BUFFERS);
}
public void test_fixedLengthUpload_largeBuffers() throws Exception {
doUpload(UploadKind.FIXED_LENGTH, WriteKind.LARGE_BUFFERS);
}
private void doUpload(UploadKind uploadKind, WriteKind writeKind) throws Exception {
int n = 512*1024;
AtomicInteger total = new AtomicInteger(0);
ServerSocket ss = startSinkServer(total);
URL url = new URL("http://localhost:" + ss.getLocalPort() + "/test1");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setRequestMethod("POST");
if (uploadKind == UploadKind.CHUNKED) {
conn.setChunkedStreamingMode(-1);
} else {
conn.setFixedLengthStreamingMode(n);
}
OutputStream out = conn.getOutputStream();
if (writeKind == WriteKind.BYTE_BY_BYTE) {
for (int i = 0; i < n; ++i) {
out.write('x');
}
} else {
byte[] buf = new byte[writeKind == WriteKind.SMALL_BUFFERS ? 256 : 64*1024];
Arrays.fill(buf, (byte) 'x');
for (int i = 0; i < n; i += buf.length) {
out.write(buf, 0, Math.min(buf.length, n - i));
}
}
out.close();
assertTrue(conn.getResponseCode() > 0);
assertEquals(uploadKind == UploadKind.CHUNKED ? -1 : n, total.get());
}
private ServerSocket startSinkServer(final AtomicInteger totalByteCount) throws Exception {
final ServerSocket ss = new ServerSocket(0);
ss.setReuseAddress(true);
Thread t = new Thread(new Runnable() {
public void run() {
try {
Socket s = ss.accept();
BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
int contentLength = -1;
String line;
int emptyLineCount = 0;
// read the headers
while ((line = in.readLine()) != null) {
if (contentLength == -1 && line.toLowerCase().startsWith("content-length: ")) {
contentLength = Integer.parseInt(line.substring(16));
}
if (line.length() == 0) {
++emptyLineCount;
// If we had a content length, the first empty line we see marks the
// start of the payload. The loop below then skips over that.
// If we didn't get a content length, we're using chunked encoding.
// The first empty line again marks the start of the payload, and the
// second empty line is a consequence of both the last chunk ending
// CRLF and the chunked-body itself ending with a CRLF. (The fact that
// a chunk of size 0 is used to mark the end isn't sufficient because
// there may also be a "trailer": header fields deferred until after
// the payload.)
if (contentLength != -1 || emptyLineCount == 2) {
break;
}
}
}
// Skip the payload in the setFixedLengthStreamingMode case.
// In the chunked case, we read all the chunked data in the loop above.
long left = contentLength;
while (left > 0) {
left -= in.skip(left);
}
// Send a response to unblock the client.
totalByteCount.set(contentLength);
OutputStream out = s.getOutputStream();
out.write("HTTP/1.1 200 OK\r\n\r\n".getBytes());
out.flush();
out.close();
// Check there wasn't junk at the end.
try {
assertEquals(-1, in.read());
} catch (SocketException expected) {
// The client already closed the connection.
}
} catch (Exception ex) {
throw new RuntimeException("server died unexpectedly", ex);
}
}
});
t.start();
return ss;
}
}