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