| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 import "package:expect/expect.dart"; | 5 import "package:expect/expect.dart"; |
| 6 import "dart:async"; | 6 import "dart:async"; |
| 7 import 'dart:crypto'; |
| 7 import "dart:io"; | 8 import "dart:io"; |
| 8 import "dart:uri"; | 9 import "dart:uri"; |
| 10 import 'dart:utf'; |
| 9 | 11 |
| 10 class Server { | 12 class Server { |
| 11 HttpServer server; | 13 HttpServer server; |
| 12 bool secure; | 14 bool secure; |
| 13 int proxyHops; | 15 int proxyHops; |
| 14 List<String> directRequestPaths; | 16 List<String> directRequestPaths; |
| 15 int requestCount = 0; | 17 int requestCount = 0; |
| 16 | 18 |
| 17 Server(this.proxyHops, this.directRequestPaths, this.secure); | 19 Server(this.proxyHops, this.directRequestPaths, this.secure); |
| 18 | 20 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 41 } else { | 43 } else { |
| 42 Expect.isNull(request.headers[HttpHeaders.VIA]); | 44 Expect.isNull(request.headers[HttpHeaders.VIA]); |
| 43 } | 45 } |
| 44 var body = new StringBuffer(); | 46 var body = new StringBuffer(); |
| 45 request.listen( | 47 request.listen( |
| 46 (data) { | 48 (data) { |
| 47 body.write(new String.fromCharCodes(data)); | 49 body.write(new String.fromCharCodes(data)); |
| 48 }, | 50 }, |
| 49 onDone: () { | 51 onDone: () { |
| 50 String path = request.uri.path.substring(1); | 52 String path = request.uri.path.substring(1); |
| 51 String content = "$path$path$path"; | 53 if (path != "A") { |
| 52 Expect.equals(content, body.toString()); | 54 String content = "$path$path$path"; |
| 55 Expect.equals(content, body.toString()); |
| 56 } |
| 53 response.write(request.uri.path); | 57 response.write(request.uri.path); |
| 54 response.close(); | 58 response.close(); |
| 55 }); | 59 }); |
| 56 }); | 60 }); |
| 57 return x.future; | 61 return x.future; |
| 58 }); | 62 }); |
| 59 } | 63 } |
| 60 | 64 |
| 61 void shutdown() { | 65 void shutdown() { |
| 62 server.close(); | 66 server.close(); |
| 63 } | 67 } |
| 64 | 68 |
| 65 int get port => server.port; | 69 int get port => server.port; |
| 66 } | 70 } |
| 67 | 71 |
| 68 Future<Server> setupServer(int proxyHops, | 72 Future<Server> setupServer(int proxyHops, |
| 69 {List<String> directRequestPaths: const <String>[], | 73 {List<String> directRequestPaths: const <String>[], |
| 70 secure: false}) { | 74 secure: false}) { |
| 71 Server server = new Server(proxyHops, directRequestPaths, secure); | 75 Server server = new Server(proxyHops, directRequestPaths, secure); |
| 72 return server.start(); | 76 return server.start(); |
| 73 } | 77 } |
| 74 | 78 |
| 75 class ProxyServer { | 79 class ProxyServer { |
| 76 HttpServer server; | 80 HttpServer server; |
| 77 HttpClient client; | 81 HttpClient client; |
| 78 int requestCount = 0; | 82 int requestCount = 0; |
| 83 String username; |
| 84 String password; |
| 79 | 85 |
| 80 ProxyServer() : client = new HttpClient(); | 86 ProxyServer() : client = new HttpClient(); |
| 81 | 87 |
| 88 authenticationRequired(request) { |
| 89 request.fold(null, (x, y) {}).then((_) { |
| 90 var response = request.response; |
| 91 response.headers.set(HttpHeaders.PROXY_AUTHENTICATE, |
| 92 "Basic, realm=realm"); |
| 93 response.statusCode = HttpStatus.PROXY_AUTHENTICATION_REQUIRED; |
| 94 response.close(); |
| 95 }); |
| 96 } |
| 97 |
| 82 Future<ProxyServer> start() { | 98 Future<ProxyServer> start() { |
| 83 var x = new Completer(); | 99 var x = new Completer(); |
| 84 HttpServer.bind().then((s) { | 100 HttpServer.bind().then((s) { |
| 85 server = s; | 101 server = s; |
| 86 x.complete(this); | 102 x.complete(this); |
| 87 server.listen((HttpRequest request) { | 103 server.listen((HttpRequest request) { |
| 88 requestCount++; | 104 requestCount++; |
| 105 if (username != null && password != null) { |
| 106 if (request.headers[HttpHeaders.PROXY_AUTHORIZATION] == null) { |
| 107 authenticationRequired(request); |
| 108 return; |
| 109 } else { |
| 110 Expect.equals( |
| 111 1, request.headers[HttpHeaders.PROXY_AUTHORIZATION].length); |
| 112 String authorization = |
| 113 request.headers[HttpHeaders.PROXY_AUTHORIZATION][0]; |
| 114 List<String> tokens = authorization.split(" "); |
| 115 Expect.equals("Basic", tokens[0]); |
| 116 String auth = |
| 117 CryptoUtils.bytesToBase64(encodeUtf8("$username:$password")); |
| 118 if (auth != tokens[1]) { |
| 119 authenticationRequired(request); |
| 120 return; |
| 121 } |
| 122 } |
| 123 } |
| 89 // Open the connection from the proxy. | 124 // Open the connection from the proxy. |
| 90 client.openUrl(request.method, request.uri) | 125 client.openUrl(request.method, request.uri) |
| 91 .then((HttpClientRequest clientRequest) { | 126 .then((HttpClientRequest clientRequest) { |
| 92 // Forward all headers. | 127 // Forward all headers. |
| 93 request.headers.forEach((String name, List<String> values) { | 128 request.headers.forEach((String name, List<String> values) { |
| 94 values.forEach((String value) { | 129 values.forEach((String value) { |
| 95 if (name != "content-length" && name != "via") { | 130 if (name != "content-length" && name != "via") { |
| 96 clientRequest.headers.add(name, value); | 131 clientRequest.headers.add(name, value); |
| 97 } | 132 } |
| 98 }); | 133 }); |
| (...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 355 } | 390 } |
| 356 | 391 |
| 357 test(false); | 392 test(false); |
| 358 test(true); | 393 test(true); |
| 359 } | 394 } |
| 360 }); | 395 }); |
| 361 }); | 396 }); |
| 362 }); | 397 }); |
| 363 } | 398 } |
| 364 | 399 |
| 400 |
| 401 int testProxyAuthenticateCount = 0; |
| 402 void testProxyAuthenticate() { |
| 403 setupProxyServer().then((proxyServer) { |
| 404 proxyServer.username = "test"; |
| 405 proxyServer.password = "test"; |
| 406 setupServer(1).then((server) { |
| 407 setupServer(1, secure: true).then((secureServer) { |
| 408 HttpClient client = new HttpClient(); |
| 409 |
| 410 Completer step1 = new Completer(); |
| 411 Completer step2 = new Completer(); |
| 412 |
| 413 // Test with no authentication. |
| 414 client.findProxy = (Uri uri) { |
| 415 return "PROXY localhost:${proxyServer.port}"; |
| 416 }; |
| 417 |
| 418 const int loopCount = 2; |
| 419 for (int i = 0; i < loopCount; i++) { |
| 420 test(bool secure) { |
| 421 String url = secure |
| 422 ? "https://localhost:${secureServer.port}/$i" |
| 423 : "http://127.0.0.1:${server.port}/$i"; |
| 424 |
| 425 client.postUrl(Uri.parse(url)) |
| 426 .then((HttpClientRequest clientRequest) { |
| 427 String content = "$i$i$i"; |
| 428 clientRequest.write(content); |
| 429 return clientRequest.close(); |
| 430 }) |
| 431 .then((HttpClientResponse response) { |
| 432 response.listen((_) {}, onDone: () { |
| 433 testProxyAuthenticateCount++; |
| 434 Expect.equals(HttpStatus.PROXY_AUTHENTICATION_REQUIRED, |
| 435 response.statusCode); |
| 436 if (testProxyAuthenticateCount == loopCount * 2) { |
| 437 Expect.equals(0, server.requestCount); |
| 438 Expect.equals(0, secureServer.requestCount); |
| 439 step1.complete(null); |
| 440 } |
| 441 }); |
| 442 }); |
| 443 } |
| 444 |
| 445 test(false); |
| 446 test(true); |
| 447 } |
| 448 |
| 449 step1.future.then((_) { |
| 450 testProxyAuthenticateCount = 0; |
| 451 client.findProxy = (Uri uri) { |
| 452 return "PROXY test:test@localhost:${proxyServer.port}"; |
| 453 }; |
| 454 |
| 455 for (int i = 0; i < loopCount; i++) { |
| 456 test(bool secure) { |
| 457 String url = secure |
| 458 ? "https://localhost:${secureServer.port}/$i" |
| 459 : "http://127.0.0.1:${server.port}/$i"; |
| 460 |
| 461 client.postUrl(Uri.parse(url)) |
| 462 .then((HttpClientRequest clientRequest) { |
| 463 String content = "$i$i$i"; |
| 464 clientRequest.write(content); |
| 465 return clientRequest.close(); |
| 466 }) |
| 467 .then((HttpClientResponse response) { |
| 468 response.listen((_) {}, onDone: () { |
| 469 testProxyAuthenticateCount++; |
| 470 Expect.equals(HttpStatus.OK, response.statusCode); |
| 471 if (testProxyAuthenticateCount == loopCount * 2) { |
| 472 Expect.equals(loopCount, server.requestCount); |
| 473 Expect.equals(loopCount, secureServer.requestCount); |
| 474 step2.complete(null); |
| 475 } |
| 476 }); |
| 477 }); |
| 478 } |
| 479 |
| 480 test(false); |
| 481 test(true); |
| 482 } |
| 483 }); |
| 484 |
| 485 step2.future.then((_) { |
| 486 testProxyAuthenticateCount = 0; |
| 487 client.findProxy = (Uri uri) { |
| 488 return "PROXY localhost:${proxyServer.port}"; |
| 489 }; |
| 490 |
| 491 client.authenticateProxy = (host, port, scheme, realm) { |
| 492 client.addProxyCredentials( |
| 493 "localhost", |
| 494 proxyServer.port, |
| 495 "realm", |
| 496 new HttpClientBasicCredentials("test", "test")); |
| 497 return new Future.immediate(true); |
| 498 }; |
| 499 |
| 500 for (int i = 0; i < loopCount; i++) { |
| 501 test(bool secure) { |
| 502 String url = secure |
| 503 ? "https://localhost:${secureServer.port}/A" |
| 504 : "http://127.0.0.1:${server.port}/A"; |
| 505 |
| 506 client.postUrl(Uri.parse(url)) |
| 507 .then((HttpClientRequest clientRequest) { |
| 508 String content = "$i$i$i"; |
| 509 clientRequest.write(content); |
| 510 return clientRequest.close(); |
| 511 }) |
| 512 .then((HttpClientResponse response) { |
| 513 response.listen((_) {}, onDone: () { |
| 514 testProxyAuthenticateCount++; |
| 515 Expect.equals(HttpStatus.OK, response.statusCode); |
| 516 if (testProxyAuthenticateCount == loopCount * 2) { |
| 517 Expect.equals(loopCount * 2, server.requestCount); |
| 518 Expect.equals(loopCount * 2, secureServer.requestCount); |
| 519 proxyServer.shutdown(); |
| 520 server.shutdown(); |
| 521 secureServer.shutdown(); |
| 522 client.close(); |
| 523 } |
| 524 }); |
| 525 }); |
| 526 } |
| 527 test(false); |
| 528 test(true); |
| 529 } |
| 530 }); |
| 531 |
| 532 }); |
| 533 }); |
| 534 }); |
| 535 } |
| 536 |
| 365 int testRealProxyDoneCount = 0; | 537 int testRealProxyDoneCount = 0; |
| 366 void testRealProxy() { | 538 void testRealProxy() { |
| 367 setupServer(1).then((server) { | 539 setupServer(1).then((server) { |
| 368 HttpClient client = new HttpClient(); | 540 HttpClient client = new HttpClient(); |
| 541 client.addProxyCredentials("localhost", |
| 542 8080, |
| 543 "test", |
| 544 new HttpClientBasicCredentials("test", "test")); |
| 369 | 545 |
| 370 List<String> proxy = | 546 List<String> proxy = |
| 371 ["PROXY localhost:8080", | 547 ["PROXY localhost:8080", |
| 372 "PROXY localhost:8080; PROXY hede.hule.hest:8080", | 548 "PROXY localhost:8080; PROXY hede.hule.hest:8080", |
| 373 "PROXY hede.hule.hest:8080; PROXY localhost:8080", | 549 "PROXY hede.hule.hest:8080; PROXY localhost:8080", |
| 374 "PROXY localhost:8080; DIRECT"]; | 550 "PROXY localhost:8080; DIRECT"]; |
| 375 | 551 |
| 376 client.findProxy = (Uri uri) { | 552 client.findProxy = (Uri uri) { |
| 377 // Pick the proxy configuration based on the request path. | 553 // Pick the proxy configuration based on the request path. |
| 378 int index = int.parse(uri.path.substring(1)); | 554 int index = int.parse(uri.path.substring(1)); |
| 379 return proxy[index]; | 555 return proxy[index]; |
| 380 }; | 556 }; |
| 381 | 557 |
| 382 for (int i = 0; i < proxy.length; i++) { | 558 for (int i = 0; i < proxy.length; i++) { |
| 383 client.getUrl(Uri.parse("http://127.0.0.1:${server.port}/$i")) | 559 client.getUrl(Uri.parse("http://127.0.0.1:${server.port}/$i")) |
| 384 .then((HttpClientRequest clientRequest) { | 560 .then((HttpClientRequest clientRequest) { |
| 385 String content = "$i$i$i"; | 561 String content = "$i$i$i"; |
| 386 clientRequest.contentLength = content.length; | 562 clientRequest.contentLength = content.length; |
| 387 clientRequest.write(content); | 563 clientRequest.write(content); |
| 388 return clientRequest.close(); | 564 return clientRequest.close(); |
| 389 }) | 565 }) |
| 390 .then((HttpClientResponse response) { | 566 .then((HttpClientResponse response) { |
| 391 response.listen((_) {}, onDone: () { | 567 response.listen((_) {}, onDone: () { |
| 392 testRealProxyDoneCount++; | 568 if (++testRealProxyDoneCount == proxy.length) { |
| 393 if (testRealProxyDoneCount == proxy.length) { | |
| 394 Expect.equals(proxy.length, server.requestCount); | 569 Expect.equals(proxy.length, server.requestCount); |
| 395 server.shutdown(); | 570 server.shutdown(); |
| 396 client.close(); | 571 client.close(); |
| 572 } |
| 573 }); |
| 574 }); |
| 575 } |
| 576 }); |
| 577 } |
| 578 |
| 579 int testRealProxyAuthDoneCount = 0; |
| 580 void testRealProxyAuth() { |
| 581 setupServer(1).then((server) { |
| 582 HttpClient client = new HttpClient(); |
| 583 |
| 584 List<String> proxy = |
| 585 ["PROXY test:test@localhost:8080", |
| 586 "PROXY test:test@localhost:8080; PROXY hede.hule.hest:8080", |
| 587 "PROXY hede.hule.hest:8080; PROXY test:test@localhost:8080", |
| 588 "PROXY test:test@localhost:8080; DIRECT"]; |
| 589 |
| 590 client.findProxy = (Uri uri) { |
| 591 // Pick the proxy configuration based on the request path. |
| 592 int index = int.parse(uri.path.substring(1)); |
| 593 return proxy[index]; |
| 594 }; |
| 595 |
| 596 for (int i = 0; i < proxy.length; i++) { |
| 597 client.getUrl(Uri.parse("http://127.0.0.1:${server.port}/$i")) |
| 598 .then((HttpClientRequest clientRequest) { |
| 599 String content = "$i$i$i"; |
| 600 clientRequest.contentLength = content.length; |
| 601 clientRequest.write(content); |
| 602 return clientRequest.close(); |
| 603 }) |
| 604 .then((HttpClientResponse response) { |
| 605 response.listen((_) {}, onDone: () { |
| 606 if (++testRealProxyAuthDoneCount == proxy.length) { |
| 607 Expect.equals(proxy.length, server.requestCount); |
| 608 server.shutdown(); |
| 609 client.close(); |
| 397 } | 610 } |
| 398 }); | 611 }); |
| 399 }); | 612 }); |
| 400 } | 613 } |
| 401 }); | 614 }); |
| 402 } | 615 } |
| 403 | 616 |
| 404 void InitializeSSL() { | 617 void InitializeSSL() { |
| 405 var testPkcertDatabase = | 618 var testPkcertDatabase = |
| 406 new Path(new Options().script).directoryPath.append('pkcert/'); | 619 new Path(new Options().script).directoryPath.append('pkcert/'); |
| 407 SecureSocket.initialize(database: testPkcertDatabase.toNativePath(), | 620 SecureSocket.initialize(database: testPkcertDatabase.toNativePath(), |
| 408 password: 'dartdart'); | 621 password: 'dartdart'); |
| 409 } | 622 } |
| 410 | 623 |
| 411 main() { | 624 main() { |
| 412 InitializeSSL(); | 625 InitializeSSL(); |
| 413 testInvalidProxy(); | 626 testInvalidProxy(); |
| 414 testDirectProxy(); | 627 testDirectProxy(); |
| 415 testProxy(); | 628 testProxy(); |
| 416 testProxyChain(); | 629 testProxyChain(); |
| 417 testProxyFromEnviroment(); | 630 testProxyFromEnviroment(); |
| 631 testProxyAuthenticate(); |
| 418 // This test is not normally run. It can be used for locally testing | 632 // This test is not normally run. It can be used for locally testing |
| 419 // with a real proxy server (e.g. Apache). | 633 // with a real proxy server (e.g. Apache). |
| 420 //testRealProxy(); | 634 //testRealProxy(); |
| 635 //testRealProxyAuth(); |
| 421 } | 636 } |
| OLD | NEW |