Home | History | Annotate | Download | only in https
      1 /*
      2  *  Licensed to the Apache Software Foundation (ASF) under one or more
      3  *  contributor license agreements.  See the NOTICE file distributed with
      4  *  this work for additional information regarding copyright ownership.
      5  *  The ASF licenses this file to You under the Apache License, Version 2.0
      6  *  (the "License"); you may not use this file except in compliance with
      7  *  the License.  You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  */
     17 
     18 package org.apache.harmony.luni.tests.internal.net.www.protocol.https;
     19 
     20 import java.io.File;
     21 import java.io.FileInputStream;
     22 import java.io.FileNotFoundException;
     23 import java.io.IOException;
     24 import java.io.InputStream;
     25 import java.io.OutputStream;
     26 import java.io.PrintStream;
     27 import java.net.Authenticator;
     28 import java.net.HttpURLConnection;
     29 import java.net.InetSocketAddress;
     30 import java.net.PasswordAuthentication;
     31 import java.net.Proxy;
     32 import java.net.ServerSocket;
     33 import java.net.Socket;
     34 import java.net.SocketTimeoutException;
     35 import java.net.URL;
     36 import java.security.KeyStore;
     37 import java.security.cert.Certificate;
     38 import java.util.Arrays;
     39 
     40 import javax.net.ssl.HostnameVerifier;
     41 import javax.net.ssl.HttpsURLConnection;
     42 import javax.net.ssl.KeyManagerFactory;
     43 import javax.net.ssl.SSLContext;
     44 import javax.net.ssl.SSLServerSocket;
     45 import javax.net.ssl.SSLSession;
     46 import javax.net.ssl.SSLSocket;
     47 import javax.net.ssl.SSLSocketFactory;
     48 import javax.net.ssl.TrustManagerFactory;
     49 
     50 import junit.framework.AssertionFailedError;
     51 import junit.framework.TestCase;
     52 import junit.framework.TestSuite;
     53 
     54 /**
     55  * Implementation independent test for HttpsURLConnection. The test needs
     56  * certstore file placed in system classpath and named as "key_store." + the
     57  * type of the default KeyStore installed in the system in lower case. <br>
     58  * For example: if default KeyStore type in the system is BKS (i.e.
     59  * java.security file sets up the property keystore.type=BKS), thus classpath
     60  * should point to the directory with "key_store.bks" file. <br>
     61  * This certstore file should contain self-signed certificate generated by
     62  * keytool utility in a usual way. <br>
     63  * The password to the certstore should be "password" (without quotes).
     64  */
     65 public class HttpsURLConnectionTest extends TestCase {
     66 
     67     // the password to the store
     68     private static final String KS_PASSWORD = "password";
     69 
     70     // turn on/off logging
     71     private static final boolean DO_LOG = false;
     72 
     73     // read/connection timeout value
     74     private static final int TIMEOUT = 5000;
     75 
     76     // OK response code
     77     private static final int OK_CODE = 200;
     78 
     79     // Not Found response code
     80     private static final int NOT_FOUND_CODE = 404;
     81 
     82     // Proxy authentication required response code
     83     private static final int AUTHENTICATION_REQUIRED_CODE = 407;
     84 
     85     // fields keeping the system values of corresponding properties
     86     private static String systemKeyStoreType;
     87 
     88     private static String systemKeyStore;
     89 
     90     private static String systemKeyStorePassword;
     91 
     92     private static String systemTrustStoreType;
     93 
     94     private static String systemTrustStore;
     95 
     96     private static String systemTrustStorePassword;
     97 
     98     /**
     99      * Checks that HttpsURLConnection's default SSLSocketFactory is operable.
    100      */
    101     public void testGetDefaultSSLSocketFactory() throws Exception {
    102         // set up the properties defining the default values needed by SSL stuff
    103         setUpStoreProperties();
    104 
    105         try {
    106             SSLSocketFactory defaultSSLSF = HttpsURLConnection
    107                     .getDefaultSSLSocketFactory();
    108             ServerSocket ss = new ServerSocket(0);
    109             Socket s = defaultSSLSF
    110                     .createSocket("localhost", ss.getLocalPort());
    111             ss.accept();
    112             s.close();
    113             ss.close();
    114         } finally {
    115             // roll the properties back to system values
    116             tearDownStoreProperties();
    117         }
    118     }
    119 
    120     /**
    121      * Checks if HTTPS connection performs initial SSL handshake with the server
    122      * working over SSL, sends encrypted HTTP request, and receives expected
    123      * HTTP response. After HTTPS session if finished test checks connection
    124      * state parameters established by HttpsURLConnection.
    125      */
    126     public void testHttpsConnection() throws Throwable {
    127         // set up the properties defining the default values needed by SSL stuff
    128         setUpStoreProperties();
    129 
    130         try {
    131             // create the SSL server socket acting as a server
    132             SSLContext ctx = getContext();
    133             ServerSocket ss = ctx.getServerSocketFactory()
    134                     .createServerSocket(0);
    135 
    136             // create the HostnameVerifier to check hostname verification
    137             TestHostnameVerifier hnv = new TestHostnameVerifier();
    138             HttpsURLConnection.setDefaultHostnameVerifier(hnv);
    139 
    140             // create url connection to be tested
    141             URL url = new URL("https://localhost:" + ss.getLocalPort());
    142             HttpsURLConnection connection = (HttpsURLConnection) url
    143                     .openConnection();
    144 
    145             // perform the interaction between the peers
    146             SSLSocket peerSocket = (SSLSocket) doInteraction(connection, ss);
    147 
    148             // check the connection state
    149             checkConnectionStateParameters(connection, peerSocket);
    150 
    151             // should silently exit
    152             connection.connect();
    153         } finally {
    154             // roll the properties back to system values
    155             tearDownStoreProperties();
    156         }
    157     }
    158 
    159     /**
    160      * Checks if HTTPS connection performs initial SSL handshake with the server
    161      * working over SSL, sends encrypted HTTP request, and receives expected
    162      * HTTP response. After that it checks that the established connection is
    163      * persistent. After HTTPS session if finished test checks connection state
    164      * parameters established by HttpsURLConnection.
    165      */
    166     public void testHttpsPersistentConnection() throws Throwable {
    167         // set up the properties defining the default values needed by SSL stuff
    168         setUpStoreProperties();
    169 
    170         try {
    171             // create the SSL server socket acting as a server
    172             SSLContext ctx = getContext();
    173             ServerSocket ss = ctx.getServerSocketFactory()
    174                     .createServerSocket(0);
    175 
    176             // create the HostnameVerifier to check hostname verification
    177             TestHostnameVerifier hnv = new TestHostnameVerifier();
    178             HttpsURLConnection.setDefaultHostnameVerifier(hnv);
    179 
    180             // create url connection to be tested
    181             URL url = new URL("https://localhost:" + ss.getLocalPort());
    182             HttpsURLConnection connection = (HttpsURLConnection) url
    183                     .openConnection();
    184 
    185             // perform the interaction between the peers
    186             SSLSocket peerSocket = (SSLSocket) doPersistentInteraction(
    187                     connection, ss);
    188 
    189             // check the connection state
    190             checkConnectionStateParameters(connection, peerSocket);
    191 
    192             // should silently exit
    193             connection.connect();
    194         } finally {
    195             // roll the properties back to system values
    196             tearDownStoreProperties();
    197         }
    198     }
    199 
    200     /**
    201      * Tests the behaviour of HTTPS connection in case of unavailability of
    202      * requested resource.
    203      */
    204     public void testHttpsConnection_Not_Found_Response() throws Throwable {
    205         // set up the properties defining the default values needed by SSL stuff
    206         setUpStoreProperties();
    207 
    208         try {
    209             // create the SSL server socket acting as a server
    210             SSLContext ctx = getContext();
    211             ServerSocket ss = ctx.getServerSocketFactory()
    212                     .createServerSocket(0);
    213 
    214             // create the HostnameVerifier to check hostname verification
    215             TestHostnameVerifier hnv = new TestHostnameVerifier();
    216             HttpsURLConnection.setDefaultHostnameVerifier(hnv);
    217 
    218             // create url connection to be tested
    219             URL url = new URL("https://localhost:" + ss.getLocalPort());
    220             HttpsURLConnection connection = (HttpsURLConnection) url
    221                     .openConnection();
    222 
    223             try {
    224                 doInteraction(connection, ss, NOT_FOUND_CODE);
    225                 fail("Expected exception was not thrown.");
    226             } catch (FileNotFoundException e) {
    227                 if (DO_LOG) {
    228                     System.out.println("Expected exception was thrown: "
    229                             + e.getMessage());
    230                 }
    231             }
    232 
    233             // should silently exit
    234             connection.connect();
    235         } finally {
    236             // roll the properties back to system values
    237             tearDownStoreProperties();
    238         }
    239     }
    240 
    241     /**
    242      * Tests possibility to set up the default SSLSocketFactory to be used by
    243      * HttpsURLConnection.
    244      */
    245     public void testSetDefaultSSLSocketFactory() throws Throwable {
    246         // create the SSLServerSocket which will be used by server side
    247         SSLContext ctx = getContext();
    248         SSLServerSocket ss = (SSLServerSocket) ctx.getServerSocketFactory()
    249                 .createServerSocket(0);
    250 
    251         SSLSocketFactory socketFactory = (SSLSocketFactory) ctx
    252                 .getSocketFactory();
    253         // set up the factory as default
    254         HttpsURLConnection.setDefaultSSLSocketFactory(socketFactory);
    255         // check the result
    256         assertSame("Default SSLSocketFactory differs from expected",
    257                 socketFactory, HttpsURLConnection.getDefaultSSLSocketFactory());
    258 
    259         // create the HostnameVerifier to check hostname verification
    260         TestHostnameVerifier hnv = new TestHostnameVerifier();
    261         HttpsURLConnection.setDefaultHostnameVerifier(hnv);
    262 
    263         // create HttpsURLConnection to be tested
    264         URL url = new URL("https://localhost:" + ss.getLocalPort());
    265         HttpsURLConnection connection = (HttpsURLConnection) url
    266                 .openConnection();
    267 
    268         TestHostnameVerifier hnv_late = new TestHostnameVerifier();
    269         // late initialization: should not be used for created connection
    270         HttpsURLConnection.setDefaultHostnameVerifier(hnv_late);
    271 
    272         // perform the interaction between the peers
    273         SSLSocket peerSocket = (SSLSocket) doInteraction(connection, ss);
    274         // check the connection state
    275         checkConnectionStateParameters(connection, peerSocket);
    276         // check the verification process
    277         assertTrue("Hostname verification was not done", hnv.verified);
    278         assertFalse(
    279                 "Hostname verification should not be done by this verifier",
    280                 hnv_late.verified);
    281         // check the used SSLSocketFactory
    282         assertSame("Default SSLSocketFactory should be used",
    283                 HttpsURLConnection.getDefaultSSLSocketFactory(), connection
    284                         .getSSLSocketFactory());
    285 
    286         // should silently exit
    287         connection.connect();
    288     }
    289 
    290     /**
    291      * Tests possibility to set up the SSLSocketFactory to be used by
    292      * HttpsURLConnection.
    293      */
    294     public void testSetSSLSocketFactory() throws Throwable {
    295         // create the SSLServerSocket which will be used by server side
    296         SSLContext ctx = getContext();
    297         SSLServerSocket ss = (SSLServerSocket) ctx.getServerSocketFactory()
    298                 .createServerSocket(0);
    299 
    300         // create the HostnameVerifier to check hostname verification
    301         TestHostnameVerifier hnv = new TestHostnameVerifier();
    302         HttpsURLConnection.setDefaultHostnameVerifier(hnv);
    303 
    304         // create HttpsURLConnection to be tested
    305         URL url = new URL("https://localhost:" + ss.getLocalPort());
    306         HttpsURLConnection connection = (HttpsURLConnection) url
    307                 .openConnection();
    308 
    309         SSLSocketFactory socketFactory = (SSLSocketFactory) ctx
    310                 .getSocketFactory();
    311         connection.setSSLSocketFactory(socketFactory);
    312 
    313         TestHostnameVerifier hnv_late = new TestHostnameVerifier();
    314         // late initialization: should not be used for created connection
    315         HttpsURLConnection.setDefaultHostnameVerifier(hnv_late);
    316 
    317         // perform the interaction between the peers
    318         SSLSocket peerSocket = (SSLSocket) doInteraction(connection, ss);
    319         // check the connection state
    320         checkConnectionStateParameters(connection, peerSocket);
    321         // check the verification process
    322         assertTrue("Hostname verification was not done", hnv.verified);
    323         assertFalse(
    324                 "Hostname verification should not be done by this verifier",
    325                 hnv_late.verified);
    326         // check the used SSLSocketFactory
    327         assertNotSame("Default SSLSocketFactory should not be used",
    328                 HttpsURLConnection.getDefaultSSLSocketFactory(), connection
    329                         .getSSLSocketFactory());
    330         assertSame("Result differs from expected", socketFactory, connection
    331                 .getSSLSocketFactory());
    332 
    333         // should silently exit
    334         connection.connect();
    335     }
    336 
    337     /**
    338      * Tests the behaviour of HttpsURLConnection in case of retrieving of the
    339      * connection state parameters before connection has been made.
    340      */
    341     public void testUnconnectedStateParameters() throws Throwable {
    342         // create HttpsURLConnection to be tested
    343         URL url = new URL("https://localhost:55555");
    344         HttpsURLConnection connection = (HttpsURLConnection) url
    345                 .openConnection();
    346 
    347         try {
    348             connection.getCipherSuite();
    349             fail("Expected IllegalStateException was not thrown");
    350         } catch (IllegalStateException e) {
    351         }
    352         try {
    353             connection.getPeerPrincipal();
    354             fail("Expected IllegalStateException was not thrown");
    355         } catch (IllegalStateException e) {
    356         }
    357         try {
    358             connection.getLocalPrincipal();
    359             fail("Expected IllegalStateException was not thrown");
    360         } catch (IllegalStateException e) {
    361         }
    362 
    363         try {
    364             connection.getServerCertificates();
    365             fail("Expected IllegalStateException was not thrown");
    366         } catch (IllegalStateException e) {
    367         }
    368         try {
    369             connection.getLocalCertificates();
    370             fail("Expected IllegalStateException was not thrown");
    371         } catch (IllegalStateException e) {
    372         }
    373     }
    374 
    375     /**
    376      * Tests if setHostnameVerifier() method replaces default verifier.
    377      */
    378     public void testSetHostnameVerifier() throws Throwable {
    379         // setting up the properties pointing to the key/trust stores
    380         setUpStoreProperties();
    381 
    382         try {
    383             // create the SSLServerSocket which will be used by server side
    384             SSLServerSocket ss = (SSLServerSocket) getContext()
    385                     .getServerSocketFactory().createServerSocket(0);
    386 
    387             // create the HostnameVerifier to check that Hostname verification
    388             // is done
    389             TestHostnameVerifier hnv = new TestHostnameVerifier();
    390             HttpsURLConnection.setDefaultHostnameVerifier(hnv);
    391 
    392             // create HttpsURLConnection to be tested
    393             URL url = new URL("https://localhost:" + ss.getLocalPort());
    394             HttpsURLConnection connection = (HttpsURLConnection) url
    395                     .openConnection();
    396 
    397             TestHostnameVerifier hnv_late = new TestHostnameVerifier();
    398             // replace default verifier
    399             connection.setHostnameVerifier(hnv_late);
    400 
    401             // perform the interaction between the peers and check the results
    402             SSLSocket peerSocket = (SSLSocket) doInteraction(connection, ss);
    403             assertTrue("Hostname verification was not done", hnv_late.verified);
    404             assertFalse(
    405                     "Hostname verification should not be done by this verifier",
    406                     hnv.verified);
    407             checkConnectionStateParameters(connection, peerSocket);
    408 
    409             // should silently exit
    410             connection.connect();
    411         } finally {
    412             // roll the properties back to system values
    413             tearDownStoreProperties();
    414         }
    415     }
    416 
    417     /**
    418      * Tests the behaviour in case of sending the data to the server.
    419      */
    420     public void test_doOutput() throws Throwable {
    421         // setting up the properties pointing to the key/trust stores
    422         setUpStoreProperties();
    423 
    424         try {
    425             // create the SSLServerSocket which will be used by server side
    426             SSLServerSocket ss = (SSLServerSocket) getContext()
    427                     .getServerSocketFactory().createServerSocket(0);
    428 
    429             // create the HostnameVerifier to check that Hostname verification
    430             // is done
    431             TestHostnameVerifier hnv = new TestHostnameVerifier();
    432             HttpsURLConnection.setDefaultHostnameVerifier(hnv);
    433 
    434             // create HttpsURLConnection to be tested
    435             URL url = new URL("https://localhost:" + ss.getLocalPort());
    436             HttpsURLConnection connection = (HttpsURLConnection) url
    437                     .openConnection();
    438             connection.setDoOutput(true);
    439 
    440             // perform the interaction between the peers and check the results
    441             SSLSocket peerSocket = (SSLSocket) doInteraction(connection, ss);
    442             checkConnectionStateParameters(connection, peerSocket);
    443 
    444             // should silently exit
    445             connection.connect();
    446         } finally {
    447             // roll the properties back to system values
    448             tearDownStoreProperties();
    449         }
    450     }
    451 
    452     /**
    453      * Tests the behaviour in case of sending the data to the server over
    454      * persistent connection.
    455      */
    456     public void testPersistence_doOutput() throws Throwable {
    457         // setting up the properties pointing to the key/trust stores
    458         setUpStoreProperties();
    459 
    460         try {
    461             // create the SSLServerSocket which will be used by server side
    462             SSLServerSocket ss = (SSLServerSocket) getContext()
    463                     .getServerSocketFactory().createServerSocket(0);
    464 
    465             // create the HostnameVerifier to check that Hostname verification
    466             // is done
    467             TestHostnameVerifier hnv = new TestHostnameVerifier();
    468             HttpsURLConnection.setDefaultHostnameVerifier(hnv);
    469 
    470             // create HttpsURLConnection to be tested
    471             URL url = new URL("https://localhost:" + ss.getLocalPort());
    472             HttpsURLConnection connection = (HttpsURLConnection) url
    473                     .openConnection();
    474             connection.setDoOutput(true);
    475 
    476             // perform the interaction between the peers and check the results
    477             SSLSocket peerSocket = (SSLSocket) doPersistentInteraction(
    478                     connection, ss);
    479             checkConnectionStateParameters(connection, peerSocket);
    480 
    481             // should silently exit
    482             connection.connect();
    483         } finally {
    484             // roll the properties back to system values
    485             tearDownStoreProperties();
    486         }
    487     }
    488 
    489     /**
    490      * Tests HTTPS connection process made through the proxy server.
    491      */
    492     public void testProxyConnection() throws Throwable {
    493         // setting up the properties pointing to the key/trust stores
    494         setUpStoreProperties();
    495 
    496         try {
    497             // create the SSLServerSocket which will be used by server side
    498             ServerSocket ss = new ServerSocket(0);
    499 
    500             // create the HostnameVerifier to check that Hostname verification
    501             // is done
    502             TestHostnameVerifier hnv = new TestHostnameVerifier();
    503             HttpsURLConnection.setDefaultHostnameVerifier(hnv);
    504 
    505             // create HttpsURLConnection to be tested
    506             URL url = new URL("https://requested.host:55556/requested.data");
    507             HttpsURLConnection connection = (HttpsURLConnection) url
    508                     .openConnection(new Proxy(Proxy.Type.HTTP,
    509                             new InetSocketAddress("localhost", ss
    510                                     .getLocalPort())));
    511 
    512             // perform the interaction between the peers and check the results
    513             SSLSocket peerSocket = (SSLSocket) doInteraction(connection, ss);
    514             checkConnectionStateParameters(connection, peerSocket);
    515 
    516             // should silently exit
    517             connection.connect();
    518         } finally {
    519             // roll the properties back to system values
    520             tearDownStoreProperties();
    521         }
    522     }
    523 
    524     /**
    525      * Tests HTTPS connection process made through the proxy server. Checks that
    526      * persistent connection to the host exists and can be used no in spite of
    527      * explicit Proxy specifying.
    528      */
    529     public void testPersistentProxyConnection() throws Throwable {
    530         // setting up the properties pointing to the key/trust stores
    531         setUpStoreProperties();
    532 
    533         try {
    534             // create the SSLServerSocket which will be used by server side
    535             ServerSocket ss = new ServerSocket(0);
    536 
    537             // create the HostnameVerifier to check that Hostname verification
    538             // is done
    539             TestHostnameVerifier hnv = new TestHostnameVerifier();
    540             HttpsURLConnection.setDefaultHostnameVerifier(hnv);
    541 
    542             // create HttpsURLConnection to be tested
    543             URL url = new URL("https://requested.host:55556/requested.data");
    544             HttpsURLConnection connection = (HttpsURLConnection) url
    545                     .openConnection(new Proxy(Proxy.Type.HTTP,
    546                             new InetSocketAddress("localhost", ss
    547                                     .getLocalPort())));
    548 
    549             // perform the interaction between the peers and check the results
    550             SSLSocket peerSocket = (SSLSocket) doPersistentInteraction(
    551                     connection, ss);
    552             checkConnectionStateParameters(connection, peerSocket);
    553 
    554             // should silently exit
    555             connection.connect();
    556         } finally {
    557             // roll the properties back to system values
    558             tearDownStoreProperties();
    559         }
    560     }
    561 
    562     /**
    563      * Tests HTTPS connection process made through the proxy server. Proxy
    564      * server needs authentication.
    565      */
    566     public void testProxyAuthConnection() throws Throwable {
    567         // setting up the properties pointing to the key/trust stores
    568         setUpStoreProperties();
    569 
    570         try {
    571             // create the SSLServerSocket which will be used by server side
    572             ServerSocket ss = new ServerSocket(0);
    573 
    574             // create the HostnameVerifier to check that Hostname verification
    575             // is done
    576             TestHostnameVerifier hnv = new TestHostnameVerifier();
    577             HttpsURLConnection.setDefaultHostnameVerifier(hnv);
    578 
    579             Authenticator.setDefault(new Authenticator() {
    580 
    581                 protected PasswordAuthentication getPasswordAuthentication() {
    582                     return new PasswordAuthentication("user", "password"
    583                             .toCharArray());
    584                 }
    585             });
    586 
    587             // create HttpsURLConnection to be tested
    588             URL url = new URL("https://requested.host:55555/requested.data");
    589             HttpsURLConnection connection = (HttpsURLConnection) url
    590                     .openConnection(new Proxy(Proxy.Type.HTTP,
    591                             new InetSocketAddress("localhost", ss
    592                                     .getLocalPort())));
    593 
    594             // perform the interaction between the peers and check the results
    595             SSLSocket peerSocket = (SSLSocket) doInteraction(connection, ss);
    596             checkConnectionStateParameters(connection, peerSocket);
    597 
    598             // should silently exit
    599             connection.connect();
    600         } finally {
    601             // roll the properties back to system values
    602             tearDownStoreProperties();
    603         }
    604     }
    605 
    606     /**
    607      * Tests HTTPS connection process made through the proxy server. 2 HTTPS
    608      * connections are opened for one URL. For the first time the connection is
    609      * opened through one proxy, for the second time through another.
    610      */
    611     public void testConsequentProxyConnection() throws Throwable {
    612         // setting up the properties pointing to the key/trust stores
    613         setUpStoreProperties();
    614 
    615         try {
    616             // create the SSLServerSocket which will be used by server side
    617             ServerSocket ss = new ServerSocket(0);
    618 
    619             // create the HostnameVerifier to check that Hostname verification
    620             // is done
    621             TestHostnameVerifier hnv = new TestHostnameVerifier();
    622             HttpsURLConnection.setDefaultHostnameVerifier(hnv);
    623 
    624             // create HttpsURLConnection to be tested
    625             URL url = new URL("https://requested.host:55555/requested.data");
    626             HttpsURLConnection connection = (HttpsURLConnection) url
    627                     .openConnection(new Proxy(Proxy.Type.HTTP,
    628                             new InetSocketAddress("localhost", ss
    629                                     .getLocalPort())));
    630 
    631             // perform the interaction between the peers and check the results
    632             SSLSocket peerSocket = (SSLSocket) doInteraction(connection, ss);
    633             checkConnectionStateParameters(connection, peerSocket);
    634 
    635             // create another SSLServerSocket which will be used by server side
    636             ss = new ServerSocket(0);
    637 
    638             connection = (HttpsURLConnection) url.openConnection(new Proxy(
    639                     Proxy.Type.HTTP, new InetSocketAddress("localhost", ss
    640                             .getLocalPort())));
    641 
    642             // perform the interaction between the peers and check the results
    643             peerSocket = (SSLSocket) doInteraction(connection, ss);
    644             checkConnectionStateParameters(connection, peerSocket);
    645         } finally {
    646             // roll the properties back to system values
    647             tearDownStoreProperties();
    648         }
    649     }
    650 
    651     /**
    652      * Tests HTTPS connection process made through the proxy server. Proxy
    653      * server needs authentication. Client sends data to the server.
    654      */
    655     public void testProxyAuthConnection_doOutput() throws Throwable {
    656         // setting up the properties pointing to the key/trust stores
    657         setUpStoreProperties();
    658 
    659         try {
    660             // create the SSLServerSocket which will be used by server side
    661             ServerSocket ss = new ServerSocket(0);
    662 
    663             // create the HostnameVerifier to check that Hostname verification
    664             // is done
    665             TestHostnameVerifier hnv = new TestHostnameVerifier();
    666             HttpsURLConnection.setDefaultHostnameVerifier(hnv);
    667 
    668             Authenticator.setDefault(new Authenticator() {
    669 
    670                 protected PasswordAuthentication getPasswordAuthentication() {
    671                     return new PasswordAuthentication("user", "password"
    672                             .toCharArray());
    673                 }
    674             });
    675 
    676             // create HttpsURLConnection to be tested
    677             URL url = new URL("https://requested.host:55554/requested.data");
    678             HttpsURLConnection connection = (HttpsURLConnection) url
    679                     .openConnection(new Proxy(Proxy.Type.HTTP,
    680                             new InetSocketAddress("localhost", ss
    681                                     .getLocalPort())));
    682             connection.setDoOutput(true);
    683 
    684             // perform the interaction between the peers and check the results
    685             SSLSocket peerSocket = (SSLSocket) doInteraction(connection, ss,
    686                     OK_CODE);
    687             checkConnectionStateParameters(connection, peerSocket);
    688         } finally {
    689             // roll the properties back to system values
    690             tearDownStoreProperties();
    691         }
    692     }
    693 
    694     /**
    695      * Tests HTTPS connection process made through the proxy server. Proxy
    696      * server needs authentication but client fails to authenticate
    697      * (Authenticator was not set up in the system).
    698      */
    699     public void testProxyAuthConnectionFailed() throws Throwable {
    700         // setting up the properties pointing to the key/trust stores
    701         setUpStoreProperties();
    702 
    703         try {
    704             // create the SSLServerSocket which will be used by server side
    705             ServerSocket ss = new ServerSocket(0);
    706 
    707             // create the HostnameVerifier to check that Hostname verification
    708             // is done
    709             TestHostnameVerifier hnv = new TestHostnameVerifier();
    710             HttpsURLConnection.setDefaultHostnameVerifier(hnv);
    711 
    712             // create HttpsURLConnection to be tested
    713             URL url = new URL("https://requested.host:55555/requested.data");
    714             HttpURLConnection connection = (HttpURLConnection) url
    715                     .openConnection(new Proxy(Proxy.Type.HTTP,
    716                             new InetSocketAddress("localhost", ss
    717                                     .getLocalPort())));
    718 
    719             // perform the interaction between the peers and check the results
    720             try {
    721                 doInteraction(connection, ss, AUTHENTICATION_REQUIRED_CODE);
    722             } catch (IOException e) {
    723                 // SSL Tunnelling failed
    724                 if (DO_LOG) {
    725                     System.out.println("Got expected IOException: "
    726                             + e.getMessage());
    727                 }
    728             }
    729         } finally {
    730             // roll the properties back to system values
    731             tearDownStoreProperties();
    732         }
    733     }
    734 
    735     /**
    736      * Tests the behaviour of HTTPS connection in case of unavailability of
    737      * requested resource.
    738      */
    739     public void testProxyConnection_Not_Found_Response() throws Throwable {
    740         // setting up the properties pointing to the key/trust stores
    741         setUpStoreProperties();
    742 
    743         try {
    744             // create the SSLServerSocket which will be used by server side
    745             ServerSocket ss = new ServerSocket(0);
    746 
    747             // create the HostnameVerifier to check that Hostname verification
    748             // is done
    749             TestHostnameVerifier hnv = new TestHostnameVerifier();
    750             HttpsURLConnection.setDefaultHostnameVerifier(hnv);
    751 
    752             // create HttpsURLConnection to be tested
    753             URL url = new URL("https://localhost:" + ss.getLocalPort());
    754             HttpURLConnection connection = (HttpURLConnection) url
    755                     .openConnection(new Proxy(Proxy.Type.HTTP,
    756                             new InetSocketAddress("localhost", ss
    757                                     .getLocalPort())));
    758 
    759             try {
    760                 doInteraction(connection, ss, NOT_FOUND_CODE); // NOT FOUND
    761                 fail("Expected exception was not thrown.");
    762             } catch (FileNotFoundException e) {
    763                 if (DO_LOG) {
    764                     System.out.println("Expected exception was thrown: "
    765                             + e.getMessage());
    766                 }
    767             }
    768         } finally {
    769             // roll the properties back to system values
    770             tearDownStoreProperties();
    771         }
    772     }
    773 
    774     // ---------------------------------------------------------------------
    775     // ------------------------ Staff Methods ------------------------------
    776     // ---------------------------------------------------------------------
    777 
    778     /**
    779      * Log the name of the test case to be executed.
    780      */
    781     public void setUp() throws Exception {
    782         if (DO_LOG) {
    783             System.out.println();
    784             System.out.println("------------------------");
    785             System.out.println("------ " + getName());
    786             System.out.println("------------------------");
    787         }
    788     }
    789 
    790     /**
    791      * Checks the HttpsURLConnection getter's values and compares them with
    792      * actual corresponding values of remote peer.
    793      */
    794     public static void checkConnectionStateParameters(
    795             HttpsURLConnection clientConnection, SSLSocket serverPeer)
    796             throws Exception {
    797         SSLSession session = serverPeer.getSession();
    798 
    799         assertEquals(session.getCipherSuite(), clientConnection
    800                 .getCipherSuite());
    801 
    802         assertEquals(session.getLocalPrincipal(), clientConnection
    803                 .getPeerPrincipal());
    804 
    805         assertEquals(session.getPeerPrincipal(), clientConnection
    806                 .getLocalPrincipal());
    807 
    808         Certificate[] serverCertificates = clientConnection
    809                 .getServerCertificates();
    810         Certificate[] localCertificates = session.getLocalCertificates();
    811         assertTrue("Server certificates differ from expected", Arrays.equals(
    812                 serverCertificates, localCertificates));
    813 
    814         localCertificates = clientConnection.getLocalCertificates();
    815         serverCertificates = session.getPeerCertificates();
    816         assertTrue("Local certificates differ from expected", Arrays.equals(
    817                 serverCertificates, localCertificates));
    818     }
    819 
    820     /**
    821      * Returns the file name of the key/trust store. The key store file (named
    822      * as "key_store." + extension equals to the default KeyStore type installed
    823      * in the system in lower case) is searched in classpath.
    824      *
    825      * @throws AssertionFailedError
    826      *             if property was not set or file does not exist.
    827      */
    828     private static String getKeyStoreFileName() throws Exception {
    829         String ksFileName = "org/apache/harmony/luni/tests/key_store."
    830                 + KeyStore.getDefaultType().toLowerCase();
    831         URL url = ClassLoader.getSystemClassLoader().getResource(ksFileName);
    832         assertNotNull("Expected KeyStore file: '" + ksFileName
    833                 + "' for default KeyStore of type '"
    834                 + KeyStore.getDefaultType() + "' does not exist.", url);
    835         return new File(url.toURI()).getAbsolutePath();
    836     }
    837 
    838     /**
    839      * Builds and returns the context used for secure socket creation.
    840      */
    841     private static SSLContext getContext() throws Exception {
    842         String type = KeyStore.getDefaultType();
    843         SSLContext ctx;
    844 
    845         String keyStore = getKeyStoreFileName();
    846         File keyStoreFile = new File(keyStore);
    847 
    848         FileInputStream fis = new FileInputStream(keyStoreFile);
    849 
    850         KeyStore ks = KeyStore.getInstance(type);
    851         ks.load(fis, KS_PASSWORD.toCharArray());
    852 
    853         KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory
    854                 .getDefaultAlgorithm());
    855         kmf.init(ks, KS_PASSWORD.toCharArray());
    856 
    857         TrustManagerFactory tmf = TrustManagerFactory
    858                 .getInstance(TrustManagerFactory.getDefaultAlgorithm());
    859         tmf.init(ks);
    860 
    861         ctx = SSLContext.getInstance("TLSv1");
    862         ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
    863 
    864         return ctx;
    865     }
    866 
    867     /**
    868      * Sets up the properties pointing to the key store and trust store and used
    869      * as default values by JSSE staff. This is needed to test HTTPS behaviour
    870      * in the case of default SSL Socket Factories.
    871      */
    872     private static void setUpStoreProperties() throws Exception {
    873         String type = KeyStore.getDefaultType();
    874 
    875         systemKeyStoreType = System.getProperty("javax.net.ssl.keyStoreType");
    876         systemKeyStore = System.getProperty("javax.net.ssl.keyStore");
    877         systemKeyStorePassword = System
    878                 .getProperty("javax.net.ssl.keyStorePassword");
    879 
    880         systemTrustStoreType = System
    881                 .getProperty("javax.net.ssl.trustStoreType");
    882         systemTrustStore = System.getProperty("javax.net.ssl.trustStore");
    883         systemTrustStorePassword = System
    884                 .getProperty("javax.net.ssl.trustStorePassword");
    885 
    886         System.setProperty("javax.net.ssl.keyStoreType", type);
    887         System.setProperty("javax.net.ssl.keyStore", getKeyStoreFileName());
    888         System.setProperty("javax.net.ssl.keyStorePassword", KS_PASSWORD);
    889 
    890         System.setProperty("javax.net.ssl.trustStoreType", type);
    891         System.setProperty("javax.net.ssl.trustStore", getKeyStoreFileName());
    892         System.setProperty("javax.net.ssl.trustStorePassword", KS_PASSWORD);
    893     }
    894 
    895     /**
    896      * Rolls back the values of system properties.
    897      */
    898     private static void tearDownStoreProperties() {
    899         if (systemKeyStoreType == null) {
    900             System.clearProperty("javax.net.ssl.keyStoreType");
    901         } else {
    902             System
    903                     .setProperty("javax.net.ssl.keyStoreType",
    904                             systemKeyStoreType);
    905         }
    906         if (systemKeyStore == null) {
    907             System.clearProperty("javax.net.ssl.keyStore");
    908         } else {
    909             System.setProperty("javax.net.ssl.keyStore", systemKeyStore);
    910         }
    911         if (systemKeyStorePassword == null) {
    912             System.clearProperty("javax.net.ssl.keyStorePassword");
    913         } else {
    914             System.setProperty("javax.net.ssl.keyStorePassword",
    915                     systemKeyStorePassword);
    916         }
    917 
    918         if (systemTrustStoreType == null) {
    919             System.clearProperty("javax.net.ssl.trustStoreType");
    920         } else {
    921             System.setProperty("javax.net.ssl.trustStoreType",
    922                     systemTrustStoreType);
    923         }
    924         if (systemTrustStore == null) {
    925             System.clearProperty("javax.net.ssl.trustStore");
    926         } else {
    927             System.setProperty("javax.net.ssl.trustStore", systemTrustStore);
    928         }
    929         if (systemTrustStorePassword == null) {
    930             System.clearProperty("javax.net.ssl.trustStorePassword");
    931         } else {
    932             System.setProperty("javax.net.ssl.trustStorePassword",
    933                     systemTrustStorePassword);
    934         }
    935     }
    936 
    937     /**
    938      * Performs interaction between client's HttpURLConnection and servers side
    939      * (ServerSocket).
    940      */
    941     public static Socket doInteraction(
    942             final HttpURLConnection clientConnection,
    943             final ServerSocket serverSocket) throws Throwable {
    944         return doInteraction(clientConnection, serverSocket, OK_CODE, false,
    945                 false);
    946     }
    947 
    948     /**
    949      * Performs interaction between client's HttpURLConnection and servers side
    950      * (ServerSocket). Server will response with specified response code.
    951      */
    952     public static Socket doInteraction(
    953             final HttpURLConnection clientConnection,
    954             final ServerSocket serverSocket, final int responseCode)
    955             throws Throwable {
    956         return doInteraction(clientConnection, serverSocket, responseCode,
    957                 false, false);
    958     }
    959 
    960     /**
    961      * Performs interaction between client's HttpURLConnection and servers side
    962      * (ServerSocket) over persistent connection.
    963      */
    964     public static Socket doPersistentInteraction(
    965             final HttpURLConnection clientConnection,
    966             final ServerSocket serverSocket) throws Throwable {
    967         return doInteraction(clientConnection, serverSocket, OK_CODE, false,
    968                 true);
    969     }
    970 
    971     /**
    972      * Performs interaction between client's HttpURLConnection and servers side
    973      * (ServerSocket) over persistent connection. Server will response with
    974      * specified response code.
    975      */
    976     public static Socket doPersistentInteraction(
    977             final HttpURLConnection clientConnection,
    978             final ServerSocket serverSocket, final int responseCode)
    979             throws Throwable {
    980         return doInteraction(clientConnection, serverSocket, responseCode,
    981                 false, true);
    982     }
    983 
    984     /**
    985      * Performs interaction between client's HttpURLConnection and servers side
    986      * (ServerSocket). Server will response with specified response code.
    987      *
    988      * @param doAuthentication
    989      *            specifies if the server needs client authentication.
    990      */
    991     public static Socket doInteraction(
    992             final HttpURLConnection clientConnection,
    993             final ServerSocket serverSocket, final int responseCode,
    994             final boolean doAuthentication, final boolean checkPersistence)
    995             throws Throwable {
    996 
    997         // set up the connection
    998         clientConnection.setDoInput(true);
    999         clientConnection.setConnectTimeout(TIMEOUT);
   1000         clientConnection.setReadTimeout(TIMEOUT);
   1001 
   1002         ServerWork server = new ServerWork(serverSocket, responseCode,
   1003                 doAuthentication, checkPersistence);
   1004 
   1005         ClientConnectionWork client = new ClientConnectionWork(clientConnection);
   1006 
   1007         server.start();
   1008         client.start();
   1009 
   1010         client.join();
   1011         if (client.thrown != null) {
   1012             if (responseCode != OK_CODE) { // not OK response expected
   1013                 // it is probably expected exception, keep it as is
   1014                 throw client.thrown;
   1015             }
   1016             if ((client.thrown instanceof SocketTimeoutException)
   1017                     && (server.thrown != null)) {
   1018                 // server's exception is more informative in this case
   1019                 throw new Exception(server.thrown);
   1020             } else {
   1021                 throw new Exception(client.thrown);
   1022             }
   1023         }
   1024 
   1025         if (checkPersistence) {
   1026             ClientConnectionWork client2 = new ClientConnectionWork(
   1027                     (HttpURLConnection) clientConnection.getURL()
   1028                             .openConnection());
   1029             client2.start();
   1030             client2.join();
   1031             if (client2.thrown != null) {
   1032                 if (responseCode != OK_CODE) { // not OK response expected
   1033                     // it is probably expected exception, keep it as is
   1034                     throw client2.thrown;
   1035                 }
   1036                 if ((client2.thrown instanceof SocketTimeoutException)
   1037                         && (server.thrown != null)) {
   1038                     // server's exception is more informative in this case
   1039                     throw new Exception(server.thrown);
   1040                 } else {
   1041                     throw new Exception(client2.thrown);
   1042                 }
   1043             }
   1044         }
   1045 
   1046         server.join();
   1047 
   1048         if (server.thrown != null) {
   1049             throw server.thrown;
   1050         }
   1051         return server.peerSocket;
   1052     }
   1053 
   1054     /**
   1055      * The host name verifier used in test.
   1056      */
   1057     static class TestHostnameVerifier implements HostnameVerifier {
   1058 
   1059         boolean verified = false;
   1060 
   1061         public boolean verify(String hostname, SSLSession session) {
   1062             if (DO_LOG) {
   1063                 System.out.println("***> verification " + hostname + " "
   1064                         + session.getPeerHost());
   1065             }
   1066             verified = true;
   1067             return true;
   1068         }
   1069     }
   1070 
   1071     /**
   1072      * The base class for mock Client and Server.
   1073      */
   1074     static class Work extends Thread {
   1075 
   1076         /**
   1077          * The header of OK HTTP response.
   1078          */
   1079         static String responseHead = "HTTP/1.1 200 OK\n";
   1080 
   1081         /**
   1082          * The content of the response.
   1083          */
   1084         static String plainResponseContent = "<HTML>\n"
   1085                 + "<HEAD><TITLE>Plain Response Content</TITLE></HEAD>\n"
   1086                 + "</HTML>";
   1087 
   1088         /**
   1089          * The tail of the response.
   1090          */
   1091         static String plainResponseTail = "Content-type: text/html\n"
   1092                 + "Content-length: " + plainResponseContent.length() + "\n\n"
   1093                 + plainResponseContent;
   1094 
   1095         /**
   1096          * The response message to be sent in plain (HTTP) format.
   1097          */
   1098         static String plainResponse = responseHead + plainResponseTail;
   1099 
   1100         /**
   1101          * The content of the response to be sent during HTTPS session.
   1102          */
   1103         static String httpsResponseContent = "<HTML>\n"
   1104                 + "<HEAD><TITLE>HTTPS Response Content</TITLE></HEAD>\n"
   1105                 + "</HTML>";
   1106 
   1107         /**
   1108          * The tail of the response to be sent during HTTPS session.
   1109          */
   1110         static String httpsResponseTail = "Content-type: text/html\n"
   1111                 + "Content-length: " + httpsResponseContent.length() + "\n\n"
   1112                 + httpsResponseContent;
   1113 
   1114         /**
   1115          * The response requiring client's proxy authentication.
   1116          */
   1117         static String respAuthenticationRequired = "HTTP/1.0 407 Proxy authentication required\n"
   1118                 + "Proxy-authenticate: Basic realm=\"localhost\"\n\n";
   1119 
   1120         /**
   1121          * The data to be posted by client to the server.
   1122          */
   1123         static String clientsData = "_.-^ Client's Data ^-._";
   1124 
   1125         /**
   1126          * The exception thrown during peers interaction.
   1127          */
   1128         protected Throwable thrown;
   1129 
   1130         /**
   1131          * The print stream used for debug log. If it is null debug info will
   1132          * not be printed.
   1133          */
   1134         private PrintStream out = new PrintStream(System.out);
   1135 
   1136         /**
   1137          * Prints log message.
   1138          */
   1139         public synchronized void log(String message) {
   1140             if (DO_LOG && (out != null)) {
   1141                 System.out.println("[" + getName() + "]: " + message);
   1142             }
   1143         }
   1144     }
   1145 
   1146     /**
   1147      * The class used for server side works.
   1148      */
   1149     static class ServerWork extends Work {
   1150 
   1151         // the server socket used for connection
   1152         private ServerSocket serverSocket;
   1153 
   1154         // the socket connected with client peer
   1155         private Socket peerSocket;
   1156 
   1157         // indicates if the server acts as proxy server
   1158         private boolean actAsProxy;
   1159 
   1160         // indicates if the server needs proxy authentication
   1161         private boolean needProxyAuthentication;
   1162 
   1163         // do we check for connection persistence
   1164         private boolean checkPersistence;
   1165 
   1166         // response code to be send to the client peer
   1167         private int responseCode;
   1168 
   1169         /**
   1170          * Creates the thread acting as a server side.
   1171          */
   1172         public ServerWork(ServerSocket serverSocket) {
   1173             // the server does not require proxy authentication
   1174             // and sends OK_CODE (OK) response code
   1175             this(serverSocket, OK_CODE, false, false);
   1176         }
   1177 
   1178         /**
   1179          * Creates the thread acting as a server side.
   1180          *
   1181          * @param serverSocket
   1182          *            the server socket to be used during connection
   1183          * @param responseCode
   1184          *            the response code to be sent to the client
   1185          * @param needProxyAuthentication
   1186          *            indicates if the server needs proxy authentication
   1187          */
   1188         public ServerWork(ServerSocket serverSocket, int responseCode,
   1189                 boolean needProxyAuthentication, boolean checkPersistence) {
   1190             this.serverSocket = serverSocket;
   1191             this.responseCode = responseCode;
   1192             this.needProxyAuthentication = needProxyAuthentication;
   1193             this.checkPersistence = checkPersistence;
   1194             // will act as a proxy server if the specified server socket
   1195             // is not a secure server socket
   1196             if (serverSocket instanceof SSLServerSocket) {
   1197                 // demand client to send its certificate
   1198                 ((SSLServerSocket) serverSocket).setNeedClientAuth(true);
   1199                 // work as a HTTPS server, not as HTTP proxy
   1200                 this.actAsProxy = false;
   1201             } else {
   1202                 this.actAsProxy = true;
   1203             }
   1204             this.actAsProxy = !(serverSocket instanceof SSLServerSocket);
   1205             setName(this.actAsProxy ? "Proxy Server" : "Server");
   1206         }
   1207 
   1208         /**
   1209          * Closes the connection.
   1210          */
   1211         public void closeSocket(Socket socket) {
   1212             try {
   1213                 socket.getInputStream().close();
   1214             } catch (IOException e) {
   1215             }
   1216             try {
   1217                 socket.getOutputStream().close();
   1218             } catch (IOException e) {
   1219             }
   1220             try {
   1221                 socket.close();
   1222             } catch (IOException e) {
   1223             }
   1224         }
   1225 
   1226         /**
   1227          * Performs the actual server work. If some exception occurs during the
   1228          * work it will be stored in the <code>thrown</code> field.
   1229          */
   1230         public void run() {
   1231             // the buffer used for reading the messages
   1232             byte[] buff = new byte[2048];
   1233             // the number of bytes read into the buffer
   1234             int num;
   1235             try {
   1236                 // configure the server socket to avoid blocking
   1237                 serverSocket.setSoTimeout(TIMEOUT);
   1238                 // accept client connection
   1239                 peerSocket = serverSocket.accept();
   1240                 // configure the client connection to avoid blocking
   1241                 peerSocket.setSoTimeout(TIMEOUT);
   1242                 log("Client connection ACCEPTED");
   1243 
   1244                 InputStream is = peerSocket.getInputStream();
   1245                 OutputStream os = peerSocket.getOutputStream();
   1246 
   1247                 // how many times established connection will be used
   1248                 int number_of_uses = checkPersistence ? 2 : 1;
   1249                 for (int it = 0; it < number_of_uses; it++) {
   1250                     if (checkPersistence) {
   1251                         log("==========================================");
   1252                         log("Use established connection for " + (it + 1)
   1253                                 + " time");
   1254                     }
   1255 
   1256                     num = is.read(buff);
   1257                     String message = new String(buff, 0, num, "UTF-8");
   1258                     log("Got request:\n" + message);
   1259                     log("------------------");
   1260 
   1261                     if (!actAsProxy) {
   1262                         // Act as Server (not Proxy) side
   1263                         if (message.startsWith("POST")) {
   1264                             // client connection sent some data
   1265                             log("try to read client data");
   1266                             num = is.read(buff);
   1267                             message = new String(buff, 0, num, "UTF-8");
   1268                             log("client's data: '" + message + "'");
   1269                             // check the received data
   1270                             assertEquals(clientsData, message);
   1271                         }
   1272                         // just send the response
   1273                         os
   1274                                 .write(("HTTP/1.1 " + responseCode + "\n" + httpsResponseTail)
   1275                                         .getBytes("UTF-8"));
   1276                         log("Simple NON-Proxy work is DONE");
   1277                         continue;
   1278                     }
   1279 
   1280                     // Do proxy work
   1281                     if (needProxyAuthentication) {
   1282                         log("Authentication required ...");
   1283                         // send Authentication Request
   1284                         os.write(respAuthenticationRequired.getBytes("UTF-8"));
   1285                         // read response
   1286                         num = is.read(buff);
   1287                         if (num == -1) {
   1288                             // this connection was closed,
   1289                             // do clean up and create new one:
   1290                             closeSocket(peerSocket);
   1291                             peerSocket = serverSocket.accept();
   1292                             peerSocket.setSoTimeout(TIMEOUT);
   1293                             log("New client connection ACCEPTED");
   1294                             is = peerSocket.getInputStream();
   1295                             os = peerSocket.getOutputStream();
   1296                             num = is.read(buff);
   1297                         }
   1298                         message = new String(buff, 0, num, "UTF-8");
   1299                         log("Got authenticated request:\n" + message);
   1300                         log("------------------");
   1301                         // check provided authorization credentials
   1302                         assertTrue("Received message does not contain "
   1303                                 + "authorization credentials",
   1304                                 message.toLowerCase().indexOf(
   1305                                         "proxy-authorization:") > 0);
   1306                     }
   1307 
   1308                     if (peerSocket instanceof SSLSocket) {
   1309                         // it will be so if we are have second iteration
   1310                         // over persistent connection
   1311                         os
   1312                                 .write(("HTTP/1.1 " + OK_CODE + "\n" + httpsResponseTail)
   1313                                         .getBytes("UTF-8"));
   1314                         log("Sent OK RESPONSE over SSL");
   1315                     } else {
   1316                         // The content of this response will reach proxied
   1317                         // HTTPUC but will not reach proxied HTTPSUC
   1318                         // In case of HTTP connection it will be the final
   1319                         // message, in case of HTTPS connection this message
   1320                         // will just indicate that connection with remote
   1321                         // host has been done
   1322                         // (i.e. SSL tunnel has been established).
   1323                         os.write(plainResponse.getBytes("UTF-8"));
   1324                         log("Sent OK RESPONSE");
   1325                     }
   1326 
   1327                     if (message.startsWith("CONNECT")) { // request for SSL
   1328                                                             // tunnel
   1329                         log("Perform SSL Handshake...");
   1330                         // create sslSocket acting as a remote server peer
   1331                         SSLSocket sslSocket = (SSLSocket) getContext()
   1332                                 .getSocketFactory()
   1333                                 .createSocket(peerSocket, "localhost",
   1334                                         peerSocket.getPort(), true); // do
   1335                                                                         // autoclose
   1336                         sslSocket.setUseClientMode(false);
   1337                         // demand client authentication
   1338                         sslSocket.setNeedClientAuth(true);
   1339                         sslSocket.startHandshake();
   1340                         peerSocket = sslSocket;
   1341                         is = peerSocket.getInputStream();
   1342                         os = peerSocket.getOutputStream();
   1343 
   1344                         // read the HTTP request sent by secure connection
   1345                         // (HTTPS request)
   1346                         num = is.read(buff);
   1347                         message = new String(buff, 0, num, "UTF-8");
   1348                         log("[Remote Server] Request from SSL tunnel:\n"
   1349                                 + message);
   1350                         log("------------------");
   1351 
   1352                         if (message.startsWith("POST")) {
   1353                             // client connection sent some data
   1354                             log("[Remote Server] try to read client data");
   1355                             num = is.read(buff);
   1356                             message = new String(buff, 0, num, "UTF-8");
   1357                             log("[Remote Server] client's data: '" + message
   1358                                     + "'");
   1359                             // check the received data
   1360                             assertEquals(clientsData, message);
   1361                         }
   1362 
   1363                         log("[Remote Server] Sending the response by SSL tunnel..");
   1364                         // send the response with specified response code
   1365                         os
   1366                                 .write(("HTTP/1.1 " + responseCode + "\n" + httpsResponseTail)
   1367                                         .getBytes("UTF-8"));
   1368                     }
   1369                     log("Work is DONE");
   1370                 }
   1371                 ;
   1372             } catch (Throwable e) {
   1373                 if (DO_LOG) {
   1374                     e.printStackTrace();
   1375                 }
   1376                 thrown = e;
   1377             } finally {
   1378                 closeSocket(peerSocket);
   1379                 try {
   1380                     serverSocket.close();
   1381                 } catch (IOException e) {
   1382                 }
   1383             }
   1384         }
   1385     }
   1386 
   1387     /**
   1388      * The class used for client side works. It could be used to test both
   1389      * HttpURLConnection and HttpsURLConnection.
   1390      */
   1391     static class ClientConnectionWork extends Work {
   1392 
   1393         // connection to be used to contact the server side
   1394         private HttpURLConnection connection;
   1395 
   1396         /**
   1397          * Creates the thread acting as a client side.
   1398          *
   1399          * @param connection
   1400          *            connection to be used to contact the server side
   1401          */
   1402         public ClientConnectionWork(HttpURLConnection connection) {
   1403             this.connection = connection;
   1404             setName("Client Connection");
   1405             log("Created over connection: " + connection.getClass());
   1406         }
   1407 
   1408         /**
   1409          * Performs the actual client work. If some exception occurs during the
   1410          * work it will be stored in the <code>thrown<code> field.
   1411          */
   1412         public void run() {
   1413             try {
   1414                 log("Opening the connection..");
   1415                 connection.connect();
   1416                 log("Connection has been ESTABLISHED, using proxy: "
   1417                         + connection.usingProxy());
   1418                 if (connection.getDoOutput()) {
   1419                     // connection configured to post data, do so
   1420                     connection.getOutputStream().write(clientsData.getBytes("UTF-8"));
   1421                 }
   1422                 // read the content of HTTP(s) response
   1423                 InputStream is = connection.getInputStream();
   1424                 log("Input Stream obtained: " + is.getClass());
   1425                 byte[] buff = new byte[2048];
   1426                 int num = 0;
   1427                 int byt = 0;
   1428                 while ((num < buff.length) && (is.available() > 0)
   1429                         && ((byt = is.read()) != -1)) {
   1430                     buff[num++] = (byte) byt;
   1431                 }
   1432                 String message = new String(buff, 0, num, "UTF-8");
   1433                 log("Got content:\n" + message);
   1434                 log("------------------");
   1435                 log("Response code: " + connection.getResponseCode());
   1436 
   1437                 if (connection instanceof HttpsURLConnection) {
   1438                     assertEquals(httpsResponseContent, message);
   1439                 } else {
   1440                     assertEquals(plainResponseContent, message);
   1441                 }
   1442             } catch (Throwable e) {
   1443                 if (DO_LOG) {
   1444                     e.printStackTrace();
   1445                 }
   1446                 thrown = e;
   1447             }
   1448         }
   1449     }
   1450 
   1451     public static junit.framework.Test suite() {
   1452         return new TestSuite(HttpsURLConnectionTest.class);
   1453     }
   1454 
   1455 }
   1456