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