| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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 org.apache.harmony.tests.internal.net.www.protocol.http; |
| |
| import java.io.ByteArrayOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.lang.reflect.InvocationTargetException; |
| import java.net.HttpURLConnection; |
| import java.net.ServerSocket; |
| import java.net.Socket; |
| import java.net.SocketTimeoutException; |
| import java.net.URI; |
| import java.net.URISyntaxException; |
| import java.net.URL; |
| |
| import junit.framework.TestCase; |
| |
| import org.apache.harmony.luni.internal.net.www.protocol.http.HttpConnection; |
| import org.apache.harmony.luni.internal.net.www.protocol.http.HttpConnectionManager; |
| |
| import tests.support.Support_HttpServer; |
| import tests.support.Support_HttpServerSocket; |
| import tests.support.Support_Jetty; |
| import tests.support.Support_PortManager; |
| import tests.support.Support_URLConnector; |
| |
| /** |
| * Tests for <code>HttpURLConnection</code> persistence. |
| * These tests depends on internal implementation. |
| */ |
| public class PersistenceTest extends TestCase { |
| |
| private static final boolean DEBUG = false; |
| |
| private final static Object bound = new Object(); |
| |
| private static int port; |
| |
| static { |
| // run-once set up |
| try { |
| port = Support_Jetty.startDefaultHttpServer(); |
| } catch (Exception e) { |
| fail("Exception during setup jetty : " + e.getMessage()); |
| } |
| } |
| |
| static class MockServer extends Thread { |
| ServerSocket serverSocket; |
| boolean accepted = false; |
| boolean started = false; |
| |
| public MockServer(String name) throws IOException { |
| super(name); |
| serverSocket = new ServerSocket(0); |
| serverSocket.setSoTimeout(5000); |
| } |
| |
| public int port() { |
| return serverSocket.getLocalPort(); |
| } |
| |
| @Override |
| public void run() { |
| try { |
| synchronized (bound) { |
| started = true; |
| bound.notify(); |
| } |
| try { |
| serverSocket.accept().close(); |
| accepted = true; |
| } catch (SocketTimeoutException ignore) { |
| } |
| serverSocket.close(); |
| } catch (IOException e) { |
| throw new RuntimeException(e); |
| } |
| } |
| } |
| |
| static class MockHTTPServer extends MockServer { |
| // HTTP response codes |
| static final int OK_CODE = 200; |
| static final int NOT_FOUND_CODE = 404; |
| // how many times persistent connection will be used |
| // by server |
| int persUses; |
| // result code to be sent to client |
| int responseCode; |
| // response content to be sent to client |
| String response = "<html></html>"; |
| // client's POST message |
| String clientPost = "Hello from client!"; |
| |
| public MockHTTPServer(String name, int persUses) throws IOException { |
| this(name, persUses, OK_CODE); |
| } |
| |
| public MockHTTPServer(String name, int persUses, |
| int responseCode) throws IOException { |
| super(name); |
| this.persUses = persUses; |
| this.responseCode = responseCode; |
| } |
| |
| public int port() { |
| return serverSocket.getLocalPort(); |
| } |
| |
| @Override |
| public void run() { |
| try { |
| synchronized (bound) { |
| started = true; |
| bound.notify(); |
| } |
| InputStream is = null; |
| Socket client = null; |
| try { |
| client = serverSocket.accept(); |
| accepted = true; |
| for (int i=0; i<persUses; i++) { |
| if (DEBUG) { |
| System.out.println("*** Using connection for " |
| + (i+1) + " time ***"); |
| } |
| byte[] buff = new byte[1024]; |
| is = client.getInputStream(); |
| int num = 0; // number of read bytes |
| int bytik; // read byte value |
| boolean wasEOL = false; |
| // read header (until empty string) |
| while (((bytik = is.read()) > 0)) { |
| if (bytik == '\r') { |
| bytik = is.read(); |
| } |
| if (wasEOL && (bytik == '\n')) { |
| break; |
| } |
| wasEOL = (bytik == '\n'); |
| buff[num++] = (byte) bytik; |
| } |
| //int num = is.read(buff); |
| String message = new String(buff, 0, num); |
| if (DEBUG) { |
| System.out.println("---- Server got request: ----\n" |
| + message + "-----------------------------"); |
| } |
| |
| // Act as Server (not Proxy) side |
| if (message.startsWith("POST")) { |
| // client connection sent some data |
| // if the data was not read with header |
| if (DEBUG) { |
| System.out.println( |
| "---- Server read client's data: ----"); |
| } |
| num = is.read(buff); |
| message = new String(buff, 0, num); |
| if (DEBUG) { |
| System.out.println("'" + message + "'"); |
| System.out.println( |
| "------------------------------------"); |
| } |
| // check the received data |
| assertEquals(clientPost, message); |
| } |
| |
| client.getOutputStream().write(( |
| "HTTP/1.1 " + responseCode + " OK\n" |
| + "Content-type: text/html\n" |
| + "Content-length: " |
| + response.length() + "\n\n" |
| + response).getBytes()); |
| |
| if (responseCode != OK_CODE) { |
| // wait while test case check closed connection |
| // and interrupt this thread |
| try { |
| while (!isInterrupted()) { |
| Thread.sleep(1000); |
| } |
| } catch (Exception ignore) { } |
| } |
| } |
| } catch (SocketTimeoutException ignore) { |
| ignore.printStackTrace(); |
| } finally { |
| if (is != null) { |
| is.close(); |
| } |
| if (client != null) { |
| client.close(); |
| } |
| serverSocket.close(); |
| } |
| } catch (IOException e) { |
| throw new RuntimeException(e); |
| } |
| } |
| } |
| |
| public void setUp() { |
| if (DEBUG) { |
| System.out.println("\n=============================="); |
| System.out.println("===== Execution: "+getName()); |
| System.out.println("=============================="); |
| } |
| } |
| |
| /** |
| * Test that an HTTP connection persists |
| */ |
| public void testConnectionsPersist() throws IOException, InterruptedException { |
| int initialFreeConnections = HttpConnectionManager.getDefault().numFreeConnections(); |
| MockServer httpServer = |
| new MockServer("ServerSocket for HttpURLConnectionTest"); |
| httpServer.start(); |
| synchronized(bound) { |
| if (!httpServer.started) { |
| bound.wait(5000); |
| } |
| } |
| HttpURLConnection c = (HttpURLConnection) |
| new URL("http://127.0.0.1:" + httpServer.port()).openConnection(); |
| c.setDoOutput(true); |
| c.setRequestMethod("POST"); |
| c.getOutputStream().close(); |
| assertEquals(initialFreeConnections + 1, HttpConnectionManager.getDefault().numFreeConnections()); |
| c = (HttpURLConnection) |
| new URL("http://127.0.0.1:" + httpServer.port()).openConnection(); |
| c.setDoOutput(true); |
| c.setRequestMethod("POST"); |
| OutputStream os = c.getOutputStream(); |
| assertEquals(initialFreeConnections, HttpConnectionManager.getDefault().numFreeConnections()); |
| os.close(); |
| assertEquals(initialFreeConnections + 1, HttpConnectionManager.getDefault().numFreeConnections()); |
| httpServer.join(); |
| } |
| |
| /** |
| * Test that multiple HTTP connections persist |
| */ |
| public void testMultipleConnectionsPersist() throws IOException, InterruptedException { |
| int initialFreeConnections = HttpConnectionManager.getDefault().numFreeConnections(); |
| MockServer httpServer = |
| new MockServer("ServerSocket for HttpURLConnectionTest"); |
| httpServer.start(); |
| synchronized(bound) { |
| if (!httpServer.started) { |
| bound.wait(5000); |
| } |
| } |
| MockServer httpServer2 = |
| new MockServer("ServerSocket for HttpURLConnectionTest"); |
| httpServer2.start(); |
| synchronized(bound) { |
| if (!httpServer2.started) { |
| bound.wait(5000); |
| } |
| } |
| HttpURLConnection c = (HttpURLConnection) |
| new URL("http://127.0.0.1:" + httpServer.port()).openConnection(); |
| c.setDoOutput(true); |
| c.setRequestMethod("POST"); |
| OutputStream os = c.getOutputStream(); |
| HttpURLConnection c2 = (HttpURLConnection) |
| new URL("http://127.0.0.1:" + httpServer2.port()).openConnection(); |
| c2.setDoOutput(true); |
| c2.setRequestMethod("POST"); |
| OutputStream os2 = c2.getOutputStream(); |
| os.close(); |
| os2.close(); |
| assertEquals(initialFreeConnections + 2, HttpConnectionManager.getDefault().numFreeConnections()); |
| |
| c = (HttpURLConnection) |
| new URL("http://127.0.0.1:" + httpServer.port()).openConnection(); |
| c.setDoOutput(true); |
| c.setRequestMethod("POST"); |
| os = c.getOutputStream(); |
| assertEquals(initialFreeConnections + 1, HttpConnectionManager.getDefault().numFreeConnections()); |
| c2 = (HttpURLConnection) |
| new URL("http://127.0.0.1:" + httpServer2.port()).openConnection(); |
| c2.setDoOutput(true); |
| c2.setRequestMethod("POST"); |
| os2 = c2.getOutputStream(); |
| assertEquals(initialFreeConnections, HttpConnectionManager.getDefault().numFreeConnections()); |
| os.close(); |
| os2.close(); |
| assertEquals(initialFreeConnections + 2, HttpConnectionManager.getDefault().numFreeConnections()); |
| httpServer.join(); |
| httpServer2.join(); |
| } |
| |
| /** |
| * Test that a closed HTTP connection is not kept in the pool of live connections |
| * @throws URISyntaxException |
| */ |
| public void testForcedClosure() throws Exception { |
| int initialFreeConnections = HttpConnectionManager.getDefault().numFreeConnections(); |
| MockServer httpServer = |
| new MockServer("ServerSocket for HttpURLConnectionTest"); |
| httpServer.start(); |
| synchronized(bound) { |
| if (!httpServer.started) { |
| bound.wait(5000); |
| } |
| } |
| HttpConnection connection = HttpConnectionManager.getDefault().getConnection(new URI("http://127.0.0.1:" + httpServer.port()), 1000); |
| HttpConnectionManager.getDefault().returnConnectionToPool(connection); |
| assertEquals(initialFreeConnections + 1, HttpConnectionManager.getDefault().numFreeConnections()); |
| HttpURLConnection c = (HttpURLConnection) |
| new URL("http://127.0.0.1:" + httpServer.port()).openConnection(); |
| c.setDoOutput(true); |
| c.setRequestMethod("POST"); |
| c.getOutputStream(); |
| assertEquals(initialFreeConnections, HttpConnectionManager.getDefault().numFreeConnections()); |
| c.disconnect(); |
| assertEquals(initialFreeConnections, HttpConnectionManager.getDefault().numFreeConnections()); |
| } |
| |
| /** |
| * Test that a connection is closed if the client does not read all the data |
| * @throws Exception |
| */ |
| public void testIncorrectUsage() throws Exception { |
| int initialFreeConnections = HttpConnectionManager.getDefault().numFreeConnections(); |
| HttpURLConnection c = (HttpURLConnection) |
| new URL("http://localhost:" + port).openConnection(); |
| c.setDoOutput(true); |
| c.setRequestMethod("GET"); |
| InputStream is = c.getInputStream(); // get the input stream but don't finish reading it |
| is.close(); |
| assertEquals(initialFreeConnections, HttpConnectionManager.getDefault().numFreeConnections()); |
| } |
| |
| /** |
| * Test that a connection is closed in case of unsuccessful connection. |
| * Here client gets NOT_FOUND response. |
| */ |
| public void testConnectionNonPersistence() throws Exception { |
| MockHTTPServer httpServer = |
| new MockHTTPServer("HTTP Server for NOT FOUND checking", 1, |
| MockHTTPServer.NOT_FOUND_CODE); |
| httpServer.start(); |
| synchronized(bound) { |
| if (!httpServer.started) { |
| bound.wait(5000); |
| } |
| } |
| |
| int initialFreeConnections |
| = HttpConnectionManager.getDefault().numFreeConnections(); |
| |
| HttpURLConnection c = (HttpURLConnection) |
| new URL("http://localhost:"+httpServer.port()).openConnection(); |
| if (DEBUG) { |
| System.out.println("Actual connection class: "+c.getClass()); |
| } |
| |
| c.setDoInput(true); |
| c.setConnectTimeout(5000); |
| c.setReadTimeout(5000); |
| try { |
| c.getInputStream(); |
| fail("Expected IOException was not thrown"); |
| } catch (IOException expected) { |
| // expected |
| } finally { |
| httpServer.interrupt(); |
| } |
| assertEquals("Unsuccessful connection was not closed", |
| initialFreeConnections, |
| HttpConnectionManager.getDefault().numFreeConnections()); |
| } |
| |
| /** |
| * Test that a connection is not closed if the client does read all the data |
| * @throws Exception |
| */ |
| public void testCorrectUsage() throws Exception { |
| int initialFreeConnections = HttpConnectionManager.getDefault().numFreeConnections(); |
| HttpURLConnection c = (HttpURLConnection) |
| new URL("http://localhost:" + port).openConnection(); |
| c.setDoOutput(true); |
| c.setRequestMethod("GET"); |
| InputStream is = c.getInputStream(); |
| byte[] buffer = new byte[128]; |
| int totalBytes = 0; |
| int bytesRead = 0; |
| while((bytesRead = is.read(buffer)) > 0){ |
| totalBytes += bytesRead; |
| } |
| is.close(); |
| assertEquals(initialFreeConnections + 1, HttpConnectionManager.getDefault().numFreeConnections()); |
| |
| HttpURLConnection c2 = (HttpURLConnection) |
| new URL("http://localhost:" + port).openConnection(); |
| c2.setDoOutput(true); |
| c2.setRequestMethod("GET"); |
| InputStream is2 = c2.getInputStream(); |
| byte[] buffer2 = new byte[128]; |
| int totalBytes2 = 0; |
| int bytesRead2 = 0; |
| while((bytesRead2 = is2.read(buffer2)) > 0){ |
| totalBytes2 += bytesRead2; |
| } |
| is2.close(); |
| assertEquals(initialFreeConnections + 1, HttpConnectionManager.getDefault().numFreeConnections()); |
| assertEquals(totalBytes, totalBytes2); |
| } |
| |
| /** |
| * Test that the http.keepAlive system property has the required effect on persistent connections |
| */ |
| public void testKeepAliveSystemProperty() throws IOException, InterruptedException { |
| System.setProperty("http.keepAlive", "false"); |
| MockServer httpServer = |
| new MockServer("ServerSocket for HttpURLConnectionTest"); |
| httpServer.start(); |
| synchronized(bound) { |
| if (!httpServer.started) { |
| bound.wait(5000); |
| } |
| } |
| HttpURLConnection c = (HttpURLConnection) |
| new URL("http://127.0.0.1:" + httpServer.port()).openConnection(); |
| c.setDoOutput(true); |
| c.setRequestMethod("POST"); |
| OutputStream os = c.getOutputStream(); |
| os.close(); |
| assertEquals(0, HttpConnectionManager.getDefault().numFreeConnections()); |
| httpServer.join(); |
| System.setProperty("http.keepAlive", "true"); |
| } |
| |
| /** |
| * Test that the http.maxConnections system property has the required effect on persistent connections |
| * @throws Exception |
| */ |
| public void testMaxConnectionsSystemProperty() throws Exception { |
| int initialFreeConnections = HttpConnectionManager.getDefault().numFreeConnections(); |
| System.setProperty("http.maxConnections", "2"); |
| HttpURLConnection c = (HttpURLConnection) |
| new URL("http://localhost:" + port).openConnection(); |
| c.setDoOutput(true); |
| c.setRequestMethod("GET"); |
| InputStream is = c.getInputStream(); |
| c = (HttpURLConnection) |
| new URL("http://localhost:" + port).openConnection(); |
| c.setDoOutput(true); |
| c.setRequestMethod("GET"); |
| InputStream is2 = c.getInputStream(); |
| c = (HttpURLConnection) |
| new URL("http://localhost:" + port).openConnection(); |
| c.setDoOutput(true); |
| c.setRequestMethod("GET"); |
| InputStream is3 = c.getInputStream(); |
| byte[] buffer = new byte[128]; |
| while(is.read(buffer) > 0){ |
| } |
| while(is2.read(buffer) > 0){ |
| } |
| while(is3.read(buffer) > 0){ |
| } |
| is.close(); |
| is2.close(); |
| is3.close(); |
| assertEquals(initialFreeConnections + 2, HttpConnectionManager.getDefault().numFreeConnections()); |
| } |
| |
| public void testClosingOutputStream() throws IOException { |
| // create a serversocket |
| Support_HttpServerSocket serversocket = new Support_HttpServerSocket(); |
| int portNumber = Support_PortManager.getNextPort(); |
| // create a client connector |
| Support_URLConnector connector = new Support_URLConnector(); |
| Support_HttpServer server = new Support_HttpServer(serversocket, this); |
| |
| server.startServer(portNumber); |
| |
| |
| ByteArrayOutputStream bout = new ByteArrayOutputStream(); |
| InputStream is; |
| int c; |
| final String postTestUrl = "http://localhost:" + portNumber |
| + Support_HttpServer.POSTTEST; |
| |
| String toWrite = "abcdef"; |
| connector.open(postTestUrl); |
| OutputStream out = connector.getOutputStream(); |
| System.out.println("Output stream = " + out.hashCode()); |
| out.write(toWrite.getBytes("ISO8859_1")); |
| out.close(); |
| is = connector.getInputStream(); |
| bout.reset(); |
| do { |
| c = is.read(); |
| if (c != -1) { |
| bout.write(c); |
| } |
| } while (c != -1); |
| is.close(); |
| connector.close(); |
| String result = new String(bout.toByteArray(), "ISO8859_1"); |
| assertTrue("Error sending data 1: " + result, toWrite |
| .equals(result)); |
| |
| toWrite = "zyxwvuts"; |
| connector.open(postTestUrl); |
| connector.setRequestProperty("Transfer-encoding", "chunked"); |
| out = connector.getOutputStream(); |
| System.out.println("Output stream = " + out.hashCode()); |
| out.write(toWrite.getBytes("ISO8859_1")); |
| out.close(); |
| is = connector.getInputStream(); |
| bout.reset(); |
| do { |
| c = is.read(); |
| if (c != -1) { |
| bout.write(c); |
| } |
| } while (c != -1); |
| is.close(); |
| connector.close(); |
| result = new String(bout.toByteArray(), "ISO8859_1"); |
| assertEquals(toWrite, result); |
| |
| } |
| |
| } |