| Index: sdk/lib/io/http_impl.dart
|
| diff --git a/sdk/lib/io/http_impl.dart b/sdk/lib/io/http_impl.dart
|
| index 889a32e04638d807b9a9b46d9ae0e67390f5200f..bc681a3a4b7d9719fc2e707e915101c77e354ba9 100644
|
| --- a/sdk/lib/io/http_impl.dart
|
| +++ b/sdk/lib/io/http_impl.dart
|
| @@ -38,18 +38,12 @@ class _HttpIncoming extends Stream<List<int>> {
|
| _HttpIncoming(this.headers, this._transferLength, this._stream);
|
|
|
| StreamSubscription<List<int>> listen(void onData(List<int> event),
|
| - {Function onError,
|
| - void onDone(),
|
| - bool cancelOnError}) {
|
| + {Function onError, void onDone(), bool cancelOnError}) {
|
| hasSubscriber = true;
|
| - return _stream
|
| - .handleError((error) {
|
| - throw new HttpException(error.message, uri: uri);
|
| - })
|
| - .listen(onData,
|
| - onError: onError,
|
| - onDone: onDone,
|
| - cancelOnError: cancelOnError);
|
| + return _stream.handleError((error) {
|
| + throw new HttpException(error.message, uri: uri);
|
| + }).listen(onData,
|
| + onError: onError, onDone: onDone, cancelOnError: cancelOnError);
|
| }
|
|
|
| // Is completed once all data have been received.
|
| @@ -79,7 +73,6 @@ abstract class _HttpInboundMessage extends Stream<List<int>> {
|
| bool get persistentConnection => headers.persistentConnection;
|
| }
|
|
|
| -
|
| class _HttpRequest extends _HttpInboundMessage implements HttpRequest {
|
| final HttpResponse response;
|
|
|
| @@ -92,11 +85,12 @@ class _HttpRequest extends _HttpInboundMessage implements HttpRequest {
|
| Uri _requestedUri;
|
|
|
| _HttpRequest(this.response, _HttpIncoming _incoming, this._httpServer,
|
| - this._httpConnection) : super(_incoming) {
|
| + this._httpConnection)
|
| + : super(_incoming) {
|
| if (headers.protocolVersion == "1.1") {
|
| response.headers
|
| - ..chunkedTransferEncoding = true
|
| - ..persistentConnection = headers.persistentConnection;
|
| + ..chunkedTransferEncoding = true
|
| + ..persistentConnection = headers.persistentConnection;
|
| }
|
|
|
| if (_httpServer._sessionManagerInstance != null) {
|
| @@ -115,13 +109,9 @@ class _HttpRequest extends _HttpInboundMessage implements HttpRequest {
|
| }
|
|
|
| StreamSubscription<List<int>> listen(void onData(List<int> event),
|
| - {Function onError,
|
| - void onDone(),
|
| - bool cancelOnError}) {
|
| + {Function onError, void onDone(), bool cancelOnError}) {
|
| return _incoming.listen(onData,
|
| - onError: onError,
|
| - onDone: onDone,
|
| - cancelOnError: cancelOnError);
|
| + onError: onError, onDone: onDone, cancelOnError: cancelOnError);
|
| }
|
|
|
| Uri get uri => _incoming.uri;
|
| @@ -129,8 +119,9 @@ class _HttpRequest extends _HttpInboundMessage implements HttpRequest {
|
| Uri get requestedUri {
|
| if (_requestedUri == null) {
|
| var proto = headers['x-forwarded-proto'];
|
| - var scheme = proto != null ? proto.first :
|
| - _httpConnection._socket is SecureSocket ? "https" : "http";
|
| + var scheme = proto != null
|
| + ? proto.first
|
| + : _httpConnection._socket is SecureSocket ? "https" : "http";
|
| var hostList = headers['x-forwarded-host'];
|
| String host;
|
| if (hostList != null) {
|
| @@ -174,9 +165,8 @@ class _HttpRequest extends _HttpInboundMessage implements HttpRequest {
|
| }
|
| }
|
|
|
| -
|
| -class _HttpClientResponse
|
| - extends _HttpInboundMessage implements HttpClientResponse {
|
| +class _HttpClientResponse extends _HttpInboundMessage
|
| + implements HttpClientResponse {
|
| List<RedirectInfo> get redirects => _httpRequest._responseRedirects;
|
|
|
| // The HttpClient this response belongs to.
|
| @@ -185,8 +175,9 @@ class _HttpClientResponse
|
| // The HttpClientRequest of this response.
|
| final _HttpClientRequest _httpRequest;
|
|
|
| - _HttpClientResponse(_HttpIncoming _incoming, this._httpRequest,
|
| - this._httpClient) : super(_incoming) {
|
| + _HttpClientResponse(
|
| + _HttpIncoming _incoming, this._httpRequest, this._httpClient)
|
| + : super(_incoming) {
|
| // Set uri for potential exceptions.
|
| _incoming.uri = _httpRequest.uri;
|
| }
|
| @@ -215,18 +206,17 @@ class _HttpClientResponse
|
| bool get isRedirect {
|
| if (_httpRequest.method == "GET" || _httpRequest.method == "HEAD") {
|
| return statusCode == HttpStatus.MOVED_PERMANENTLY ||
|
| - statusCode == HttpStatus.FOUND ||
|
| - statusCode == HttpStatus.SEE_OTHER ||
|
| - statusCode == HttpStatus.TEMPORARY_REDIRECT;
|
| + statusCode == HttpStatus.FOUND ||
|
| + statusCode == HttpStatus.SEE_OTHER ||
|
| + statusCode == HttpStatus.TEMPORARY_REDIRECT;
|
| } else if (_httpRequest.method == "POST") {
|
| return statusCode == HttpStatus.SEE_OTHER;
|
| }
|
| return false;
|
| }
|
|
|
| - Future<HttpClientResponse> redirect([String method,
|
| - Uri url,
|
| - bool followLoops]) {
|
| + Future<HttpClientResponse> redirect(
|
| + [String method, Uri url, bool followLoops]) {
|
| if (method == null) {
|
| // Set method as defined by RFC 2616 section 10.3.4.
|
| if (statusCode == HttpStatus.SEE_OTHER && _httpRequest.method == "POST") {
|
| @@ -250,19 +240,18 @@ class _HttpClientResponse
|
| }
|
| }
|
| }
|
| - return _httpClient._openUrlFromRequest(method, url, _httpRequest)
|
| + return _httpClient
|
| + ._openUrlFromRequest(method, url, _httpRequest)
|
| .then((request) {
|
| - request._responseRedirects
|
| - ..addAll(this.redirects)
|
| - ..add(new _RedirectInfo(statusCode, method, url));
|
| - return request.close();
|
| - });
|
| + request._responseRedirects
|
| + ..addAll(this.redirects)
|
| + ..add(new _RedirectInfo(statusCode, method, url));
|
| + return request.close();
|
| + });
|
| }
|
|
|
| StreamSubscription<List<int>> listen(void onData(List<int> event),
|
| - {Function onError,
|
| - void onDone(),
|
| - bool cancelOnError}) {
|
| + {Function onError, void onDone(), bool cancelOnError}) {
|
| if (_incoming.upgraded) {
|
| // If upgraded, the connection is already 'removed' form the client.
|
| // Since listening to upgraded data is 'bogus', simply close and
|
| @@ -276,9 +265,7 @@ class _HttpClientResponse
|
| stream = stream.transform(GZIP.decoder);
|
| }
|
| return stream.listen(onData,
|
| - onError: onError,
|
| - onDone: onDone,
|
| - cancelOnError: cancelOnError);
|
| + onError: onError, onDone: onDone, cancelOnError: cancelOnError);
|
| }
|
|
|
| Future<Socket> detachSocket() {
|
| @@ -292,36 +279,39 @@ class _HttpClientResponse
|
| // Only try to authenticate if there is a challenge in the response.
|
| List<String> challenge = headers[HttpHeaders.PROXY_AUTHENTICATE];
|
| return statusCode == HttpStatus.PROXY_AUTHENTICATION_REQUIRED &&
|
| - challenge != null && challenge.length == 1;
|
| + challenge != null &&
|
| + challenge.length == 1;
|
| }
|
|
|
| bool get _shouldAuthenticate {
|
| // Only try to authenticate if there is a challenge in the response.
|
| List<String> challenge = headers[HttpHeaders.WWW_AUTHENTICATE];
|
| return statusCode == HttpStatus.UNAUTHORIZED &&
|
| - challenge != null && challenge.length == 1;
|
| + challenge != null &&
|
| + challenge.length == 1;
|
| }
|
|
|
| Future<HttpClientResponse> _authenticate(bool proxyAuth) {
|
| Future<HttpClientResponse> retry() {
|
| // Drain body and retry.
|
| return drain().then((_) {
|
| - return _httpClient._openUrlFromRequest(_httpRequest.method,
|
| - _httpRequest.uri,
|
| - _httpRequest)
|
| - .then((request) => request.close());
|
| - });
|
| + return _httpClient
|
| + ._openUrlFromRequest(
|
| + _httpRequest.method, _httpRequest.uri, _httpRequest)
|
| + .then((request) => request.close());
|
| + });
|
| }
|
|
|
| List<String> authChallenge() {
|
| - return proxyAuth ? headers[HttpHeaders.PROXY_AUTHENTICATE]
|
| - : headers[HttpHeaders.WWW_AUTHENTICATE];
|
| + return proxyAuth
|
| + ? headers[HttpHeaders.PROXY_AUTHENTICATE]
|
| + : headers[HttpHeaders.WWW_AUTHENTICATE];
|
| }
|
|
|
| _Credentials findCredentials(_AuthenticationScheme scheme) {
|
| - return proxyAuth ? _httpClient._findProxyCredentials(_httpRequest._proxy,
|
| - scheme)
|
| - : _httpClient._findCredentials(_httpRequest.uri, scheme);
|
| + return proxyAuth
|
| + ? _httpClient._findProxyCredentials(_httpRequest._proxy, scheme)
|
| + : _httpClient._findCredentials(_httpRequest.uri, scheme);
|
| }
|
|
|
| void removeCredentials(_Credentials cr) {
|
| @@ -338,17 +328,14 @@ class _HttpClientResponse
|
| return new Future.value(false);
|
| }
|
| var proxy = _httpRequest._proxy;
|
| - return _httpClient._authenticateProxy(proxy.host,
|
| - proxy.port,
|
| - scheme.toString(),
|
| - realm);
|
| + return _httpClient._authenticateProxy(
|
| + proxy.host, proxy.port, scheme.toString(), realm);
|
| } else {
|
| if (_httpClient._authenticate == null) {
|
| return new Future.value(false);
|
| }
|
| - return _httpClient._authenticate(_httpRequest.uri,
|
| - scheme.toString(),
|
| - realm);
|
| + return _httpClient._authenticate(
|
| + _httpRequest.uri, scheme.toString(), realm);
|
| }
|
| }
|
|
|
| @@ -374,12 +361,13 @@ class _HttpClientResponse
|
| // Digest authentication only supports the MD5 algorithm.
|
| if (cr.scheme == _AuthenticationScheme.DIGEST &&
|
| (header.parameters["algorithm"] == null ||
|
| - header.parameters["algorithm"].toLowerCase() == "md5")) {
|
| + header.parameters["algorithm"].toLowerCase() == "md5")) {
|
| if (cr.nonce == null || cr.nonce == header.parameters["nonce"]) {
|
| // If the nonce is not set then this is the first authenticate
|
| // response for these credentials. Set up authentication state.
|
| if (cr.nonce == null) {
|
| - cr..nonce = header.parameters["nonce"]
|
| + cr
|
| + ..nonce = header.parameters["nonce"]
|
| ..algorithm = "MD5"
|
| ..qop = header.parameters["qop"]
|
| ..nonceCount = 0;
|
| @@ -387,7 +375,7 @@ class _HttpClientResponse
|
| // Credentials where found, prepare for retrying the request.
|
| return retry();
|
| } else if (header.parameters["stale"] != null &&
|
| - header.parameters["stale"].toLowerCase() == "true") {
|
| + header.parameters["stale"].toLowerCase() == "true") {
|
| // If stale is true retry with new nonce.
|
| cr.nonce = header.parameters["nonce"];
|
| // Credentials where found, prepare for retrying the request.
|
| @@ -415,7 +403,6 @@ class _HttpClientResponse
|
| }
|
| }
|
|
|
| -
|
| abstract class _HttpOutboundMessage<T> extends _IOSinkImpl {
|
| // Used to mark when the body should be written. This is used for HEAD
|
| // requests and in error handling.
|
| @@ -428,16 +415,13 @@ abstract class _HttpOutboundMessage<T> extends _IOSinkImpl {
|
|
|
| final _HttpHeaders headers;
|
|
|
| - _HttpOutboundMessage(Uri uri,
|
| - String protocolVersion,
|
| - _HttpOutgoing outgoing,
|
| - {_HttpHeaders initialHeaders})
|
| + _HttpOutboundMessage(Uri uri, String protocolVersion, _HttpOutgoing outgoing,
|
| + {_HttpHeaders initialHeaders})
|
| : _uri = uri,
|
| - headers = new _HttpHeaders(
|
| - protocolVersion,
|
| - defaultPortForScheme: uri.scheme == 'https' ?
|
| - HttpClient.DEFAULT_HTTPS_PORT :
|
| - HttpClient.DEFAULT_HTTP_PORT,
|
| + headers = new _HttpHeaders(protocolVersion,
|
| + defaultPortForScheme: uri.scheme == 'https'
|
| + ? HttpClient.DEFAULT_HTTPS_PORT
|
| + : HttpClient.DEFAULT_HTTP_PORT,
|
| initialHeaders: initialHeaders),
|
| _outgoing = outgoing,
|
| super(outgoing, null) {
|
| @@ -461,7 +445,6 @@ abstract class _HttpOutboundMessage<T> extends _IOSinkImpl {
|
| _bufferOutput = bufferOutput;
|
| }
|
|
|
| -
|
| Encoding get encoding {
|
| if (_encodingSet && _outgoing.headersWritten) {
|
| return _encoding;
|
| @@ -493,7 +476,6 @@ abstract class _HttpOutboundMessage<T> extends _IOSinkImpl {
|
| bool get _isConnectionClosed => false;
|
| }
|
|
|
| -
|
| class _HttpResponse extends _HttpOutboundMessage<HttpResponse>
|
| implements HttpResponse {
|
| int _statusCode = 200;
|
| @@ -503,11 +485,8 @@ class _HttpResponse extends _HttpOutboundMessage<HttpResponse>
|
| Duration _deadline;
|
| Timer _deadlineTimer;
|
|
|
| - _HttpResponse(Uri uri,
|
| - String protocolVersion,
|
| - _HttpOutgoing outgoing,
|
| - HttpHeaders defaultHeaders,
|
| - String serverHeader)
|
| + _HttpResponse(Uri uri, String protocolVersion, _HttpOutgoing outgoing,
|
| + HttpHeaders defaultHeaders, String serverHeader)
|
| : super(uri, protocolVersion, outgoing, initialHeaders: defaultHeaders) {
|
| if (serverHeader != null) headers.set('server', serverHeader);
|
| }
|
| @@ -540,11 +519,11 @@ class _HttpResponse extends _HttpOutboundMessage<HttpResponse>
|
|
|
| Future<Socket> detachSocket({bool writeHeaders: true}) {
|
| if (_outgoing.headersWritten) throw new StateError("Headers already sent");
|
| - deadline = null; // Be sure to stop any deadline.
|
| + deadline = null; // Be sure to stop any deadline.
|
| var future = _httpRequest._httpConnection.detachSocket();
|
| if (writeHeaders) {
|
| - var headersFuture = _outgoing.writeHeaders(drainRequest: false,
|
| - setOutgoing: false);
|
| + var headersFuture =
|
| + _outgoing.writeHeaders(drainRequest: false, setOutgoing: false);
|
| assert(headersFuture == null);
|
| } else {
|
| // Imitate having written the headers.
|
| @@ -598,17 +577,17 @@ class _HttpResponse extends _HttpOutboundMessage<HttpResponse>
|
| for (int i = 0; i < cookies.length; i++) {
|
| if (cookies[i].name.toUpperCase() == _DART_SESSION_ID) {
|
| cookies[i]
|
| - ..value = session.id
|
| - ..httpOnly = true
|
| - ..path = "/";
|
| + ..value = session.id
|
| + ..httpOnly = true
|
| + ..path = "/";
|
| found = true;
|
| }
|
| }
|
| if (!found) {
|
| var cookie = new Cookie(_DART_SESSION_ID, session.id);
|
| cookies.add(cookie
|
| - ..httpOnly = true
|
| - ..path = "/");
|
| + ..httpOnly = true
|
| + ..path = "/");
|
| }
|
| }
|
| // Add all the cookies set to the headers.
|
| @@ -634,57 +613,92 @@ class _HttpResponse extends _HttpOutboundMessage<HttpResponse>
|
| }
|
|
|
| switch (statusCode) {
|
| - case HttpStatus.CONTINUE: return "Continue";
|
| - case HttpStatus.SWITCHING_PROTOCOLS: return "Switching Protocols";
|
| - case HttpStatus.OK: return "OK";
|
| - case HttpStatus.CREATED: return "Created";
|
| - case HttpStatus.ACCEPTED: return "Accepted";
|
| + case HttpStatus.CONTINUE:
|
| + return "Continue";
|
| + case HttpStatus.SWITCHING_PROTOCOLS:
|
| + return "Switching Protocols";
|
| + case HttpStatus.OK:
|
| + return "OK";
|
| + case HttpStatus.CREATED:
|
| + return "Created";
|
| + case HttpStatus.ACCEPTED:
|
| + return "Accepted";
|
| case HttpStatus.NON_AUTHORITATIVE_INFORMATION:
|
| return "Non-Authoritative Information";
|
| - case HttpStatus.NO_CONTENT: return "No Content";
|
| - case HttpStatus.RESET_CONTENT: return "Reset Content";
|
| - case HttpStatus.PARTIAL_CONTENT: return "Partial Content";
|
| - case HttpStatus.MULTIPLE_CHOICES: return "Multiple Choices";
|
| - case HttpStatus.MOVED_PERMANENTLY: return "Moved Permanently";
|
| - case HttpStatus.FOUND: return "Found";
|
| - case HttpStatus.SEE_OTHER: return "See Other";
|
| - case HttpStatus.NOT_MODIFIED: return "Not Modified";
|
| - case HttpStatus.USE_PROXY: return "Use Proxy";
|
| - case HttpStatus.TEMPORARY_REDIRECT: return "Temporary Redirect";
|
| - case HttpStatus.BAD_REQUEST: return "Bad Request";
|
| - case HttpStatus.UNAUTHORIZED: return "Unauthorized";
|
| - case HttpStatus.PAYMENT_REQUIRED: return "Payment Required";
|
| - case HttpStatus.FORBIDDEN: return "Forbidden";
|
| - case HttpStatus.NOT_FOUND: return "Not Found";
|
| - case HttpStatus.METHOD_NOT_ALLOWED: return "Method Not Allowed";
|
| - case HttpStatus.NOT_ACCEPTABLE: return "Not Acceptable";
|
| + case HttpStatus.NO_CONTENT:
|
| + return "No Content";
|
| + case HttpStatus.RESET_CONTENT:
|
| + return "Reset Content";
|
| + case HttpStatus.PARTIAL_CONTENT:
|
| + return "Partial Content";
|
| + case HttpStatus.MULTIPLE_CHOICES:
|
| + return "Multiple Choices";
|
| + case HttpStatus.MOVED_PERMANENTLY:
|
| + return "Moved Permanently";
|
| + case HttpStatus.FOUND:
|
| + return "Found";
|
| + case HttpStatus.SEE_OTHER:
|
| + return "See Other";
|
| + case HttpStatus.NOT_MODIFIED:
|
| + return "Not Modified";
|
| + case HttpStatus.USE_PROXY:
|
| + return "Use Proxy";
|
| + case HttpStatus.TEMPORARY_REDIRECT:
|
| + return "Temporary Redirect";
|
| + case HttpStatus.BAD_REQUEST:
|
| + return "Bad Request";
|
| + case HttpStatus.UNAUTHORIZED:
|
| + return "Unauthorized";
|
| + case HttpStatus.PAYMENT_REQUIRED:
|
| + return "Payment Required";
|
| + case HttpStatus.FORBIDDEN:
|
| + return "Forbidden";
|
| + case HttpStatus.NOT_FOUND:
|
| + return "Not Found";
|
| + case HttpStatus.METHOD_NOT_ALLOWED:
|
| + return "Method Not Allowed";
|
| + case HttpStatus.NOT_ACCEPTABLE:
|
| + return "Not Acceptable";
|
| case HttpStatus.PROXY_AUTHENTICATION_REQUIRED:
|
| return "Proxy Authentication Required";
|
| - case HttpStatus.REQUEST_TIMEOUT: return "Request Time-out";
|
| - case HttpStatus.CONFLICT: return "Conflict";
|
| - case HttpStatus.GONE: return "Gone";
|
| - case HttpStatus.LENGTH_REQUIRED: return "Length Required";
|
| - case HttpStatus.PRECONDITION_FAILED: return "Precondition Failed";
|
| + case HttpStatus.REQUEST_TIMEOUT:
|
| + return "Request Time-out";
|
| + case HttpStatus.CONFLICT:
|
| + return "Conflict";
|
| + case HttpStatus.GONE:
|
| + return "Gone";
|
| + case HttpStatus.LENGTH_REQUIRED:
|
| + return "Length Required";
|
| + case HttpStatus.PRECONDITION_FAILED:
|
| + return "Precondition Failed";
|
| case HttpStatus.REQUEST_ENTITY_TOO_LARGE:
|
| return "Request Entity Too Large";
|
| - case HttpStatus.REQUEST_URI_TOO_LONG: return "Request-URI Too Large";
|
| - case HttpStatus.UNSUPPORTED_MEDIA_TYPE: return "Unsupported Media Type";
|
| + case HttpStatus.REQUEST_URI_TOO_LONG:
|
| + return "Request-URI Too Large";
|
| + case HttpStatus.UNSUPPORTED_MEDIA_TYPE:
|
| + return "Unsupported Media Type";
|
| case HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE:
|
| return "Requested range not satisfiable";
|
| - case HttpStatus.EXPECTATION_FAILED: return "Expectation Failed";
|
| - case HttpStatus.INTERNAL_SERVER_ERROR: return "Internal Server Error";
|
| - case HttpStatus.NOT_IMPLEMENTED: return "Not Implemented";
|
| - case HttpStatus.BAD_GATEWAY: return "Bad Gateway";
|
| - case HttpStatus.SERVICE_UNAVAILABLE: return "Service Unavailable";
|
| - case HttpStatus.GATEWAY_TIMEOUT: return "Gateway Time-out";
|
| + case HttpStatus.EXPECTATION_FAILED:
|
| + return "Expectation Failed";
|
| + case HttpStatus.INTERNAL_SERVER_ERROR:
|
| + return "Internal Server Error";
|
| + case HttpStatus.NOT_IMPLEMENTED:
|
| + return "Not Implemented";
|
| + case HttpStatus.BAD_GATEWAY:
|
| + return "Bad Gateway";
|
| + case HttpStatus.SERVICE_UNAVAILABLE:
|
| + return "Service Unavailable";
|
| + case HttpStatus.GATEWAY_TIMEOUT:
|
| + return "Gateway Time-out";
|
| case HttpStatus.HTTP_VERSION_NOT_SUPPORTED:
|
| return "Http Version not supported";
|
| - default: return "Status $statusCode";
|
| + default:
|
| + return "Status $statusCode";
|
| }
|
| }
|
| }
|
|
|
| -
|
| class _HttpClientRequest extends _HttpOutboundMessage<HttpClientResponse>
|
| implements HttpClientRequest {
|
| final String method;
|
| @@ -695,8 +709,8 @@ class _HttpClientRequest extends _HttpOutboundMessage<HttpClientResponse>
|
| final _HttpClient _httpClient;
|
| final _HttpClientConnection _httpClientConnection;
|
|
|
| - final Completer<HttpClientResponse> _responseCompleter
|
| - = new Completer<HttpClientResponse>();
|
| + final Completer<HttpClientResponse> _responseCompleter =
|
| + new Completer<HttpClientResponse>();
|
|
|
| final _Proxy _proxy;
|
|
|
| @@ -710,7 +724,7 @@ class _HttpClientRequest extends _HttpOutboundMessage<HttpClientResponse>
|
| List<RedirectInfo> _responseRedirects = [];
|
|
|
| _HttpClientRequest(_HttpOutgoing outgoing, Uri uri, this.method, this._proxy,
|
| - this._httpClient, this._httpClientConnection)
|
| + this._httpClient, this._httpClientConnection)
|
| : uri = uri,
|
| super(uri, "1.1", outgoing) {
|
| // GET and HEAD have 'content-length: 0' by default.
|
| @@ -724,8 +738,7 @@ class _HttpClientRequest extends _HttpOutboundMessage<HttpClientResponse>
|
| Future<HttpClientResponse> get done {
|
| if (_response == null) {
|
| _response = Future.wait([_responseCompleter.future, super.done],
|
| - eagerError: true)
|
| - .then((list) => list[0]);
|
| + eagerError: true).then((list) => list[0]);
|
| }
|
| return _response;
|
| }
|
| @@ -755,15 +768,14 @@ class _HttpClientRequest extends _HttpOutboundMessage<HttpClientResponse>
|
| if (followRedirects && response.isRedirect) {
|
| if (response.redirects.length < maxRedirects) {
|
| // Redirect and drain response.
|
| - future = response.drain()
|
| + future = response
|
| + .drain()
|
| .then<HttpClientResponse>((_) => response.redirect());
|
| } else {
|
| // End with exception, too many redirects.
|
| - future = response.drain()
|
| - .then<HttpClientResponse>((_) {
|
| - return new Future<HttpClientResponse>.error(
|
| - new RedirectException("Redirect limit exceeded",
|
| - response.redirects));
|
| + future = response.drain().then<HttpClientResponse>((_) {
|
| + return new Future<HttpClientResponse>.error(new RedirectException(
|
| + "Redirect limit exceeded", response.redirects));
|
| });
|
| }
|
| } else if (response._shouldAuthenticateProxy) {
|
| @@ -773,8 +785,7 @@ class _HttpClientRequest extends _HttpOutboundMessage<HttpClientResponse>
|
| } else {
|
| future = new Future<HttpClientResponse>.value(response);
|
| }
|
| - future.then(
|
| - (v) => _responseCompleter.complete(v),
|
| + future.then((v) => _responseCompleter.complete(v),
|
| onError: _responseCompleter.completeError);
|
| }
|
|
|
| @@ -868,7 +879,6 @@ class _HttpGZipSink extends ByteConversionSink {
|
| void close() {}
|
| }
|
|
|
| -
|
| // The _HttpOutgoing handles all of the following:
|
| // - Buffering
|
| // - GZip compressionm
|
| @@ -878,12 +888,23 @@ class _HttpGZipSink extends ByteConversionSink {
|
| // Most notable is the GZip compression, that uses a double-buffering system,
|
| // one before gzip (_gzipBuffer) and one after (_buffer).
|
| class _HttpOutgoing implements StreamConsumer<List<int>> {
|
| - static const List<int> _footerAndChunk0Length =
|
| - const [_CharCode.CR, _CharCode.LF, 0x30, _CharCode.CR, _CharCode.LF,
|
| - _CharCode.CR, _CharCode.LF];
|
| -
|
| - static const List<int> _chunk0Length =
|
| - const [0x30, _CharCode.CR, _CharCode.LF, _CharCode.CR, _CharCode.LF];
|
| + static const List<int> _footerAndChunk0Length = const [
|
| + _CharCode.CR,
|
| + _CharCode.LF,
|
| + 0x30,
|
| + _CharCode.CR,
|
| + _CharCode.LF,
|
| + _CharCode.CR,
|
| + _CharCode.LF
|
| + ];
|
| +
|
| + static const List<int> _chunk0Length = const [
|
| + 0x30,
|
| + _CharCode.CR,
|
| + _CharCode.LF,
|
| + _CharCode.CR,
|
| + _CharCode.LF
|
| + ];
|
|
|
| final Completer<Socket> _doneCompleter = new Completer<Socket>();
|
| final Socket socket;
|
| @@ -965,7 +986,6 @@ class _HttpOutgoing implements StreamConsumer<List<int>> {
|
| return null;
|
| }
|
|
|
| -
|
| Future addStream(Stream<List<int>> stream) {
|
| if (_socketError) {
|
| stream.listen(null).cancel();
|
| @@ -984,9 +1004,7 @@ class _HttpOutgoing implements StreamConsumer<List<int>> {
|
| // alternative is to use stream.extand, but that won't give us a way of
|
| // pausing.
|
| var controller = new StreamController<List<int>>(
|
| - onPause: () => sub.pause(),
|
| - onResume: () => sub.resume(),
|
| - sync: true);
|
| + onPause: () => sub.pause(), onResume: () => sub.resume(), sync: true);
|
|
|
| void onData(List<int> data) {
|
| if (_socketError) return;
|
| @@ -1016,8 +1034,7 @@ class _HttpOutgoing implements StreamConsumer<List<int>> {
|
| _addChunk(data, controller.add);
|
| }
|
|
|
| - sub = stream.listen(
|
| - onData,
|
| + sub = stream.listen(onData,
|
| onError: controller.addError,
|
| onDone: controller.close,
|
| cancelOnError: true);
|
| @@ -1030,20 +1047,19 @@ class _HttpOutgoing implements StreamConsumer<List<int>> {
|
| sub.pause(future);
|
| }
|
| }
|
| - return socket.addStream(controller.stream)
|
| - .then((_) {
|
| - return outbound;
|
| - }, onError: (error, stackTrace) {
|
| - // Be sure to close it in case of an error.
|
| - if (_gzip) _gzipSink.close();
|
| - _socketError = true;
|
| - _doneCompleter.completeError(error, stackTrace);
|
| - if (_ignoreError(error)) {
|
| - return outbound;
|
| - } else {
|
| - throw error;
|
| - }
|
| - });
|
| + return socket.addStream(controller.stream).then((_) {
|
| + return outbound;
|
| + }, onError: (error, stackTrace) {
|
| + // Be sure to close it in case of an error.
|
| + if (_gzip) _gzipSink.close();
|
| + _socketError = true;
|
| + _doneCompleter.completeError(error, stackTrace);
|
| + if (_ignoreError(error)) {
|
| + return outbound;
|
| + } else {
|
| + throw error;
|
| + }
|
| + });
|
| }
|
|
|
| Future close() {
|
| @@ -1062,9 +1078,9 @@ class _HttpOutgoing implements StreamConsumer<List<int>> {
|
| outbound.headers.contentLength = 0;
|
| } else if (outbound.headers.contentLength > 0) {
|
| var error = new HttpException(
|
| - "No content even though contentLength was specified to be "
|
| - "greater than 0: ${outbound.headers.contentLength}.",
|
| - uri: outbound._uri);
|
| + "No content even though contentLength was specified to be "
|
| + "greater than 0: ${outbound.headers.contentLength}.",
|
| + uri: outbound._uri);
|
| _doneCompleter.completeError(error);
|
| return _closeFuture = new Future.error(error);
|
| }
|
| @@ -1089,8 +1105,8 @@ class _HttpOutgoing implements StreamConsumer<List<int>> {
|
| if (_gzip) {
|
| _gzipAdd = socket.add;
|
| if (_gzipBufferLength > 0) {
|
| - _gzipSink.add(new Uint8List.view(
|
| - _gzipBuffer.buffer, 0, _gzipBufferLength));
|
| + _gzipSink.add(
|
| + new Uint8List.view(_gzipBuffer.buffer, 0, _gzipBufferLength));
|
| }
|
| _gzipBuffer = null;
|
| _gzipSink.close();
|
| @@ -1107,18 +1123,17 @@ class _HttpOutgoing implements StreamConsumer<List<int>> {
|
| // And finally flush it. As we support keep-alive, never close it from
|
| // here. Once the socket is flushed, we'll be able to reuse it (signaled
|
| // by the 'done' future).
|
| - return socket.flush()
|
| - .then((_) {
|
| - _doneCompleter.complete(socket);
|
| + return socket.flush().then((_) {
|
| + _doneCompleter.complete(socket);
|
| + return outbound;
|
| + }, onError: (error, stackTrace) {
|
| + _doneCompleter.completeError(error, stackTrace);
|
| + if (_ignoreError(error)) {
|
| return outbound;
|
| - }, onError: (error, stackTrace) {
|
| - _doneCompleter.completeError(error, stackTrace);
|
| - if (_ignoreError(error)) {
|
| - return outbound;
|
| - } else {
|
| - throw error;
|
| - }
|
| - });
|
| + } else {
|
| + throw error;
|
| + }
|
| + });
|
| }
|
|
|
| var future = writeHeaders();
|
| @@ -1142,20 +1157,19 @@ class _HttpOutgoing implements StreamConsumer<List<int>> {
|
| _gzipBuffer = new Uint8List(_OUTGOING_BUFFER_SIZE);
|
| assert(_gzipSink == null);
|
| _gzipSink = new ZLibEncoder(gzip: true)
|
| - .startChunkedConversion(
|
| - new _HttpGZipSink((data) {
|
| - // We are closing down prematurely, due to an error. Discard.
|
| - if (_gzipAdd == null) return;
|
| - _addChunk(_chunkHeader(data.length), _gzipAdd);
|
| - _pendingChunkedFooter = 2;
|
| - _addChunk(data, _gzipAdd);
|
| - }));
|
| + .startChunkedConversion(new _HttpGZipSink((data) {
|
| + // We are closing down prematurely, due to an error. Discard.
|
| + if (_gzipAdd == null) return;
|
| + _addChunk(_chunkHeader(data.length), _gzipAdd);
|
| + _pendingChunkedFooter = 2;
|
| + _addChunk(data, _gzipAdd);
|
| + }));
|
| }
|
| }
|
|
|
| - bool _ignoreError(error)
|
| - => (error is SocketException || error is TlsException) &&
|
| - outbound is HttpResponse;
|
| + bool _ignoreError(error) =>
|
| + (error is SocketException || error is TlsException) &&
|
| + outbound is HttpResponse;
|
|
|
| void _addGZipChunk(List<int> chunk, void add(List<int> data)) {
|
| if (!outbound.bufferOutput) {
|
| @@ -1163,17 +1177,15 @@ class _HttpOutgoing implements StreamConsumer<List<int>> {
|
| return;
|
| }
|
| if (chunk.length > _gzipBuffer.length - _gzipBufferLength) {
|
| - add(new Uint8List.view(
|
| - _gzipBuffer.buffer, 0, _gzipBufferLength));
|
| + add(new Uint8List.view(_gzipBuffer.buffer, 0, _gzipBufferLength));
|
| _gzipBuffer = new Uint8List(_OUTGOING_BUFFER_SIZE);
|
| _gzipBufferLength = 0;
|
| }
|
| if (chunk.length > _OUTGOING_BUFFER_SIZE) {
|
| add(chunk);
|
| } else {
|
| - _gzipBuffer.setRange(_gzipBufferLength,
|
| - _gzipBufferLength + chunk.length,
|
| - chunk);
|
| + _gzipBuffer.setRange(
|
| + _gzipBufferLength, _gzipBufferLength + chunk.length, chunk);
|
| _gzipBufferLength += chunk.length;
|
| }
|
| }
|
| @@ -1204,8 +1216,24 @@ class _HttpOutgoing implements StreamConsumer<List<int>> {
|
| }
|
|
|
| List<int> _chunkHeader(int length) {
|
| - const hexDigits = const [0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
| - 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46];
|
| + const hexDigits = const [
|
| + 0x30,
|
| + 0x31,
|
| + 0x32,
|
| + 0x33,
|
| + 0x34,
|
| + 0x35,
|
| + 0x36,
|
| + 0x37,
|
| + 0x38,
|
| + 0x39,
|
| + 0x41,
|
| + 0x42,
|
| + 0x43,
|
| + 0x44,
|
| + 0x45,
|
| + 0x46
|
| + ];
|
| if (length == 0) {
|
| if (_pendingChunkedFooter == 2) return _footerAndChunk0Length;
|
| return _chunk0Length;
|
| @@ -1250,94 +1278,85 @@ class _HttpClientConnection {
|
| Future<Socket> _streamFuture;
|
|
|
| _HttpClientConnection(this.key, this._socket, this._httpClient,
|
| - [this._proxyTunnel = false, this._context])
|
| + [this._proxyTunnel = false, this._context])
|
| : _httpParser = new _HttpParser.responseParser() {
|
| _httpParser.listenToStream(_socket);
|
|
|
| // Set up handlers on the parser here, so we are sure to get 'onDone' from
|
| // the parser.
|
| - _subscription = _httpParser.listen(
|
| - (incoming) {
|
| - // Only handle one incoming response at the time. Keep the
|
| - // stream paused until the response have been processed.
|
| - _subscription.pause();
|
| - // We assume the response is not here, until we have send the request.
|
| - if (_nextResponseCompleter == null) {
|
| - throw new HttpException(
|
| - "Unexpected response (unsolicited response without request).",
|
| - uri: _currentUri);
|
| - }
|
| + _subscription = _httpParser.listen((incoming) {
|
| + // Only handle one incoming response at the time. Keep the
|
| + // stream paused until the response have been processed.
|
| + _subscription.pause();
|
| + // We assume the response is not here, until we have send the request.
|
| + if (_nextResponseCompleter == null) {
|
| + throw new HttpException(
|
| + "Unexpected response (unsolicited response without request).",
|
| + uri: _currentUri);
|
| + }
|
|
|
| - // Check for status code '100 Continue'. In that case just
|
| - // consume that response as the final response will follow
|
| - // it. There is currently no API for the client to wait for
|
| - // the '100 Continue' response.
|
| - if (incoming.statusCode == 100) {
|
| - incoming.drain().then((_) {
|
| - _subscription.resume();
|
| - }).catchError((error, [StackTrace stackTrace]) {
|
| - _nextResponseCompleter.completeError(
|
| - new HttpException(error.message, uri: _currentUri),
|
| - stackTrace);
|
| - _nextResponseCompleter = null;
|
| - });
|
| - } else {
|
| - _nextResponseCompleter.complete(incoming);
|
| - _nextResponseCompleter = null;
|
| - }
|
| - },
|
| - onError: (error, [StackTrace stackTrace]) {
|
| - if (_nextResponseCompleter != null) {
|
| - _nextResponseCompleter.completeError(
|
| - new HttpException(error.message, uri: _currentUri),
|
| - stackTrace);
|
| - _nextResponseCompleter = null;
|
| - }
|
| - },
|
| - onDone: () {
|
| - if (_nextResponseCompleter != null) {
|
| - _nextResponseCompleter.completeError(new HttpException(
|
| - "Connection closed before response was received",
|
| - uri: _currentUri));
|
| - _nextResponseCompleter = null;
|
| - }
|
| - close();
|
| + // Check for status code '100 Continue'. In that case just
|
| + // consume that response as the final response will follow
|
| + // it. There is currently no API for the client to wait for
|
| + // the '100 Continue' response.
|
| + if (incoming.statusCode == 100) {
|
| + incoming.drain().then((_) {
|
| + _subscription.resume();
|
| + }).catchError((error, [StackTrace stackTrace]) {
|
| + _nextResponseCompleter.completeError(
|
| + new HttpException(error.message, uri: _currentUri), stackTrace);
|
| + _nextResponseCompleter = null;
|
| });
|
| + } else {
|
| + _nextResponseCompleter.complete(incoming);
|
| + _nextResponseCompleter = null;
|
| + }
|
| + }, onError: (error, [StackTrace stackTrace]) {
|
| + if (_nextResponseCompleter != null) {
|
| + _nextResponseCompleter.completeError(
|
| + new HttpException(error.message, uri: _currentUri), stackTrace);
|
| + _nextResponseCompleter = null;
|
| + }
|
| + }, onDone: () {
|
| + if (_nextResponseCompleter != null) {
|
| + _nextResponseCompleter.completeError(new HttpException(
|
| + "Connection closed before response was received",
|
| + uri: _currentUri));
|
| + _nextResponseCompleter = null;
|
| + }
|
| + close();
|
| + });
|
| }
|
|
|
| _HttpClientRequest send(Uri uri, int port, String method, _Proxy proxy) {
|
| if (closed) {
|
| - throw new HttpException(
|
| - "Socket closed before request was sent", uri: uri);
|
| + throw new HttpException("Socket closed before request was sent",
|
| + uri: uri);
|
| }
|
| _currentUri = uri;
|
| // Start with pausing the parser.
|
| _subscription.pause();
|
| - _ProxyCredentials proxyCreds; // Credentials used to authorize proxy.
|
| - _SiteCredentials creds; // Credentials used to authorize this request.
|
| + _ProxyCredentials proxyCreds; // Credentials used to authorize proxy.
|
| + _SiteCredentials creds; // Credentials used to authorize this request.
|
| var outgoing = new _HttpOutgoing(_socket);
|
| // Create new request object, wrapping the outgoing connection.
|
| - var request = new _HttpClientRequest(outgoing,
|
| - uri,
|
| - method,
|
| - proxy,
|
| - _httpClient,
|
| - this);
|
| + var request =
|
| + new _HttpClientRequest(outgoing, uri, method, proxy, _httpClient, this);
|
| // For the Host header an IPv6 address must be enclosed in []'s.
|
| var host = uri.host;
|
| if (host.contains(':')) host = "[$host]";
|
| request.headers
|
| - ..host = host
|
| - ..port = port
|
| - .._add(HttpHeaders.ACCEPT_ENCODING, "gzip");
|
| + ..host = host
|
| + ..port = port
|
| + .._add(HttpHeaders.ACCEPT_ENCODING, "gzip");
|
| if (_httpClient.userAgent != null) {
|
| request.headers._add('user-agent', _httpClient.userAgent);
|
| }
|
| if (proxy.isAuthenticated) {
|
| // If the proxy configuration contains user information use that
|
| // for proxy basic authorization.
|
| - String auth = _CryptoUtils.bytesToBase64(
|
| - UTF8.encode("${proxy.username}:${proxy.password}"));
|
| + String auth = _CryptoUtils
|
| + .bytesToBase64(UTF8.encode("${proxy.username}:${proxy.password}"));
|
| request.headers.set(HttpHeaders.PROXY_AUTHORIZATION, "Basic $auth");
|
| } else if (!proxy.isDirect && _httpClient._proxyCredentials.length > 0) {
|
| proxyCreds = _httpClient._findProxyCredentials(proxy);
|
| @@ -1348,8 +1367,7 @@ class _HttpClientConnection {
|
| if (uri.userInfo != null && !uri.userInfo.isEmpty) {
|
| // If the URL contains user information use that for basic
|
| // authorization.
|
| - String auth =
|
| - _CryptoUtils.bytesToBase64(UTF8.encode(uri.userInfo));
|
| + String auth = _CryptoUtils.bytesToBase64(UTF8.encode(uri.userInfo));
|
| request.headers.set(HttpHeaders.AUTHORIZATION, "Basic $auth");
|
| } else {
|
| // Look for credentials.
|
| @@ -1361,80 +1379,74 @@ class _HttpClientConnection {
|
| // Start sending the request (lazy, delayed until the user provides
|
| // data).
|
| _httpParser.isHead = method == "HEAD";
|
| - _streamFuture = outgoing.done
|
| - .then<Socket>((Socket s) {
|
| - // Request sent, set up response completer.
|
| - _nextResponseCompleter = new Completer();
|
| -
|
| - // Listen for response.
|
| - _nextResponseCompleter.future
|
| - .then((incoming) {
|
| - _currentUri = null;
|
| - incoming.dataDone.then((closing) {
|
| - if (incoming.upgraded) {
|
| - _httpClient._connectionClosed(this);
|
| - startTimer();
|
| - return;
|
| - }
|
| - if (closed) return;
|
| - if (!closing &&
|
| - !_dispose &&
|
| - incoming.headers.persistentConnection &&
|
| - request.persistentConnection) {
|
| - // Return connection, now we are done.
|
| - _httpClient._returnConnection(this);
|
| - _subscription.resume();
|
| - } else {
|
| - destroy();
|
| - }
|
| - });
|
| - // For digest authentication if proxy check if the proxy
|
| - // requests the client to start using a new nonce for proxy
|
| - // authentication.
|
| - if (proxyCreds != null &&
|
| - proxyCreds.scheme == _AuthenticationScheme.DIGEST) {
|
| - var authInfo = incoming.headers["proxy-authentication-info"];
|
| - if (authInfo != null && authInfo.length == 1) {
|
| - var header =
|
| - _HeaderValue.parse(
|
| - authInfo[0], parameterSeparator: ',');
|
| - var nextnonce = header.parameters["nextnonce"];
|
| - if (nextnonce != null) proxyCreds.nonce = nextnonce;
|
| - }
|
| - }
|
| - // For digest authentication check if the server requests the
|
| - // client to start using a new nonce.
|
| - if (creds != null &&
|
| - creds.scheme == _AuthenticationScheme.DIGEST) {
|
| - var authInfo = incoming.headers["authentication-info"];
|
| - if (authInfo != null && authInfo.length == 1) {
|
| - var header =
|
| - _HeaderValue.parse(
|
| - authInfo[0], parameterSeparator: ',');
|
| - var nextnonce = header.parameters["nextnonce"];
|
| - if (nextnonce != null) creds.nonce = nextnonce;
|
| - }
|
| - }
|
| - request._onIncoming(incoming);
|
| - })
|
| - // If we see a state error, we failed to get the 'first'
|
| - // element.
|
| - .catchError((error) {
|
| - throw new HttpException(
|
| - "Connection closed before data was received", uri: uri);
|
| - }, test: (error) => error is StateError)
|
| - .catchError((error, stackTrace) {
|
| - // We are done with the socket.
|
| - destroy();
|
| - request._onError(error, stackTrace);
|
| - });
|
| -
|
| - // Resume the parser now we have a handler.
|
| - _subscription.resume();
|
| - return s;
|
| - }, onError: (e) {
|
| - destroy();
|
| + _streamFuture = outgoing.done.then<Socket>((Socket s) {
|
| + // Request sent, set up response completer.
|
| + _nextResponseCompleter = new Completer();
|
| +
|
| + // Listen for response.
|
| + _nextResponseCompleter.future.then((incoming) {
|
| + _currentUri = null;
|
| + incoming.dataDone.then((closing) {
|
| + if (incoming.upgraded) {
|
| + _httpClient._connectionClosed(this);
|
| + startTimer();
|
| + return;
|
| + }
|
| + if (closed) return;
|
| + if (!closing &&
|
| + !_dispose &&
|
| + incoming.headers.persistentConnection &&
|
| + request.persistentConnection) {
|
| + // Return connection, now we are done.
|
| + _httpClient._returnConnection(this);
|
| + _subscription.resume();
|
| + } else {
|
| + destroy();
|
| + }
|
| });
|
| + // For digest authentication if proxy check if the proxy
|
| + // requests the client to start using a new nonce for proxy
|
| + // authentication.
|
| + if (proxyCreds != null &&
|
| + proxyCreds.scheme == _AuthenticationScheme.DIGEST) {
|
| + var authInfo = incoming.headers["proxy-authentication-info"];
|
| + if (authInfo != null && authInfo.length == 1) {
|
| + var header =
|
| + _HeaderValue.parse(authInfo[0], parameterSeparator: ',');
|
| + var nextnonce = header.parameters["nextnonce"];
|
| + if (nextnonce != null) proxyCreds.nonce = nextnonce;
|
| + }
|
| + }
|
| + // For digest authentication check if the server requests the
|
| + // client to start using a new nonce.
|
| + if (creds != null && creds.scheme == _AuthenticationScheme.DIGEST) {
|
| + var authInfo = incoming.headers["authentication-info"];
|
| + if (authInfo != null && authInfo.length == 1) {
|
| + var header =
|
| + _HeaderValue.parse(authInfo[0], parameterSeparator: ',');
|
| + var nextnonce = header.parameters["nextnonce"];
|
| + if (nextnonce != null) creds.nonce = nextnonce;
|
| + }
|
| + }
|
| + request._onIncoming(incoming);
|
| + })
|
| + // If we see a state error, we failed to get the 'first'
|
| + // element.
|
| + .catchError((error) {
|
| + throw new HttpException("Connection closed before data was received",
|
| + uri: uri);
|
| + }, test: (error) => error is StateError).catchError((error, stackTrace) {
|
| + // We are done with the socket.
|
| + destroy();
|
| + request._onError(error, stackTrace);
|
| + });
|
| +
|
| + // Resume the parser now we have a handler.
|
| + _subscription.resume();
|
| + return s;
|
| + }, onError: (e) {
|
| + destroy();
|
| + });
|
| return request;
|
| }
|
|
|
| @@ -1453,43 +1465,37 @@ class _HttpClientConnection {
|
| closed = true;
|
| _httpClient._connectionClosed(this);
|
| _streamFuture
|
| - // TODO(ajohnsen): Add timeout.
|
| + // TODO(ajohnsen): Add timeout.
|
| .then((_) => _socket.destroy());
|
| }
|
|
|
| Future<_HttpClientConnection> createProxyTunnel(String host, int port,
|
| _Proxy proxy, bool callback(X509Certificate certificate)) {
|
| _HttpClientRequest request =
|
| - send(new Uri(host: host, port: port),
|
| - port,
|
| - "CONNECT",
|
| - proxy);
|
| + send(new Uri(host: host, port: port), port, "CONNECT", proxy);
|
| if (proxy.isAuthenticated) {
|
| // If the proxy configuration contains user information use that
|
| // for proxy basic authorization.
|
| - String auth = _CryptoUtils.bytesToBase64(
|
| - UTF8.encode("${proxy.username}:${proxy.password}"));
|
| + String auth = _CryptoUtils
|
| + .bytesToBase64(UTF8.encode("${proxy.username}:${proxy.password}"));
|
| request.headers.set(HttpHeaders.PROXY_AUTHORIZATION, "Basic $auth");
|
| }
|
| - return request.close()
|
| - .then((response) {
|
| - if (response.statusCode != HttpStatus.OK) {
|
| - throw "Proxy failed to establish tunnel "
|
| - "(${response.statusCode} ${response.reasonPhrase})";
|
| - }
|
| - var socket = (response as _HttpClientResponse)._httpRequest
|
| - ._httpClientConnection._socket;
|
| - return SecureSocket.secure(
|
| - socket,
|
| - host: host,
|
| - context: _context,
|
| - onBadCertificate: callback);
|
| - })
|
| - .then((secureSocket) {
|
| - String key = _HttpClientConnection.makeKey(true, host, port);
|
| - return new _HttpClientConnection(
|
| - key, secureSocket, request._httpClient, true);
|
| - });
|
| + return request.close().then((response) {
|
| + if (response.statusCode != HttpStatus.OK) {
|
| + throw "Proxy failed to establish tunnel "
|
| + "(${response.statusCode} ${response.reasonPhrase})";
|
| + }
|
| + var socket = (response as _HttpClientResponse)
|
| + ._httpRequest
|
| + ._httpClientConnection
|
| + ._socket;
|
| + return SecureSocket.secure(socket,
|
| + host: host, context: _context, onBadCertificate: callback);
|
| + }).then((secureSocket) {
|
| + String key = _HttpClientConnection.makeKey(true, host, port);
|
| + return new _HttpClientConnection(
|
| + key, secureSocket, request._httpClient, true);
|
| + });
|
| }
|
|
|
| HttpConnectionInfo get connectionInfo => _HttpConnectionInfo.create(_socket);
|
| @@ -1507,12 +1513,10 @@ class _HttpClientConnection {
|
|
|
| void startTimer() {
|
| assert(_idleTimer == null);
|
| - _idleTimer = new Timer(
|
| - _httpClient.idleTimeout,
|
| - () {
|
| - _idleTimer = null;
|
| - close();
|
| - });
|
| + _idleTimer = new Timer(_httpClient.idleTimeout, () {
|
| + _idleTimer = null;
|
| + close();
|
| + });
|
| }
|
| }
|
|
|
| @@ -1523,7 +1527,6 @@ class _ConnectionInfo {
|
| _ConnectionInfo(this.connection, this.proxy);
|
| }
|
|
|
| -
|
| class _ConnectionTarget {
|
| // Unique key for this connection target.
|
| final String key;
|
| @@ -1536,11 +1539,8 @@ class _ConnectionTarget {
|
| final Queue _pending = new ListQueue();
|
| int _connecting = 0;
|
|
|
| - _ConnectionTarget(this.key,
|
| - this.host,
|
| - this.port,
|
| - this.isSecure,
|
| - this.context);
|
| + _ConnectionTarget(
|
| + this.key, this.host, this.port, this.isSecure, this.context);
|
|
|
| bool get isEmpty => _idle.isEmpty && _active.isEmpty && _connecting == 0;
|
|
|
| @@ -1593,10 +1593,8 @@ class _ConnectionTarget {
|
| }
|
| }
|
|
|
| - Future<_ConnectionInfo> connect(String uriHost,
|
| - int uriPort,
|
| - _Proxy proxy,
|
| - _HttpClient client) {
|
| + Future<_ConnectionInfo> connect(
|
| + String uriHost, int uriPort, _Proxy proxy, _HttpClient client) {
|
| if (hasIdle) {
|
| var connection = takeIdle();
|
| client._connectionsChanged();
|
| @@ -1618,34 +1616,34 @@ class _ConnectionTarget {
|
| }
|
|
|
| Future socketFuture = (isSecure && proxy.isDirect
|
| - ? SecureSocket.connect(host,
|
| - port,
|
| - context: context,
|
| - onBadCertificate: callback)
|
| + ? SecureSocket.connect(host, port,
|
| + context: context, onBadCertificate: callback)
|
| : Socket.connect(host, port));
|
| _connecting++;
|
| return socketFuture.then((socket) {
|
| - _connecting--;
|
| - socket.setOption(SocketOption.TCP_NODELAY, true);
|
| - var connection =
|
| - new _HttpClientConnection(key, socket, client, false, context);
|
| - if (isSecure && !proxy.isDirect) {
|
| - connection._dispose = true;
|
| - return connection.createProxyTunnel(uriHost, uriPort, proxy, callback)
|
| - .then((tunnel) {
|
| - client._getConnectionTarget(uriHost, uriPort, true)
|
| - .addNewActive(tunnel);
|
| - return new _ConnectionInfo(tunnel, proxy);
|
| - });
|
| - } else {
|
| - addNewActive(connection);
|
| - return new _ConnectionInfo(connection, proxy);
|
| - }
|
| - }, onError: (error) {
|
| - _connecting--;
|
| - _checkPending();
|
| - throw error;
|
| - });
|
| + _connecting--;
|
| + socket.setOption(SocketOption.TCP_NODELAY, true);
|
| + var connection =
|
| + new _HttpClientConnection(key, socket, client, false, context);
|
| + if (isSecure && !proxy.isDirect) {
|
| + connection._dispose = true;
|
| + return connection
|
| + .createProxyTunnel(uriHost, uriPort, proxy, callback)
|
| + .then((tunnel) {
|
| + client
|
| + ._getConnectionTarget(uriHost, uriPort, true)
|
| + .addNewActive(tunnel);
|
| + return new _ConnectionInfo(tunnel, proxy);
|
| + });
|
| + } else {
|
| + addNewActive(connection);
|
| + return new _ConnectionInfo(connection, proxy);
|
| + }
|
| + }, onError: (error) {
|
| + _connecting--;
|
| + _checkPending();
|
| + throw error;
|
| + });
|
| }
|
| }
|
|
|
| @@ -1654,8 +1652,8 @@ typedef bool BadCertificateCallback(X509Certificate cr, String host, int port);
|
| class _HttpClient implements HttpClient {
|
| bool _closing = false;
|
| bool _closingForcefully = false;
|
| - final Map<String, _ConnectionTarget> _connectionTargets
|
| - = new HashMap<String, _ConnectionTarget>();
|
| + final Map<String, _ConnectionTarget> _connectionTargets =
|
| + new HashMap<String, _ConnectionTarget>();
|
| final List<_Credentials> _credentials = [];
|
| final List<_ProxyCredentials> _proxyCredentials = [];
|
| final SecurityContext _context;
|
| @@ -1686,17 +1684,13 @@ class _HttpClient implements HttpClient {
|
| }
|
| }
|
|
|
| - set badCertificateCallback(bool callback(X509Certificate cert,
|
| - String host,
|
| - int port)) {
|
| + set badCertificateCallback(
|
| + bool callback(X509Certificate cert, String host, int port)) {
|
| _badCertificateCallback = callback;
|
| }
|
|
|
| -
|
| - Future<HttpClientRequest> open(String method,
|
| - String host,
|
| - int port,
|
| - String path) {
|
| + Future<HttpClientRequest> open(
|
| + String method, String host, int port, String path) {
|
| const int hashMark = 0x23;
|
| const int questionMark = 0x3f;
|
| int fragmentStart = path.length;
|
| @@ -1715,41 +1709,41 @@ class _HttpClient implements HttpClient {
|
| query = path.substring(queryStart + 1, fragmentStart);
|
| path = path.substring(0, queryStart);
|
| }
|
| - Uri uri = new Uri(scheme: "http", host: host, port: port,
|
| - path: path, query: query);
|
| + Uri uri = new Uri(
|
| + scheme: "http", host: host, port: port, path: path, query: query);
|
| return _openUrl(method, uri);
|
| }
|
|
|
| - Future<HttpClientRequest> openUrl(String method, Uri url)
|
| - => _openUrl(method, url);
|
| + Future<HttpClientRequest> openUrl(String method, Uri url) =>
|
| + _openUrl(method, url);
|
|
|
| - Future<HttpClientRequest> get(String host, int port, String path)
|
| - => open("get", host, port, path);
|
| + Future<HttpClientRequest> get(String host, int port, String path) =>
|
| + open("get", host, port, path);
|
|
|
| Future<HttpClientRequest> getUrl(Uri url) => _openUrl("get", url);
|
|
|
| - Future<HttpClientRequest> post(String host, int port, String path)
|
| - => open("post", host, port, path);
|
| + Future<HttpClientRequest> post(String host, int port, String path) =>
|
| + open("post", host, port, path);
|
|
|
| Future<HttpClientRequest> postUrl(Uri url) => _openUrl("post", url);
|
|
|
| - Future<HttpClientRequest> put(String host, int port, String path)
|
| - => open("put", host, port, path);
|
| + Future<HttpClientRequest> put(String host, int port, String path) =>
|
| + open("put", host, port, path);
|
|
|
| Future<HttpClientRequest> putUrl(Uri url) => _openUrl("put", url);
|
|
|
| - Future<HttpClientRequest> delete(String host, int port, String path)
|
| - => open("delete", host, port, path);
|
| + Future<HttpClientRequest> delete(String host, int port, String path) =>
|
| + open("delete", host, port, path);
|
|
|
| Future<HttpClientRequest> deleteUrl(Uri url) => _openUrl("delete", url);
|
|
|
| - Future<HttpClientRequest> head(String host, int port, String path)
|
| - => open("head", host, port, path);
|
| + Future<HttpClientRequest> head(String host, int port, String path) =>
|
| + open("head", host, port, path);
|
|
|
| Future<HttpClientRequest> headUrl(Uri url) => _openUrl("head", url);
|
|
|
| - Future<HttpClientRequest> patch(String host, int port, String path)
|
| - => open("patch", host, port, path);
|
| + Future<HttpClientRequest> patch(String host, int port, String path) =>
|
| + open("patch", host, port, path);
|
|
|
| Future<HttpClientRequest> patchUrl(Uri url) => _openUrl("patch", url);
|
|
|
| @@ -1758,8 +1752,8 @@ class _HttpClient implements HttpClient {
|
| _closingForcefully = force;
|
| _closeConnections(_closingForcefully);
|
| assert(!_connectionTargets.values.any((s) => s.hasIdle));
|
| - assert(!force ||
|
| - !_connectionTargets.values.any((s) => s._active.isNotEmpty));
|
| + assert(
|
| + !force || !_connectionTargets.values.any((s) => s._active.isNotEmpty));
|
| }
|
|
|
| set authenticate(Future<bool> f(Uri url, String scheme, String realm)) {
|
| @@ -1775,10 +1769,8 @@ class _HttpClient implements HttpClient {
|
| _authenticateProxy = f;
|
| }
|
|
|
| - void addProxyCredentials(String host,
|
| - int port,
|
| - String realm,
|
| - HttpClientCredentials cr) {
|
| + void addProxyCredentials(
|
| + String host, int port, String realm, HttpClientCredentials cr) {
|
| _proxyCredentials.add(new _ProxyCredentials(host, port, realm, cr));
|
| }
|
|
|
| @@ -1803,9 +1795,9 @@ class _HttpClient implements HttpClient {
|
| bool isSecure = (uri.scheme == "https");
|
| int port = uri.port;
|
| if (port == 0) {
|
| - port = isSecure ?
|
| - HttpClient.DEFAULT_HTTPS_PORT :
|
| - HttpClient.DEFAULT_HTTP_PORT;
|
| + port = isSecure
|
| + ? HttpClient.DEFAULT_HTTPS_PORT
|
| + : HttpClient.DEFAULT_HTTP_PORT;
|
| }
|
| // Check to see if a proxy server should be used for this connection.
|
| var proxyConf = const _ProxyConfiguration.direct();
|
| @@ -1820,47 +1812,41 @@ class _HttpClient implements HttpClient {
|
| }
|
| return _getConnection(uri.host, port, proxyConf, isSecure)
|
| .then((_ConnectionInfo info) {
|
| + _HttpClientRequest send(_ConnectionInfo info) {
|
| + return info.connection
|
| + .send(uri, port, method.toUpperCase(), info.proxy);
|
| + }
|
|
|
| - _HttpClientRequest send(_ConnectionInfo info) {
|
| - return info.connection.send(uri,
|
| - port,
|
| - method.toUpperCase(),
|
| - info.proxy);
|
| - }
|
| -
|
| - // If the connection was closed before the request was sent, create
|
| - // and use another connection.
|
| - if (info.connection.closed) {
|
| - return _getConnection(uri.host, port, proxyConf, isSecure)
|
| - .then(send);
|
| - }
|
| - return send(info);
|
| - });
|
| + // If the connection was closed before the request was sent, create
|
| + // and use another connection.
|
| + if (info.connection.closed) {
|
| + return _getConnection(uri.host, port, proxyConf, isSecure).then(send);
|
| + }
|
| + return send(info);
|
| + });
|
| }
|
|
|
| - Future<_HttpClientRequest> _openUrlFromRequest(String method,
|
| - Uri uri,
|
| - _HttpClientRequest previous) {
|
| + Future<_HttpClientRequest> _openUrlFromRequest(
|
| + String method, Uri uri, _HttpClientRequest previous) {
|
| // If the new URI is relative (to either '/' or some sub-path),
|
| // construct a full URI from the previous one.
|
| Uri resolved = previous.uri.resolveUri(uri);
|
| return _openUrl(method, resolved).then((_HttpClientRequest request) {
|
| -
|
| - request
|
| - // Only follow redirects if initial request did.
|
| - ..followRedirects = previous.followRedirects
|
| - // Allow same number of redirects.
|
| - ..maxRedirects = previous.maxRedirects;
|
| - // Copy headers.
|
| - for (var header in previous.headers._headers.keys) {
|
| - if (request.headers[header] == null) {
|
| - request.headers.set(header, previous.headers[header]);
|
| - }
|
| - }
|
| - return request
|
| - ..headers.chunkedTransferEncoding = false
|
| - ..contentLength = 0;
|
| - });
|
| + request
|
| + // Only follow redirects if initial request did.
|
| + ..followRedirects = previous.followRedirects
|
| + // Allow same number of redirects.
|
| + ..maxRedirects = previous.maxRedirects;
|
| + // Copy headers.
|
| + for (var header in previous.headers._headers.keys) {
|
| + if (request.headers[header] == null) {
|
| + request.headers.set(header, previous.headers[header]);
|
| + }
|
| + }
|
| + return request
|
| + ..headers.chunkedTransferEncoding = false
|
| + ..contentLength = 0;
|
| + });
|
| }
|
|
|
| // Return a live connection to the idle pool.
|
| @@ -1902,22 +1888,21 @@ class _HttpClient implements HttpClient {
|
| }
|
|
|
| // Get a new _HttpClientConnection, from the matching _ConnectionTarget.
|
| - Future<_ConnectionInfo> _getConnection(String uriHost,
|
| - int uriPort,
|
| - _ProxyConfiguration proxyConf,
|
| - bool isSecure) {
|
| + Future<_ConnectionInfo> _getConnection(String uriHost, int uriPort,
|
| + _ProxyConfiguration proxyConf, bool isSecure) {
|
| Iterator<_Proxy> proxies = proxyConf.proxies.iterator;
|
|
|
| Future<_ConnectionInfo> connect(error) {
|
| if (!proxies.moveNext()) return new Future.error(error);
|
| _Proxy proxy = proxies.current;
|
| - String host = proxy.isDirect ? uriHost: proxy.host;
|
| - int port = proxy.isDirect ? uriPort: proxy.port;
|
| + String host = proxy.isDirect ? uriHost : proxy.host;
|
| + int port = proxy.isDirect ? uriPort : proxy.port;
|
| return _getConnectionTarget(host, port, isSecure)
|
| .connect(uriHost, uriPort, proxy, this)
|
| // On error, continue with next proxy.
|
| .catchError(connect);
|
| }
|
| +
|
| // Make sure we go through the event loop before taking a
|
| // connection from the pool. For long-running synchronous code the
|
| // server might have closed the connection, so this lowers the
|
| @@ -1930,21 +1915,21 @@ class _HttpClient implements HttpClient {
|
| // Look for credentials.
|
| _SiteCredentials cr =
|
| _credentials.fold(null, (_SiteCredentials prev, value) {
|
| - var siteCredentials = value as _SiteCredentials;
|
| - if (siteCredentials.applies(url, scheme)) {
|
| - if (prev == null) return value;
|
| - return siteCredentials.uri.path.length > prev.uri.path.length
|
| - ? siteCredentials
|
| - : prev;
|
| - } else {
|
| - return prev;
|
| - }
|
| - });
|
| + var siteCredentials = value as _SiteCredentials;
|
| + if (siteCredentials.applies(url, scheme)) {
|
| + if (prev == null) return value;
|
| + return siteCredentials.uri.path.length > prev.uri.path.length
|
| + ? siteCredentials
|
| + : prev;
|
| + } else {
|
| + return prev;
|
| + }
|
| + });
|
| return cr;
|
| }
|
|
|
| _ProxyCredentials _findProxyCredentials(_Proxy proxy,
|
| - [_AuthenticationScheme scheme]) {
|
| + [_AuthenticationScheme scheme]) {
|
| // Look for credentials.
|
| var it = _proxyCredentials.iterator;
|
| while (it.moveNext()) {
|
| @@ -1969,18 +1954,17 @@ class _HttpClient implements HttpClient {
|
| }
|
| }
|
|
|
| - static String _findProxyFromEnvironment(Uri url,
|
| - Map<String, String> environment) {
|
| + 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()) {
|
| var name = names.current;
|
| if ((name.startsWith("[") &&
|
| - name.endsWith("]") &&
|
| - "[${url.host}]" == name) ||
|
| - (name.isNotEmpty &&
|
| - url.host.endsWith(name))) {
|
| + name.endsWith("]") &&
|
| + "[${url.host}]" == name) ||
|
| + (name.isNotEmpty && url.host.endsWith(name))) {
|
| return "DIRECT";
|
| }
|
| }
|
| @@ -2039,9 +2023,8 @@ class _HttpClient implements HttpClient {
|
| static Map<String, String> _platformEnvironmentCache = Platform.environment;
|
| }
|
|
|
| -
|
| -class _HttpConnection
|
| - extends LinkedListEntry<_HttpConnection> with _ServiceObject {
|
| +class _HttpConnection extends LinkedListEntry<_HttpConnection>
|
| + with _ServiceObject {
|
| static const _ACTIVE = 0;
|
| static const _IDLE = 1;
|
| static const _CLOSING = 2;
|
| @@ -2061,61 +2044,62 @@ class _HttpConnection
|
|
|
| _HttpConnection(this._socket, this._httpServer)
|
| : _httpParser = new _HttpParser.requestParser() {
|
| - try { _socket._owner = this; } catch (_) { print(_); }
|
| + try {
|
| + _socket._owner = this;
|
| + } catch (_) {
|
| + print(_);
|
| + }
|
| _connections[_serviceId] = this;
|
| _httpParser.listenToStream(_socket as Object/*=Socket*/);
|
| - _subscription = _httpParser.listen(
|
| - (incoming) {
|
| - _httpServer._markActive(this);
|
| - // If the incoming was closed, close the connection.
|
| - incoming.dataDone.then((closing) {
|
| - if (closing) destroy();
|
| - });
|
| - // Only handle one incoming request at the time. Keep the
|
| - // stream paused until the request has been send.
|
| - _subscription.pause();
|
| - _state = _ACTIVE;
|
| - var outgoing = new _HttpOutgoing(_socket);
|
| - var response = new _HttpResponse(incoming.uri,
|
| - incoming.headers.protocolVersion,
|
| - outgoing,
|
| - _httpServer.defaultResponseHeaders,
|
| - _httpServer.serverHeader);
|
| - var request = new _HttpRequest(response, incoming, _httpServer, this);
|
| - _streamFuture = outgoing.done
|
| - .then((_) {
|
| - response.deadline = null;
|
| - if (_state == _DETACHED) return;
|
| - if (response.persistentConnection &&
|
| - request.persistentConnection &&
|
| - incoming.fullBodyRead &&
|
| - !_httpParser.upgrade &&
|
| - !_httpServer.closed) {
|
| - _state = _IDLE;
|
| - _idleMark = false;
|
| - _httpServer._markIdle(this);
|
| - // Resume the subscription for incoming requests as the
|
| - // request is now processed.
|
| - _subscription.resume();
|
| - } else {
|
| - // Close socket, keep-alive not used or body sent before
|
| - // received data was handled.
|
| - destroy();
|
| - }
|
| - }, onError: (_) {
|
| - destroy();
|
| - });
|
| - outgoing.ignoreBody = request.method == "HEAD";
|
| - response._httpRequest = request;
|
| - _httpServer._handleRequest(request);
|
| - },
|
| - onDone: () {
|
| - destroy();
|
| - },
|
| - onError: (error) {
|
| - // Ignore failed requests that was closed before headers was received.
|
| + _subscription = _httpParser.listen((incoming) {
|
| + _httpServer._markActive(this);
|
| + // If the incoming was closed, close the connection.
|
| + incoming.dataDone.then((closing) {
|
| + if (closing) destroy();
|
| + });
|
| + // Only handle one incoming request at the time. Keep the
|
| + // stream paused until the request has been send.
|
| + _subscription.pause();
|
| + _state = _ACTIVE;
|
| + var outgoing = new _HttpOutgoing(_socket);
|
| + var response = new _HttpResponse(
|
| + incoming.uri,
|
| + incoming.headers.protocolVersion,
|
| + outgoing,
|
| + _httpServer.defaultResponseHeaders,
|
| + _httpServer.serverHeader);
|
| + var request = new _HttpRequest(response, incoming, _httpServer, this);
|
| + _streamFuture = outgoing.done.then((_) {
|
| + response.deadline = null;
|
| + if (_state == _DETACHED) return;
|
| + if (response.persistentConnection &&
|
| + request.persistentConnection &&
|
| + incoming.fullBodyRead &&
|
| + !_httpParser.upgrade &&
|
| + !_httpServer.closed) {
|
| + _state = _IDLE;
|
| + _idleMark = false;
|
| + _httpServer._markIdle(this);
|
| + // Resume the subscription for incoming requests as the
|
| + // request is now processed.
|
| + _subscription.resume();
|
| + } else {
|
| + // Close socket, keep-alive not used or body sent before
|
| + // received data was handled.
|
| destroy();
|
| - });
|
| + }
|
| + }, onError: (_) {
|
| + destroy();
|
| + });
|
| + outgoing.ignoreBody = request.method == "HEAD";
|
| + response._httpRequest = request;
|
| + _httpServer._handleRequest(request);
|
| + }, onDone: () {
|
| + destroy();
|
| + }, onError: (error) {
|
| + // Ignore failed requests that was closed before headers was received.
|
| + destroy();
|
| + });
|
| }
|
|
|
| void markIdle() {
|
| @@ -2179,20 +2163,29 @@ class _HttpConnection
|
| };
|
| }
|
| switch (_state) {
|
| - case _ACTIVE: r['state'] = "Active"; break;
|
| - case _IDLE: r['state'] = "Idle"; break;
|
| - case _CLOSING: r['state'] = "Closing"; break;
|
| - case _DETACHED: r['state'] = "Detached"; break;
|
| - default: r['state'] = 'Unknown'; break;
|
| + case _ACTIVE:
|
| + r['state'] = "Active";
|
| + break;
|
| + case _IDLE:
|
| + r['state'] = "Idle";
|
| + break;
|
| + case _CLOSING:
|
| + r['state'] = "Closing";
|
| + break;
|
| + case _DETACHED:
|
| + r['state'] = "Detached";
|
| + break;
|
| + default:
|
| + r['state'] = 'Unknown';
|
| + break;
|
| }
|
| return r;
|
| }
|
| }
|
|
|
| -
|
| // HTTP server waiting for socket connections.
|
| -class _HttpServer
|
| - extends Stream<HttpRequest> with _ServiceObject
|
| +class _HttpServer extends Stream<HttpRequest>
|
| + with _ServiceObject
|
| implements HttpServer {
|
| // Use default Map so we keep order.
|
| static Map<int, _HttpServer> _servers = new Map<int, _HttpServer>();
|
| @@ -2206,47 +2199,48 @@ class _HttpServer
|
|
|
| static Future<HttpServer> bind(
|
| address, int port, int backlog, bool v6Only, bool shared) {
|
| - return ServerSocket.bind(
|
| - address, port, backlog: backlog, v6Only: v6Only, shared: shared)
|
| - .then((socket) {
|
| - return new _HttpServer._(socket, true);
|
| - });
|
| - }
|
| -
|
| - static Future<HttpServer> bindSecure(address,
|
| - int port,
|
| - SecurityContext context,
|
| - int backlog,
|
| - bool v6Only,
|
| - bool requestClientCertificate,
|
| - bool shared) {
|
| - return SecureServerSocket.bind(
|
| - address,
|
| - port,
|
| - context,
|
| - backlog: backlog,
|
| - v6Only: v6Only,
|
| - requestClientCertificate: requestClientCertificate,
|
| - shared: shared)
|
| - .then((socket) {
|
| - return new _HttpServer._(socket, true);
|
| - });
|
| + return ServerSocket
|
| + .bind(address, port, backlog: backlog, v6Only: v6Only, shared: shared)
|
| + .then((socket) {
|
| + return new _HttpServer._(socket, true);
|
| + });
|
| + }
|
| +
|
| + static Future<HttpServer> bindSecure(
|
| + address,
|
| + int port,
|
| + SecurityContext context,
|
| + int backlog,
|
| + bool v6Only,
|
| + bool requestClientCertificate,
|
| + bool shared) {
|
| + return SecureServerSocket
|
| + .bind(address, port, context,
|
| + backlog: backlog,
|
| + v6Only: v6Only,
|
| + requestClientCertificate: requestClientCertificate,
|
| + shared: shared)
|
| + .then((socket) {
|
| + return new _HttpServer._(socket, true);
|
| + });
|
| }
|
|
|
| _HttpServer._(this._serverSocket, this._closeServer) {
|
| - _controller = new StreamController<HttpRequest>(sync: true,
|
| - onCancel: close);
|
| + _controller =
|
| + new StreamController<HttpRequest>(sync: true, onCancel: close);
|
| idleTimeout = const Duration(seconds: 120);
|
| _servers[_serviceId] = this;
|
| _serverSocket._owner = this;
|
| }
|
|
|
| _HttpServer.listenOn(this._serverSocket) : _closeServer = false {
|
| - _controller = new StreamController<HttpRequest>(sync: true,
|
| - onCancel: close);
|
| + _controller =
|
| + new StreamController<HttpRequest>(sync: true, onCancel: close);
|
| idleTimeout = const Duration(seconds: 120);
|
| _servers[_serviceId] = this;
|
| - try { _serverSocket._owner = this; } catch (_) {}
|
| + try {
|
| + _serverSocket._owner = this;
|
| + } catch (_) {}
|
| }
|
|
|
| static HttpHeaders _initDefaultResponseHeaders() {
|
| @@ -2280,28 +2274,21 @@ class _HttpServer
|
| }
|
|
|
| StreamSubscription<HttpRequest> listen(void onData(HttpRequest event),
|
| - {Function onError,
|
| - void onDone(),
|
| - bool cancelOnError}) {
|
| - _serverSocket.listen(
|
| - (Socket socket) {
|
| - socket.setOption(SocketOption.TCP_NODELAY, true);
|
| - // Accept the client connection.
|
| - _HttpConnection connection = new _HttpConnection(socket, this);
|
| - _idleConnections.add(connection);
|
| - },
|
| - onError: (error, stackTrace) {
|
| - // Ignore HandshakeExceptions as they are bound to a single request,
|
| - // and are not fatal for the server.
|
| - if (error is! HandshakeException) {
|
| - _controller.addError(error, stackTrace);
|
| - }
|
| - },
|
| - onDone: _controller.close);
|
| + {Function onError, void onDone(), bool cancelOnError}) {
|
| + _serverSocket.listen((Socket socket) {
|
| + socket.setOption(SocketOption.TCP_NODELAY, true);
|
| + // Accept the client connection.
|
| + _HttpConnection connection = new _HttpConnection(socket, this);
|
| + _idleConnections.add(connection);
|
| + }, onError: (error, stackTrace) {
|
| + // Ignore HandshakeExceptions as they are bound to a single request,
|
| + // and are not fatal for the server.
|
| + if (error is! HandshakeException) {
|
| + _controller.addError(error, stackTrace);
|
| + }
|
| + }, onDone: _controller.close);
|
| return _controller.stream.listen(onData,
|
| - onError: onError,
|
| - onDone: onDone,
|
| - cancelOnError: cancelOnError);
|
| + onError: onError, onDone: onDone, cancelOnError: cancelOnError);
|
| }
|
|
|
| Future close({bool force: false}) {
|
| @@ -2439,18 +2426,17 @@ class _HttpServer
|
|
|
| // The server listen socket. Untyped as it can be both ServerSocket and
|
| // SecureServerSocket.
|
| - final dynamic/*ServerSocket|SecureServerSocket*/ _serverSocket;
|
| + final dynamic /*ServerSocket|SecureServerSocket*/ _serverSocket;
|
| final bool _closeServer;
|
|
|
| // Set of currently connected clients.
|
| - final LinkedList<_HttpConnection> _activeConnections
|
| - = new LinkedList<_HttpConnection>();
|
| - final LinkedList<_HttpConnection> _idleConnections
|
| - = new LinkedList<_HttpConnection>();
|
| + final LinkedList<_HttpConnection> _activeConnections =
|
| + new LinkedList<_HttpConnection>();
|
| + final LinkedList<_HttpConnection> _idleConnections =
|
| + new LinkedList<_HttpConnection>();
|
| StreamController<HttpRequest> _controller;
|
| }
|
|
|
| -
|
| class _ProxyConfiguration {
|
| static const String PROXY_PREFIX = "PROXY ";
|
| static const String DIRECT_PREFIX = "DIRECT";
|
| @@ -2510,13 +2496,11 @@ class _ProxyConfiguration {
|
| });
|
| }
|
|
|
| - const _ProxyConfiguration.direct()
|
| - : proxies = const [const _Proxy.direct()];
|
| + const _ProxyConfiguration.direct() : proxies = const [const _Proxy.direct()];
|
|
|
| final List<_Proxy> proxies;
|
| }
|
|
|
| -
|
| class _Proxy {
|
| final String host;
|
| final int port;
|
| @@ -2526,13 +2510,16 @@ class _Proxy {
|
|
|
| const _Proxy(this.host, this.port, this.username, this.password)
|
| : isDirect = false;
|
| - const _Proxy.direct() : host = null, port = null,
|
| - username = null, password = null, isDirect = true;
|
| + const _Proxy.direct()
|
| + : host = null,
|
| + port = null,
|
| + username = null,
|
| + password = null,
|
| + isDirect = true;
|
|
|
| bool get isAuthenticated => username != null;
|
| }
|
|
|
| -
|
| class _HttpConnectionInfo implements HttpConnectionInfo {
|
| InternetAddress remoteAddress;
|
| int remotePort;
|
| @@ -2543,15 +2530,14 @@ class _HttpConnectionInfo implements HttpConnectionInfo {
|
| try {
|
| _HttpConnectionInfo info = new _HttpConnectionInfo();
|
| return info
|
| - ..remoteAddress = socket.remoteAddress
|
| - ..remotePort = socket.remotePort
|
| - ..localPort = socket.port;
|
| - } catch (e) { }
|
| + ..remoteAddress = socket.remoteAddress
|
| + ..remotePort = socket.remotePort
|
| + ..localPort = socket.port;
|
| + } catch (e) {}
|
| return null;
|
| }
|
| }
|
|
|
| -
|
| class _DetachedSocket extends Stream<List<int>> implements Socket {
|
| final Stream<List<int>> _incoming;
|
| final Socket _socket;
|
| @@ -2559,13 +2545,9 @@ class _DetachedSocket extends Stream<List<int>> implements Socket {
|
| _DetachedSocket(this._socket, this._incoming);
|
|
|
| StreamSubscription<List<int>> listen(void onData(List<int> event),
|
| - {Function onError,
|
| - void onDone(),
|
| - bool cancelOnError}) {
|
| + {Function onError, void onDone(), bool cancelOnError}) {
|
| return _incoming.listen(onData,
|
| - onError: onError,
|
| - onDone: onDone,
|
| - cancelOnError: cancelOnError);
|
| + onError: onError, onDone: onDone, cancelOnError: cancelOnError);
|
| }
|
|
|
| Encoding get encoding => _socket.encoding;
|
| @@ -2574,17 +2556,25 @@ class _DetachedSocket extends Stream<List<int>> implements Socket {
|
| _socket.encoding = value;
|
| }
|
|
|
| - void write(Object obj) { _socket.write(obj); }
|
| + void write(Object obj) {
|
| + _socket.write(obj);
|
| + }
|
|
|
| - void writeln([Object obj = ""]) { _socket.writeln(obj); }
|
| + void writeln([Object obj = ""]) {
|
| + _socket.writeln(obj);
|
| + }
|
|
|
| - void writeCharCode(int charCode) { _socket.writeCharCode(charCode); }
|
| + void writeCharCode(int charCode) {
|
| + _socket.writeCharCode(charCode);
|
| + }
|
|
|
| void writeAll(Iterable objects, [String separator = ""]) {
|
| _socket.writeAll(objects, separator);
|
| }
|
|
|
| - void add(List<int> bytes) { _socket.add(bytes); }
|
| + void add(List<int> bytes) {
|
| + _socket.add(bytes);
|
| + }
|
|
|
| void addError(error, [StackTrace stackTrace]) =>
|
| _socket.addError(error, stackTrace);
|
| @@ -2593,7 +2583,9 @@ class _DetachedSocket extends Stream<List<int>> implements Socket {
|
| return _socket.addStream(stream);
|
| }
|
|
|
| - void destroy() { _socket.destroy(); }
|
| + void destroy() {
|
| + _socket.destroy();
|
| + }
|
|
|
| Future flush() => _socket.flush();
|
|
|
| @@ -2616,12 +2608,12 @@ class _DetachedSocket extends Stream<List<int>> implements Socket {
|
| Map _toJSON(bool ref) {
|
| return (_socket as dynamic)._toJSON(ref);
|
| }
|
| +
|
| void set _owner(owner) {
|
| (_socket as dynamic)._owner = owner;
|
| }
|
| }
|
|
|
| -
|
| class _AuthenticationScheme {
|
| final int _scheme;
|
|
|
| @@ -2644,7 +2636,6 @@ class _AuthenticationScheme {
|
| }
|
| }
|
|
|
| -
|
| abstract class _Credentials {
|
| _HttpClientCredentials credentials;
|
| String realm;
|
| @@ -2667,11 +2658,11 @@ abstract class _Credentials {
|
| // now always use UTF-8 encoding.
|
| _HttpClientDigestCredentials creds = credentials;
|
| var hasher = new _MD5()
|
| - ..add(UTF8.encode(creds.username))
|
| - ..add([_CharCode.COLON])
|
| - ..add(realm.codeUnits)
|
| - ..add([_CharCode.COLON])
|
| - ..add(UTF8.encode(creds.password));
|
| + ..add(UTF8.encode(creds.username))
|
| + ..add([_CharCode.COLON])
|
| + ..add(realm.codeUnits)
|
| + ..add([_CharCode.COLON])
|
| + ..add(UTF8.encode(creds.password));
|
| ha1 = _CryptoUtils.bytesToHex(hasher.close());
|
| }
|
| }
|
| @@ -2700,8 +2691,7 @@ class _SiteCredentials extends _Credentials {
|
| void authorize(HttpClientRequest request) {
|
| // Digest credentials cannot be used without a nonce from the
|
| // server.
|
| - if (credentials.scheme == _AuthenticationScheme.DIGEST &&
|
| - nonce == null) {
|
| + if (credentials.scheme == _AuthenticationScheme.DIGEST && nonce == null) {
|
| return;
|
| }
|
| credentials.authorize(this, request);
|
| @@ -2709,15 +2699,11 @@ class _SiteCredentials extends _Credentials {
|
| }
|
| }
|
|
|
| -
|
| class _ProxyCredentials extends _Credentials {
|
| String host;
|
| int port;
|
|
|
| - _ProxyCredentials(this.host,
|
| - this.port,
|
| - realm,
|
| - _HttpClientCredentials creds)
|
| + _ProxyCredentials(this.host, this.port, realm, _HttpClientCredentials creds)
|
| : super(creds, realm);
|
|
|
| bool applies(_Proxy proxy, _AuthenticationScheme scheme) {
|
| @@ -2728,24 +2714,20 @@ class _ProxyCredentials extends _Credentials {
|
| void authorize(HttpClientRequest request) {
|
| // Digest credentials cannot be used without a nonce from the
|
| // server.
|
| - if (credentials.scheme == _AuthenticationScheme.DIGEST &&
|
| - nonce == null) {
|
| + if (credentials.scheme == _AuthenticationScheme.DIGEST && nonce == null) {
|
| return;
|
| }
|
| credentials.authorizeProxy(this, request);
|
| }
|
| }
|
|
|
| -
|
| abstract class _HttpClientCredentials implements HttpClientCredentials {
|
| _AuthenticationScheme get scheme;
|
| void authorize(_Credentials credentials, HttpClientRequest request);
|
| void authorizeProxy(_ProxyCredentials credentials, HttpClientRequest request);
|
| }
|
|
|
| -
|
| -class _HttpClientBasicCredentials
|
| - extends _HttpClientCredentials
|
| +class _HttpClientBasicCredentials extends _HttpClientCredentials
|
| implements HttpClientBasicCredentials {
|
| String username;
|
| String password;
|
| @@ -2775,9 +2757,7 @@ class _HttpClientBasicCredentials
|
| }
|
| }
|
|
|
| -
|
| -class _HttpClientDigestCredentials
|
| - extends _HttpClientCredentials
|
| +class _HttpClientDigestCredentials extends _HttpClientCredentials
|
| implements HttpClientDigestCredentials {
|
| String username;
|
| String password;
|
| @@ -2789,18 +2769,16 @@ class _HttpClientDigestCredentials
|
| String authorization(_Credentials credentials, _HttpClientRequest request) {
|
| String requestUri = request._requestUri();
|
| _MD5 hasher = new _MD5()
|
| - ..add(request.method.codeUnits)
|
| - ..add([_CharCode.COLON])
|
| - ..add(requestUri.codeUnits);
|
| + ..add(request.method.codeUnits)
|
| + ..add([_CharCode.COLON])
|
| + ..add(requestUri.codeUnits);
|
| var ha2 = _CryptoUtils.bytesToHex(hasher.close());
|
|
|
| String qop;
|
| String cnonce;
|
| String nc;
|
| var x;
|
| - hasher = new _MD5()
|
| - ..add(credentials.ha1.codeUnits)
|
| - ..add([_CharCode.COLON]);
|
| + hasher = new _MD5()..add(credentials.ha1.codeUnits)..add([_CharCode.COLON]);
|
| if (credentials.qop == "auth") {
|
| qop = credentials.qop;
|
| cnonce = _CryptoUtils.bytesToHex(_IOCrypto.getRandomBytes(4));
|
| @@ -2808,53 +2786,52 @@ class _HttpClientDigestCredentials
|
| nc = credentials.nonceCount.toRadixString(16);
|
| nc = "00000000".substring(0, 8 - nc.length + 1) + nc;
|
| hasher
|
| - ..add(credentials.nonce.codeUnits)
|
| - ..add([_CharCode.COLON])
|
| - ..add(nc.codeUnits)
|
| - ..add([_CharCode.COLON])
|
| - ..add(cnonce.codeUnits)
|
| - ..add([_CharCode.COLON])
|
| - ..add(credentials.qop.codeUnits)
|
| - ..add([_CharCode.COLON])
|
| - ..add(ha2.codeUnits);
|
| + ..add(credentials.nonce.codeUnits)
|
| + ..add([_CharCode.COLON])
|
| + ..add(nc.codeUnits)
|
| + ..add([_CharCode.COLON])
|
| + ..add(cnonce.codeUnits)
|
| + ..add([_CharCode.COLON])
|
| + ..add(credentials.qop.codeUnits)
|
| + ..add([_CharCode.COLON])
|
| + ..add(ha2.codeUnits);
|
| } else {
|
| hasher
|
| - ..add(credentials.nonce.codeUnits)
|
| - ..add([_CharCode.COLON])
|
| - ..add(ha2.codeUnits);
|
| + ..add(credentials.nonce.codeUnits)
|
| + ..add([_CharCode.COLON])
|
| + ..add(ha2.codeUnits);
|
| }
|
| var response = _CryptoUtils.bytesToHex(hasher.close());
|
|
|
| StringBuffer buffer = new StringBuffer()
|
| - ..write('Digest ')
|
| - ..write('username="$username"')
|
| - ..write(', realm="${credentials.realm}"')
|
| - ..write(', nonce="${credentials.nonce}"')
|
| - ..write(', uri="$requestUri"')
|
| - ..write(', algorithm="${credentials.algorithm}"');
|
| + ..write('Digest ')
|
| + ..write('username="$username"')
|
| + ..write(', realm="${credentials.realm}"')
|
| + ..write(', nonce="${credentials.nonce}"')
|
| + ..write(', uri="$requestUri"')
|
| + ..write(', algorithm="${credentials.algorithm}"');
|
| if (qop == "auth") {
|
| buffer
|
| - ..write(', qop="$qop"')
|
| - ..write(', cnonce="$cnonce"')
|
| - ..write(', nc="$nc"');
|
| + ..write(', qop="$qop"')
|
| + ..write(', cnonce="$cnonce"')
|
| + ..write(', nc="$nc"');
|
| }
|
| buffer.write(', response="$response"');
|
| return buffer.toString();
|
| }
|
|
|
| void authorize(_Credentials credentials, HttpClientRequest request) {
|
| - request.headers.set(HttpHeaders.AUTHORIZATION,
|
| - authorization(credentials, request));
|
| + request.headers
|
| + .set(HttpHeaders.AUTHORIZATION, authorization(credentials, request));
|
| }
|
|
|
| - void authorizeProxy(_ProxyCredentials credentials,
|
| - HttpClientRequest request) {
|
| - request.headers.set(HttpHeaders.PROXY_AUTHORIZATION,
|
| - authorization(credentials, request));
|
| + void authorizeProxy(
|
| + _ProxyCredentials credentials, HttpClientRequest request) {
|
| + request.headers.set(
|
| + HttpHeaders.PROXY_AUTHORIZATION, authorization(credentials, request));
|
| }
|
| }
|
|
|
| -
|
| class _RedirectInfo implements RedirectInfo {
|
| final int statusCode;
|
| final String method;
|
|
|