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