Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8025710

Proxied HTTPS connections reused by HttpClient can send CONNECT to the server

    XMLWordPrintable

    Details

    • Type: Bug
    • Status: Closed
    • Priority: P3
    • Resolution: Fixed
    • Affects Version/s: 6u34, 7u21, 7u40, 8, 9
    • Fix Version/s: 9
    • Component/s: core-libs
    • Subcomponent:
    • Resolved In Build:
      b11
    • OS:
      linux
    • Verification:
      Verified

      Backports

        Description

        FULL PRODUCT VERSION :
        java version "1.7.0_40"
        Java(TM) SE Runtime Environment (build 1.7.0_40-b43)
        Java HotSpot(TM) 64-Bit Server VM (build 24.0-b56, mixed mode)

        This bug also exists in 1.6.0_34 and 1.7.0_21:

        java version "1.6.0_34"
        Java(TM) SE Runtime Environment (build 1.6.0_34-b04)
        Java HotSpot(TM) 64-Bit Server VM (build 20.9-b04, mixed mode)

        java version "1.7.0_21"
        Java(TM) SE Runtime Environment (build 1.7.0_21-b11)
        Java HotSpot(TM) 64-Bit Server VM (build 23.21-b01, mixed mode)


        ADDITIONAL OS VERSION INFORMATION :
        Linux slawrance-wsl 2.6.32-45-generic #104-Ubuntu SMP Tue Feb 19 21:20:09 UTC 2013 x86_64 GNU/Linux
        This also happens in RedHat Enterprise Linux 4 and 5, at least

        EXTRA RELEVANT SYSTEM CONFIGURATION :
        This bug occurs in an environment where a HTTP proxy server is used for outbound connections.

        A DESCRIPTION OF THE PROBLEM :
        When a proxied https request is reused in the JDK's built-in HttpsURLConnection, a closed connection will cause the retry code to inadvertently send the 'CONNECT' request meant for the proxy to the remote endpoint via the new proxied connection.

          From a high level, the second request in a reused request where the remote endpoint had closed down its output stream causes an error handler in sun.net.www.http.HttpClient to try it again within a new proxy connection. It does establish a new proxied connection, but it ends up sending the wrong request through the established proxied connection. Instead of sending the intended request, it sends the http request that was used to establish the second connection to the proxy.

        That bug in the error handler in HttpsURLConnection is very subtle. It appears that a part of it was coded it in a way that was intended to mitigate this issue, but it unfortunately wasn't sufficient.

        In sun.net.www.http.HttpClient.parseHTTPHeader:765 (in 1.7.0u40's source code), the call to httpuc.doTunneling() backs up the 'requests' field and then restores it by the end of that method, but that's just in httpuc. When httpud.doTunneling() writes the 'CONNECT' request, it ends up calling the sun.net.www.http.HttpClient's writeRequests:598 method, which sets the 'requests' field of sun.net.www.http.HttpClient to the 'CONNECT' request's values. After httpuc.doTunneling() returns, it proceeds to retry the request with the newly established proxy connection, but it's unfortunately using the 'requests' field that was overwritten by the writeRequests() call from the 'CONNECT' request. Consequently, the remote endpoint sees a 'CONNECT' request instead of the intended request.

        Fortunately, it is possible to override sun.net.www.http.HttpClient by using the endorsed jar mechanism. I tried that out and was able to verify that it successfully fixes the issue. The patch that fixed this issue is the following:

        --- /home/slawrance/dev/tools/Linux/jdk/jdk1.7.0_40_x64/src/jdk/src/share/classes/sun/net/www/http/HttpClient.java 2013-09-06 11:28:38.000000000 -0700
        +++ HttpClient.java 2013-09-25 23:14:19.693524881 -0700
        @@ -651,7 +634,9 @@
                             // try once more
                             openServer();
                             if (needsTunneling()) {
        + final MessageHeader origRequests = requests;
                                 httpuc.doTunneling();
        + requests = origRequests;
                             }
                             afterConnect();
                             writeRequests(requests, poster);
        @@ -762,7 +747,9 @@
                                 cachedHttpClient = false;
                                 openServer();
                                 if (needsTunneling()) {
        + final MessageHeader origRequests = requests;
                                     httpuc.doTunneling();
        + requests = origRequests;
                                 }
                                 afterConnect();
                                 writeRequests(requests, poster);



        STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
        Run the test case code. The Test.java class starts up a https server and a proxy server so that it can make two requests via the proxy to the https server in a manner that triggers reuse of the first connection.

        I was able to verify that this test fails without the fix and passes with the fix. Details exist in the expected and actual results below.

        EXPECTED VERSUS ACTUAL BEHAVIOR :
        EXPECTED -
        After the fix is applied via the endorsed jar mechanism, the test passes:

        $ ~/dev/tools/Linux/jdk/jdk1.7.0_40_x64/bin/java -Djava.endorsed.dirs=/home/slawrance/dev/system/ext/sun_misc/HttpClientFix/jars Test
        Client: Requesting https://slawrance-wsl.internal.salesforce.com:7517/ via HTTP @ slawrance-wsl.internal.salesforce.com/10.0.63.231:47856 (attempt 1 of 2)
        Proxy: NEW CONNECTION
        Server: NEW CONNECTION
        Client: Requesting https://slawrance-wsl.internal.salesforce.com:7517/ via HTTP @ slawrance-wsl.internal.salesforce.com/10.0.63.231:47856 (attempt 2 of 2)
        Proxy: NEW CONNECTION
        Server: NEW CONNECTION
        TEST PASSED

        ACTUAL -
        Failure (current) output:

        $ ~/dev/tools/Linux/jdk/jdk1.7.0_40_x64/bin/java Test
        Client: Requesting https://slawrance-wsl.internal.salesforce.com:10318/ via HTTP @ slawrance-wsl.internal.salesforce.com/10.0.63.231:5445 (attempt 1 of 2)
        Proxy: NEW CONNECTION
        Server: NEW CONNECTION
        Client: Requesting https://slawrance-wsl.internal.salesforce.com:10318/ via HTTP @ slawrance-wsl.internal.salesforce.com/10.0.63.231:5445 (attempt 2 of 2)
        Proxy: NEW CONNECTION
        Server: NEW CONNECTION
        Server: BUG! HTTP CONNECT encountered: CONNECT slawrance-wsl.internal.salesforce.com:10318 HTTP/1.1
        TEST FAILED

        REPRODUCIBILITY :
        This bug can be reproduced always.

        ---------- BEGIN SOURCE ----------
        import java.io.*;
        import java.net.*;
        import java.security.*;
        import java.security.cert.CertificateException;
        import java.util.concurrent.atomic.AtomicBoolean;
        import java.util.regex.Matcher;
        import java.util.regex.Pattern;

        import javax.net.ServerSocketFactory;
        import javax.net.SocketFactory;
        import javax.net.ssl.*;

        import com.sun.org.apache.xml.internal.security.exceptions.Base64DecodingException;
        import com.sun.org.apache.xml.internal.security.utils.Base64;

        /**
         * Test case for the bug where a closed connection will cause the retry code to inadvertently send the 'CONNECT' request
         * meant for the proxy to the remote endpoint via the new proxied connection when a proxied https request is reused in
         * the JDK's built-in HttpsURLConnection.
         *
         * @author Steven Lawrance
         */
        public class Test {
            private final InetSocketAddress serverSocketAddress, proxySocketAddress;
            private final Thread serverThread, proxyThread;
            private final AtomicBoolean keepRunning = new AtomicBoolean(true);
            private final AtomicBoolean connectObservedInServer = new AtomicBoolean();

            /** Key and certificate for the https server in this test, expressed as base64 */
            private final String TEST_PKCS12_FILE = "MIIKZgIBAzCCCjAGCSqGSIb3DQEHAaCCCiEEggodMIIKGTCCBJ8GCSqGSIb3DQEHBqCCBJAwggSM"
                    + "AgEAMIIEhQYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYwDgQIwqUBH+SDbMYCAggAgIIEWFyrRsMm"
                    + "PxJ7mqJ6EEK63TLrcjfpbc+jEK3w5nWB8NfuILFy1fvCX3Z5VfOrU0SV+ZSrbFzXL52XKItwq7nD"
                    + "WcDPAoBybKQZcOjTkTPKUlIQJdU+oovOS69ER52wOAu3FySEYCXVjVO4xQ9Jr9fmx0wbScI6ramT"
                    + "+oOJs9woi12/NQ2zLj0cIk1x84kD4Lw/vMe/2q6D6XjxZWrWCJaZNo4VJwssLBuSquM6VuW3q63r"
                    + "L8NedZ4BId6CyR0Ft/4JVQM+kpMDshhj5wnUUfPDjvldhHP1c1MSiI/gNxwbn/Ielh1zMjffitIZ"
                    + "WY2UUmVFlpg3CElA1gJKylQnXvSuXu1jw/Vnd4raI32tOqlovEx2/Iey/W0ZBj8vXzKqcYW7sCzf"
                    + "i2qEyWYvSLyqCVdOMc6wkbK5a3QInamV+2fcl3z3/l//4/yzZ6xhNQ7+9LlZs7YuMreR6og+dfWK"
                    + "FsIaZDz1sr1bHdAEJNE5YcaJkRqkT74eyKMalRa9HBHZXCG5y06JgwO6h7P4MtOltIPi/HHhHvs5"
                    + "VXZsLljLj/JyinDNNKPvhw3SxF1r4XMF2sNN+6eSGuWNjmWp1mXP/Pio8vgQH/epWlhee3b6WYYu"
                    + "bpSvHHRBdYqfdnUd4SKvgi074SFxJ7r/8XykAr7lpxqjuxPMExcEh/BsmNaXBAB3uv5B3E83tU49"
                    + "nQ+kas+QNdx08D8EOLKYhUGOsa3iMMtrmlD643Zd031uBB5JLcBRK6ZgBg16I8pBv0PjWRe3Bg7X"
                    + "rOemfUZySfsDVRIiZqvy0DbkvqvhiAMOIkWmQW6gfV/1/KeSm4NV12MCRL4B68xPn+t1Ok3O0TG2"
                    + "HkSmGUTwuLkv9dn4dW2rz1fr+9LJk27nr9+Ecn4hUfDx8xIp9rsqd3wJSqSWC55uafCq3zC5CvOY"
                    + "7DoLehM8w3GiAscZupIhG34HIt9NbQcN1RQus6TgkNWMh3s8fGM7ypWCmptN8V1wTMb1E+9zwlFg"
                    + "NQHhqg0hGwSwaF5R7+w1+QzP38Xiss5Es+Qxi2DPjhNNzHTb33JKo6VoPHUgAdHAT2VtHjhnIb6G"
                    + "PRhKI0NxrSrsfZZY2x1JnwfH0UhbDGJheObeGLplzZYvHcUw+dDRS+nPvt8faCos3Mmdz9Ux4FiX"
                    + "trXvp/3PadFduC/mKBC7/aAyu1HW0dCJd0djZbn0+VzOfr8TRPI5j1/uaELzSF67PlKr1L/PVFlL"
                    + "GdlwhMLDLPthUt3Wu7aHOOxkRZuXsHCveSIh+y4VsWH2u4SQEYEd8xASf6D/p4MtC1JIe+vapoEN"
                    + "7uLdIuG75Td2Qh12/VDbCAHFaRFqeDpdlz7qG5hrQbrSnTuGFxVEJM9tMYxshDeK0+IJ44cSQBNi"
                    + "FD3Cko281Pcgoeiqp3a43q7o12reaXU5smHLJ5BgCz1jrbBVagmX4WYIOy9iq2QjWa0Fh7aHIfAi"
                    + "Vf8BB4aeGBUUpFyNzOOHaSBfWtFWF75TMIIFcgYJKoZIhvcNAQcBoIIFYwSCBV8wggVbMIIFVwYL"
                    + "KoZIhvcNAQwKAQKgggTuMIIE6jAcBgoqhkiG9w0BDAEDMA4ECFiQCKVgBtWJAgIIAASCBMi1w33Q"
                    + "cFzrSVWzSo8fBb74biRDlMAhVFUYyQt3uU7i9ss7/Eqetvg+2erZXx4ywhlwSy7p3lQ5+rJvRYPk"
                    + "ayxzoMLYP3Q102OHtGANwhRGFbX+PKEyB9o6qBj1CfcuEptkpCvdxYbnZ8AThzyBDwWEyVJX81Zw"
                    + "0r8GpuTg6sFtfdd1Ytjzxr2MpJsrqukFD5D9/8YCHYNab3A8JrkudvHNUUlgmHH4hmEEMOxnSlc6"
                    + "tIGoWqSi3KhCZjVDiZB6dzUih2TwDkklfwa5r65/lpp9xgBKK1wf6Q3cbhwrncn9kNbnBBH/nQxO"
                    + "qsvFRzypBnU7u9XmRdBIZox9yM8Vgt+Elf90E44xiMF+RV8mzGOvogQ2QUpLsZ8JCcmMq7z3Rpth"
                    + "HDmHl067VhAll7qAZcUqtEvgutLx6QX/UmFBumdWjrNqn4S3EpaiZhe4qQKlaIHZJvnvrGpAwxGt"
                    + "0VRuDFH9B98hx7k7Rfuw4nz/AcQf3v51dY950SoAIHtbk6xQ11Ad0YJ0lUsdck4uhMpvrM4OjtG4"
                    + "UEv4ywo6JVsjXQ9bo2j6asR4NnGR5Gs7PkyEn6Yz4DTjj/hW9m8uqUjcNbxPlASx+owNsEkL9IqW"
                    + "XV7KRcPQFd1dsWttMnBh9yfr62yGBCzEj7FNcDNOpzjZFUbbe8X55GHeBQN82BHZglA1A6rD6a1H"
                    + "QXUHkXcPrh8xpRsh5MRKMf0LgV5bd2XnwQgbeq3EFbyYdx+uz7RwxNOhp5OHHasSMjAbLNNBRIUH"
                    + "YGoWH6NxQIZ7WiGpno9ZnfBLY32b9MQKJMRRiv93CGtjo2wtKZyEeVvJI99UBBz2+ateeNknG054"
                    + "oi1qENiDc8iU0lYyTP4acNKjcso0m5X4X1PJLNlj6DOzmG8x2XeESXM2FtHLpqWtbtGhRsJPsPJE"
                    + "KqWpUZ1l148i7XbJkixLhgUdpJhT69Bubcc7JkdOKbpvIW3ipPXS9GbSwhJVN95nRot8sEjM8uqe"
                    + "6kJ1/VV250Cw2ZJj2BDhK/Teq9GKm27YbC7YWUSo5YOQSfaL2k3zD5ejDTMCiWjK2FDaFQ4fHvBw"
                    + "UQyYeX3IdPo5HdwTcfrGzVCYMUxKN3eUbcYMZajC25mkd7IvPNDvezUyb0KmAAip+xnXfb0Z9zGF"
                    + "c1lzv7MkwPFI0ceYwCX49d4NDGMZ67rG+zhYR0UgxnzyMav5u4c+9gz9PZLdZRqooNpusY3A21v5"
                    + "iXRY32u7UcY2QYMR4tquJ3lKKFY9OWaOnC2cLK/fuK+3IEBdK6ZejXXmS7a5g6HCHBEFb+wOjOiT"
                    + "P795XuB6d9m2tqED4WojxnP+shagD9DU7cRcDpwYiEqhIh44OE5m9vpoX1IIk7Y89QES9tcfmEFS"
                    + "EEF1FblMZC0LjYOEuqvStRxFOoa0SuD1vEUnJdGQXrRAlvOrQK+Hx128wSO5cC895D7/MKmRenRp"
                    + "sIjuKG9nFHnzagQ5kR9Q4II5Y73qCf9894KMCp5MdK/IEZoY/yhWKHgwE9iDL53URstRoqD2OfqO"
                    + "sjxKYlOsC52IoL9xlqFVm2ahsaP+9lOzrgNo43D8GMNuGRuZ9UEJAKoi7QTknt2vEktnA5gj0TyT"
                    + "7aZYdO2sAVFRydlRsT8oiOhYhZoXMrExVjAjBgkqhkiG9w0BCRUxFgQUr8hoZhCTn3Jpm5tZ1GOM"
                    + "396ULBkwLwYJKoZIhvcNAQkUMSIeIABUAGUAcwB0ACAAQwBlAHIAdABpAGYAaQBjAGEAdABlMC0w"
                    + "ITAJBgUrDgMCGgUABBQb3xdMv5tvFY0Qi7geGD1SBoG5JwQIAcFtrXRzzmA=";

            public static void main(String[] args) {
                try {
                    final Test test = new Test();
                    test.runTest();
                    test.keepRunning.set(false);
                    test.serverThread.interrupt();
                    test.serverThread.join();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                System.exit(0);
            }

            private void runTest() throws IOException {
                final URL url = new URL("https", serverSocketAddress.getHostName(), serverSocketAddress.getPort(), "/");
                final Proxy proxy = new Proxy(Proxy.Type.HTTP, proxySocketAddress);
                HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
                    @Override
                    public boolean verify(String hostname, SSLSession sslSession) {
                        return serverSocketAddress.getHostName().equals(hostname); // ignore the cert's CN; it's not important to this test
                    }
                });
                HttpsURLConnection.setDefaultSSLSocketFactory(createTestSSLSocketFactory());

                // Make two connections. The bug occurs when the second request is made
                for (int i = 0; i < 2; i++) {
                    System.out.println("Client: Requesting " + url.toExternalForm() + " via " + proxy.toString() + " (attempt " + (i + 1) + " of 2)");
                    HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(proxy);
                    connection.setRequestMethod("POST");
                    connection.setDoInput(true);
                    connection.setDoOutput(true);
                    connection.setRequestProperty("User-Agent", "Test/1.0");
                    connection.getOutputStream().write("Hello, world!".getBytes("UTF-8"));
                    if (connection.getResponseCode() != 200) {
                        System.err.println("Client: Unexpected response code " + connection.getResponseCode());
                        break;
                    }
                    final BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
                    final String response = reader.readLine();
                    if (!"Hi!".equals(response)) {
                        System.err.println("Client: Unexpected response body: " + response);
                    }
                }
                if (connectObservedInServer.get()) {
                    System.err.println("TEST FAILED");
                } else {
                    System.out.println("TEST PASSED");
                }
            }

            private Test() throws IOException, NoSuchAlgorithmException, KeyStoreException, CertificateException, KeyManagementException, UnrecoverableKeyException {
                KeyStore ks = openKeyStore(TEST_PKCS12_FILE, "testing123", "PKCS12");
                KeyManagerFactory factory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
                factory.init(ks, "testing123".toCharArray());
                SSLContext ctx = SSLContext.getInstance("TLS");
                ctx.init(factory.getKeyManagers(), null, null);
                final SSLSocketFactory sslSocketFactory = ctx.getSocketFactory();

                // Create the server that the test wants to connect to via the proxy
                final ServerSocket serverSocket = ServerSocketFactory.getDefault().createServerSocket();
                serverSocket.bind(new InetSocketAddress(InetAddress.getLocalHost(), 0 /* ephemeral port */));
                serverSocketAddress = (InetSocketAddress) serverSocket.getLocalSocketAddress();
                serverThread = new Thread("ServerThread") {
                    @Override
                    public void run() {
                        try {
                            while (keepRunning.get()) {
                                final Socket socket = serverSocket.accept();
                                System.out.println("Server: NEW CONNECTION");
                                if (socket != null) {
                                    try {
                                        final SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket(socket, null, serverSocketAddress.getPort(), false);
                                        sslSocket.setUseClientMode(false);
                                        sslSocket.startHandshake();
                                        final BufferedReader reader = new BufferedReader(new InputStreamReader(sslSocket.getInputStream()));
                                        String line;
                                        while (!sslSocket.isInputShutdown()) {
                                            try {
                                                String firstLine = null;
                                                while ((line = reader.readLine()) != null && line.length() > 0) {
                                                    if (firstLine == null) {
                                                        firstLine = line;
                                                    }
                                                }
                                                if (line == null) {
                                                    break;
                                                }
                                                if (firstLine != null && firstLine.contains("CONNECT")) {
                                                    System.out.println("Server: BUG! HTTP CONNECT encountered: " + firstLine);
                                                    connectObservedInServer.set(true);
                                                }
                                                final String response = "HTTP/1.1 200 OK\r
        Content-Type: text/plain\r
        Content-Length: 3\r
        \r
        Hi!";
                                                final OutputStream out = sslSocket.getOutputStream();
                                                out.write(response.getBytes("UTF-8"));
                                                out.flush();

                                                // Close the underlying connection's output writer after a second to ensure that the client and proxy
                                                // think that this connection is still open in both directions for the second request.
                                                try {
                                                    Thread.sleep(1000);
                                                } catch (InterruptedException e) {
                                                }
                                                socket.shutdownOutput();
                                                break;
                                            } catch (IOException e) {
                                                e.printStackTrace();
                                                break;
                                            }
                                        }
                                    } catch (Exception e) {
                                        try {
                                            socket.close();
                                        } catch (IOException e2) {
                                        }
                                    }
                                }
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                };
                serverThread.start();

                // Create the http proxy server
                final ServerSocket proxySocket = ServerSocketFactory.getDefault().createServerSocket();
                proxySocket.bind(new InetSocketAddress(InetAddress.getLocalHost(), 0 /* ephemeral port */));
                proxySocketAddress = (InetSocketAddress) proxySocket.getLocalSocketAddress();
                proxyThread = new Thread("ProxyThread") {
                    @Override
                    public void run() {
                        try {
                            final Pattern connectLinePattern = Pattern.compile("^CONNECT ([^: ]+):([0-9]+) HTTP/[0-9.]+$");
                            int proxyConnectionCount = 0;
                            while (keepRunning.get()) {
                                final Socket clientSocket = proxySocket.accept();
                                System.out.println("Proxy: NEW CONNECTION");
                                final int proxyThreadCount = ++proxyConnectionCount;
                                new Thread("ProxySocket" + proxyThreadCount) {
                                    @Override
                                    public void run() {
                                        if (clientSocket != null) {
                                            try {
                                                final InputStream clientIn = clientSocket.getInputStream();
                                                String line;
                                                try {
                                                    String firstLine = null;
                                                    while ((line = readLineFromInputStream(clientIn)) != null && line.length() > 0) {
                                                        if (firstLine == null) {
                                                            firstLine = line;
                                                        }
                                                    }
                                                    if (line == null || firstLine == null) {
                                                        return;
                                                    }
                                                    final Matcher connectLineMatcher = connectLinePattern.matcher(firstLine);
                                                    if (!connectLineMatcher.matches()) {
                                                        System.out.println("Proxy: Unexpected request to the proxy: " + firstLine);
                                                        return;
                                                    }
                                                    final String host = connectLineMatcher.group(1);
                                                    final String portStr = connectLineMatcher.group(2);
                                                    final int port = Integer.parseInt(portStr);
                                                    final Socket serverSocket = SocketFactory.getDefault().createSocket(host, port);
                                                    final InputStream serverIn = serverSocket.getInputStream();
                                                    final OutputStream serverOut = serverSocket.getOutputStream();
                                                    final OutputStream clientOut = clientSocket.getOutputStream();
                                                    clientOut.write("HTTP/1.0 200 Connection Established\r
        Proxy-Agent: TestProxy/1.0\r
        \r
        ".getBytes("UTF-8"));
                                                    final Thread toServerCopier = new Thread("ProxyCopierToServer" + proxyThreadCount) {
                                                        @Override
                                                        public void run() {
                                                            try {
                                                                final byte[] b = new byte[1024];
                                                                int byteCount;
                                                                while ((byteCount = clientIn.read(b)) > 0) {
                                                                    serverOut.write(b, 0, byteCount);
                                                                }
                                                            } catch (IOException e) {
                                                                // Socket is probably closed
                                                            } catch (Exception e) {
                                                                e.printStackTrace();
                                                            }
                                                            try {
                                                                serverSocket.shutdownOutput();
                                                            } catch (IOException e) {
                                                                // Socket is probably closed
                                                            } catch (Exception e) {
                                                                e.printStackTrace();
                                                            }
                                                        }
                                                    };
                                                    toServerCopier.start();
                                                    try {
                                                        final byte[] b = new byte[1024];
                                                        int byteCount;
                                                        while ((byteCount = serverIn.read(b)) > 0) {
                                                            clientOut.write(b, 0, byteCount);
                                                        }
                                                    } catch (IOException e) {
                                                        // Socket is probably closed
                                                    }
                                                    try {
                                                        clientSocket.shutdownOutput();
                                                    } catch (IOException e) {
                                                        // Socket is probably closed
                                                    } catch (Exception e) {
                                                        e.printStackTrace();
                                                    }
                                                    toServerCopier.join();
                                                } catch (IOException e) {
                                                    e.printStackTrace();
                                                }
                                            } catch (Exception e) {
                                                try {
                                                    e.printStackTrace();
                                                    clientSocket.close();
                                                } catch (IOException e2) {
                                                }
                                            }
                                        }
                                    }
                                }.start();
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                };
                proxyThread.start();
            }

            private String readLineFromInputStream(InputStream in) throws IOException {
                final StringBuilder s = new StringBuilder();
                int ch;
                while ((ch = in.read()) >= 0) {
                    if (ch == '\r') {
                        continue;
                    }
                    if (ch == '
        ') {
                        break;
                    }
                    s.append((char) ch);
                }
                return s.toString();
            }

            private KeyStore openKeyStore(String pkcs12FileBase64, String password, String type) throws IOException, NoSuchAlgorithmException, KeyStoreException, CertificateException {
                ByteArrayInputStream fin = null;
                char[] passphrase = password.toCharArray();
                KeyStore ks = KeyStore.getInstance(type);
                try {
                    fin = new ByteArrayInputStream(Base64.decode(pkcs12FileBase64));
                } catch (Base64DecodingException e) {
                    throw new RuntimeException(e);
                }
                ks.load(fin, passphrase);
                return ks;
            }

            private SSLSocketFactory createTestSSLSocketFactory() {

                // Set up the socket factory to use a trust manager that trusts all certs, since trust validation isn't important to this test
                final TrustManager[] trustAllCertChains = new TrustManager[] { new X509TrustManager() {
                    @Override
                    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                        return null;
                    }

                    @Override
                    public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {}

                    @Override
                    public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {}
                } };
                final SSLContext sc;
                try {
                    sc = SSLContext.getInstance("TLS");
                }
                catch (NoSuchAlgorithmException e) {
                    throw new RuntimeException(e);
                }
                try {
                    sc.init(null, trustAllCertChains, new java.security.SecureRandom());
                }
                catch (KeyManagementException e) {
                    throw new RuntimeException(e);
                }
                return sc.getSocketFactory();
            }
        }

        ---------- END SOURCE ----------

        CUSTOMER SUBMITTED WORKAROUND :
        As a workaround, it is possible to set "Connection: close" in the HttpsURLConnection request. By turning off the use of persistent connections, this bug is worked around.

          Attachments

            Issue Links

              Activity

                People

                Assignee:
                chegar Chris Hegarty
                Reporter:
                coffeys Sean Coffey
                Votes:
                0 Vote for this issue
                Watchers:
                4 Start watching this issue

                  Dates

                  Created:
                  Updated:
                  Resolved: