Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(275)

Unified Diff: runtime/bin/http_impl.dart

Issue 11066041: Add support for HTTP proxy in the HTTP client (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Addressed review comments from ajohnsen@ Created 8 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: runtime/bin/http_impl.dart
diff --git a/runtime/bin/http_impl.dart b/runtime/bin/http_impl.dart
index eec6b398b243fb45040d388eb4e94c55fd99a4aa..935781e1f784bfbe611a16bd3b3f7796486527af 100644
--- a/runtime/bin/http_impl.dart
+++ b/runtime/bin/http_impl.dart
@@ -846,6 +846,7 @@ class _HttpRequest extends _HttpRequestResponseBase implements HttpRequest {
InputStream get inputStream {
if (_inputStream == null) {
_inputStream = new _HttpInputStream(this);
+ _inputStream._streamMarkedClosed = _dataEndCalled;
}
return _inputStream;
}
@@ -875,6 +876,7 @@ class _HttpRequest extends _HttpRequestResponseBase implements HttpRequest {
void _onDataEnd() {
if (_inputStream != null) _inputStream._closeReceived();
+ _dataEndCalled = true;
}
// Escaped characters in uri are expected to have been parsed.
@@ -917,6 +919,7 @@ class _HttpRequest extends _HttpRequestResponseBase implements HttpRequest {
Map<String, String> _queryParameters;
_HttpInputStream _inputStream;
_BufferList _buffer;
+ bool _dataEndCalled = false;
Function _streamErrorHandler;
}
@@ -1544,7 +1547,7 @@ class _HttpServer implements HttpServer {
class _HttpClientRequest
extends _HttpRequestResponseBase implements HttpClientRequest {
_HttpClientRequest(String this._method,
- String this._uri,
+ Uri this._uri,
_HttpClientConnection connection)
: super(connection) {
_connection = connection;
@@ -1613,7 +1616,23 @@ class _HttpClientRequest
data = _method.toString().charCodes();
_httpConnection._write(data);
_writeSP();
- data = _uri.toString().charCodes();
+ // Send the path for direct connections and the whole URL for
+ // proxy connections.
+ if (!_connection._usingProxy) {
+ String path;
+ if (_uri.query != "") {
+ if (_uri.fragment != "") {
+ path = "${_uri.path}?${_uri.query}#${_uri.fragment}";
+ } else {
+ path = "${_uri.path}?${_uri.query}";
+ }
+ } else {
+ path = _uri.path;
+ }
+ data = path.charCodes();
+ } else {
+ data = _uri.toString().charCodes();
+ }
_httpConnection._write(data);
_writeSP();
_httpConnection._write(_Const.HTTP11);
@@ -1646,7 +1665,7 @@ class _HttpClientRequest
}
String _method;
- String _uri;
+ Uri _uri;
_HttpClientConnection _connection;
_HttpOutputStream _outputStream;
Function _streamErrorHandler;
@@ -1685,6 +1704,7 @@ class _HttpClientResponse
InputStream get inputStream {
if (_inputStream == null) {
_inputStream = new _HttpInputStream(this);
+ _inputStream._streamMarkedClosed = _dataEndCalled;
}
return _inputStream;
}
@@ -1746,6 +1766,7 @@ class _HttpClientResponse
void _onDataEnd() {
_connection._responseDone();
if (_inputStream != null) _inputStream._closeReceived();
+ _dataEndCalled = true;
}
// Delegate functions for the HttpInputStream implementation.
@@ -1773,6 +1794,8 @@ class _HttpClientResponse
_HttpClientConnection _connection;
_HttpInputStream _inputStream;
_BufferList _buffer;
+ bool _dataEndCalled = false;
+
Function _streamErrorHandler;
}
@@ -1810,7 +1833,7 @@ class _HttpClientConnection
_socketConn = null;
}
- HttpClientRequest open(String method, String uri) {
+ HttpClientRequest open(String method, Uri uri) {
_method = method;
// Tell the HTTP parser the method it is expecting a response to.
_httpParser.responseToMethod = method;
@@ -1913,6 +1936,7 @@ class _HttpClientConnection
HttpClientRequest _request;
HttpClientResponse _response;
String _method;
+ bool _usingProxy;
// Redirect handling
bool followRedirects = true;
@@ -1948,6 +1972,58 @@ class _SocketConnection {
Date _returnTime;
}
+class _ProxyConfiguration {
+ static const String PROXY_PREFIX = "PROXY ";
+ static const String DIRECT_PREFIX = "DIRECT";
+
+ _ProxyConfiguration(String configuration) : proxies = new List<_Proxy>() {
Mads Ager (google) 2012/10/08 16:59:39 Funky indentation.
Søren Gjesse 2012/10/09 14:05:22 Done.
+ if (configuration == null) {
+ throw new HttpException("Invalid proxy configuration $configuration");
+ }
+ List<String> list = configuration.split(";");
+ list.forEach((String proxy) {
+ proxy = proxy.trim();
+ if (!proxy.isEmpty()) {
+ if (proxy.startsWith(PROXY_PREFIX)) {
+ int colon = proxy.indexOf(":");
+ if (colon == -1 || colon == 0 || colon == proxy.length - 1) {
+ throw new HttpException(
+ "Invalid proxy configuration $configuration");
+ }
+ // Skip the "PROXY " prefix.
+ String host = proxy.substring(PROXY_PREFIX.length, colon).trim();
+ String portString = proxy.substring(colon + 1).trim();
+ int port;
+ try {
+ port = int.parse(portString);
+ } on FormatException catch (e) {
+ throw new HttpException(
+ "Invalid proxy configuration $configuration, "
+ "invalid port '$portString'");
+ }
+ proxies.add(new _Proxy(host, port));
+ } else if (proxy.trim() == DIRECT_PREFIX) {
+ proxies.add(new _Proxy.direct());
+ } else {
+ throw new HttpException("Invalid proxy configuration $configuration");
+ }
+ }
+ });
+ }
+ const _ProxyConfiguration.direct()
Mads Ager (google) 2012/10/08 16:59:39 Maybe add a space between the constructors.
Søren Gjesse 2012/10/09 14:05:22 Done.
+ : proxies = [const _Proxy.direct()];
+
+ final List<_Proxy> proxies;
+}
+
+class _Proxy {
+ const _Proxy(this.host, this.port) : direct = false;
+ const _Proxy.direct() : host = null, port = null, direct = true;
+
+ final String host;
+ final int port;
+ final bool direct;
+}
class _HttpClient implements HttpClient {
static const int DEFAULT_EVICTION_TIMEOUT = 60000;
@@ -1975,7 +2051,7 @@ class _HttpClient implements HttpClient {
}
HttpClientConnection openUrl(String method, Uri url) {
- _openUrl(method, url);
+ return _openUrl(method, url);
}
HttpClientConnection _openUrl(String method,
@@ -2002,6 +2078,8 @@ class _HttpClient implements HttpClient {
HttpClientConnection postUrl(Uri url) => _openUrl("POST", url);
+ set findProxy(String f(Uri uri)) => _findProxy = f;
+
void shutdown() {
_openSockets.forEach((String key, Queue<_SocketConnection> connections) {
while (!connections.isEmpty()) {
@@ -2034,19 +2112,11 @@ class _HttpClient implements HttpClient {
int port = url.port == 0 ? HttpClient.DEFAULT_HTTP_PORT : url.port;
void _connectionOpened(_SocketConnection socketConn,
- _HttpClientConnection connection) {
+ _HttpClientConnection connection,
+ bool usingProxy) {
+ connection._usingProxy = usingProxy;
connection._connectionEstablished(socketConn);
- String path;
- if (url.query != "") {
- if (url.fragment != "") {
- path = "${url.path}?${url.query}#${url.fragment}";
- } else {
- path = "${url.path}?${url.query}";
- }
- } else {
- path = url.path;
- }
- HttpClientRequest request = connection.open(method, path);
+ HttpClientRequest request = connection.open(method, url);
request.headers.host = host;
request.headers.port = port;
if (connection._onRequest != null) {
@@ -2062,12 +2132,32 @@ class _HttpClient implements HttpClient {
}
connection.onDetach = () => _activeSockets.remove(connection._socketConn);
+ // Check to see if a proxy server should be used for this connection.
+ _ProxyConfiguration proxyConfiguration = const _ProxyConfiguration.direct();
+ if (_findProxy != null) {
+ // TODO(sgjesse): Keep a map of these as normally only a few
+ // configuration strings will be used.
+ proxyConfiguration = new _ProxyConfiguration(_findProxy(url));
+ }
+
+ // Determine the actual host to connect to.
+ String connectHost;
+ int connectPort;
+ _Proxy proxy = proxyConfiguration.proxies[0];
+ if (proxy.direct) {
+ connectHost = host;
+ connectPort = port;
+ } else {
+ connectHost = proxy.host;
+ connectPort = proxy.port;
+ }
+
// If there are active connections for this key get the first one
// otherwise create a new one.
- String key = _connectionKey(host, port);
+ String key = _connectionKey(connectHost, connectPort);
Queue socketConnections = _openSockets[key];
if (socketConnections == null || socketConnections.isEmpty()) {
- Socket socket = new Socket(host, port);
+ Socket socket = new Socket(connectHost, connectPort);
// Until the connection is established handle connection errors
// here as the HttpClientConnection object is not yet associated
// with the socket.
@@ -2083,14 +2173,19 @@ class _HttpClient implements HttpClient {
// the connected socket.
socket.onError = null;
_SocketConnection socketConn =
- new _SocketConnection(host, port, socket);
+ new _SocketConnection(connectHost, connectPort, socket);
_activeSockets.add(socketConn);
- _connectionOpened(socketConn, connection);
+ _connectionOpened(socketConn,
+ connection,
+ !proxyConfiguration.proxies[0].direct);
Mads Ager (google) 2012/10/08 16:59:39 Just !proxy.direct?
Søren Gjesse 2012/10/09 14:05:22 Already fixed.
};
} else {
_SocketConnection socketConn = socketConnections.removeFirst();
_activeSockets.add(socketConn);
- new Timer(0, (ignored) => _connectionOpened(socketConn, connection));
+ new Timer(0, (ignored) =>
+ _connectionOpened(socketConn,
+ connection,
+ !proxyConfiguration.proxies[0].direct));
Mads Ager (google) 2012/10/08 16:59:39 !proxy.direct.
Søren Gjesse 2012/10/09 14:05:22 Already fixed.
// Get rid of eviction timer if there are no more active connections.
if (socketConnections.isEmpty()) _openSockets.remove(key);

Powered by Google App Engine
This is Rietveld 408576698