Add a function for finding the HTTP proxy server from environment variables

R=ager@google.com

BUG=https://code.google.com/p/dart/issues/detail?id=5468

Review URL: https://codereview.chromium.org//12866005

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@20202 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
sgjesse@google.com 2013-03-19 12:59:52 +00:00
parent 076fa4c0ba
commit 484a94834b
4 changed files with 215 additions and 0 deletions

View file

@ -866,9 +866,63 @@ abstract class HttpClient {
* separated by semicolons, e.g.
*
* "PROXY host:port; PROXY host2:port2; DIRECT"
*
* The static function [findProxyFromEnvironment] on this class can
* be used to implement proxy server resolving based on environment
* variables.
*/
set findProxy(String f(Uri url));
/**
* Function for resolving the proxy server to be used for a HTTP
* connection from the proxy configuration specified through
* environment variables.
*
* The following environment variables are taken into account:
*
* * http_proxy
* * https_proxy
* * no_proxy
* * HTTP_PROXY
* * HTTPS_PROXY
* * NO_PROXY
*
* [:http_proxy:] and [:HTTP_PROXY:] specify the proxy server to use for
* http:// urls. Use the format [:hostname:port:]. If no port is used a
* default of 1080 will be used. If both are set the lower case one takes
* precedence.
*
* [:https_proxy:] and [:HTTPS_PROXY:] specify the proxy server to use for
* https:// urls. Use the format [:hostname:port:]. If no port is used a
* default of 1080 will be used. If both are set the lower case one takes
* precedence.
*
* [:no_proxy:] and [:NO_PROXY:] specify a comma separated list of
* postfixes of hostnames for which not to use the proxy
* server. E.g. the value "localhost,127.0.0.1" will make requests
* to both "localhost" and "127.0.0.1" not use a proxy. If both are set
* the lower case one takes precedence.
*
* To activate this way of resolving proxies assign this function to
* the [findProxy] property on the [HttpClient].
*
* HttpClient client = new HttpClient();
* client.findProxy = HttpClient.findProxyFromEnvironment;
*
* If you don't want to use the system environment you can use a
* different one by wrapping the function.
*
* HttpClient client = new HttpClient();
* client.findProxy = (url) {
* return HttpClient.findProxyFromEnvironment(
* url, {"http_proxy": ..., "no_proxy": ...});
* }
*/
static String findProxyFromEnvironment(Uri url,
{Map<String, String> environment}) {
return _HttpClient._findProxyFromEnvironment(url, environment);
}
/**
* Shutdown the HTTP client. If [force] is [:false:] (the default)
* the [:HttpClient:] will be kept alive until all active

View file

@ -1258,6 +1258,56 @@ class _HttpClient implements HttpClient {
_credentials.removeAt(index);
}
}
static String _findProxyFromEnvironment(Uri url,
Map<String, String> environment) {
checkNoProxy(String option) {
if (option == null) return null;
Iterator<String> names = option.split(",").map((s) => s.trim()).iterator;
while (names.moveNext()) {
if (url.domain.endsWith(names.current)) {
return "DIRECT";
}
}
return null;
}
checkProxy(String option) {
if (option == null) return null;
int pos = option.indexOf("://");
if (pos >= 0) {
option = option.substring(pos + 3);
}
if (option.indexOf(":") == -1) option = "$option:1080";
return "PROXY $option";
}
// Default to using the process current environment.
if (environment == null) environment = Platform.environment;
String proxyCfg;
String noProxy = environment["no_proxy"];
if (noProxy == null) noProxy = environment["NO_PROXY"];
if ((proxyCfg = checkNoProxy(noProxy)) != null) {
return proxyCfg;
}
if (url.scheme == "http") {
String proxy = environment["http_proxy"];
if (proxy == null) proxy = environment["HTTP_PROXY"];
if ((proxyCfg = checkProxy(proxy)) != null) {
return proxyCfg;
}
} else if (url.scheme == "https") {
String proxy = environment["https_proxy"];
if (proxy == null) proxy = environment["HTTPS_PROXY"];
if ((proxyCfg = checkProxy(proxy)) != null) {
return proxyCfg;
}
}
return "DIRECT";
}
}

View file

@ -0,0 +1,59 @@
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import "dart:io";
import "dart:uri";
expect(expected, String uri, environment) {
Expect.equals(expected,
HttpClient.findProxyFromEnvironment(Uri.parse(uri),
environment: environment));
}
expectDirect(String uri, environment) {
Expect.equals("DIRECT",
HttpClient.findProxyFromEnvironment(Uri.parse(uri),
environment: environment));
}
main() {
expectDirect("http://www.google.com", {});
expect("PROXY www.proxy.com:1080",
"http://www.google.com",
{"http_proxy": "www.proxy.com"});
expect("PROXY www.proxys.com:1080",
"https://www.google.com",
{"https_proxy": "www.proxys.com"});
expect("PROXY www.proxy.com:8080",
"http://www.google.com",
{"http_proxy": "www.proxy.com:8080"});
expect("PROXY www.proxys.com:8080",
"https://www.google.com",
{"https_proxy": "www.proxys.com:8080"});
expect("PROXY www.proxy.com:8080",
"http://www.google.com",
{"http_proxy": "www.proxy.com:8080",
"https_proxy": "www.proxy.com:8080"});
expect("PROXY www.proxys.com:8080",
"https://www.google.com",
{"http_proxy": "www.proxy.com:8080",
"https_proxy": "www.proxys.com:8080"});
expectDirect("http://www.google.com",
{"http_proxy": "www.proxy.com:8080",
"no_proxy": "www.google.com"});
expectDirect("http://www.google.com",
{"http_proxy": "www.proxy.com:8080",
"no_proxy": "google.com"});
expectDirect("http://www.google.com",
{"http_proxy": "www.proxy.com:8080",
"no_proxy": ".com"});
expectDirect("http://www.google.com",
{"http_proxy": "www.proxy.com:8080",
"no_proxy": ",, , www.google.edu,,.com "});
expectDirect("http://www.google.edu",
{"http_proxy": "www.proxy.com:8080",
"no_proxy": ",, , www.google.edu,,.com "});
expectDirect("http://www.google.com",
{"https_proxy": "www.proxy.com:8080"});
}

View file

@ -232,6 +232,7 @@ void testProxy() {
testProxyDoneCount++;
if (testProxyDoneCount == proxy.length * 2) {
Expect.equals(proxy.length, server.requestCount);
Expect.equals(proxy.length, secureServer.requestCount);
proxyServer.shutdown();
server.shutdown();
secureServer.shutdown();
@ -311,6 +312,56 @@ void testProxyChain() {
});
}
int testProxyFromEnviromentDoneCount = 0;
void testProxyFromEnviroment() {
setupProxyServer().then((proxyServer) {
setupServer(1).then((server) {
setupServer(1, secure: true).then((secureServer) {
HttpClient client = new HttpClient();
client.findProxy = (Uri uri) {
return HttpClient.findProxyFromEnvironment(
uri,
environment: {"http_proxy": "localhost:${proxyServer.port}",
"https_proxy": "localhost:${proxyServer.port}"});
};
const int loopCount = 5;
for (int i = 0; i < loopCount; i++) {
test(bool secure) {
String url = secure
? "https://localhost:${secureServer.port}/$i"
: "http://127.0.0.1:${server.port}/$i";
client.postUrl(Uri.parse(url))
.then((HttpClientRequest clientRequest) {
String content = "$i$i$i";
clientRequest.write(content);
return clientRequest.close();
})
.then((HttpClientResponse response) {
response.listen((_) {}, onDone: () {
testProxyFromEnviromentDoneCount++;
if (testProxyFromEnviromentDoneCount == loopCount * 2) {
Expect.equals(loopCount, server.requestCount);
Expect.equals(loopCount, secureServer.requestCount);
proxyServer.shutdown();
server.shutdown();
secureServer.shutdown();
client.close();
}
});
});
}
test(false);
test(true);
}
});
});
});
}
int testRealProxyDoneCount = 0;
void testRealProxy() {
setupServer(1).then((server) {
@ -363,6 +414,7 @@ main() {
testDirectProxy();
testProxy();
testProxyChain();
testProxyFromEnviroment();
// This test is not normally run. It can be used for locally testing
// with a real proxy server (e.g. Apache).
//testRealProxy();