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