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