OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 part of dart.io; | 5 part of dart.io; |
6 | 6 |
7 const int _HEADERS_BUFFER_SIZE = 8 * 1024; | 7 const int _HEADERS_BUFFER_SIZE = 8 * 1024; |
8 | 8 |
9 class _HttpIncoming extends Stream<List<int>> { | 9 class _HttpIncoming extends Stream<List<int>> { |
10 final int _transferLength; | 10 final int _transferLength; |
(...skipping 15 matching lines...) Expand all Loading... |
26 Uri uri; | 26 Uri uri; |
27 | 27 |
28 bool hasSubscriber = false; | 28 bool hasSubscriber = false; |
29 | 29 |
30 // The transfer length if the length of the message body as it | 30 // The transfer length if the length of the message body as it |
31 // appears in the message (RFC 2616 section 4.4). This can be -1 if | 31 // appears in the message (RFC 2616 section 4.4). This can be -1 if |
32 // the length of the massage body is not known due to transfer | 32 // the length of the massage body is not known due to transfer |
33 // codings. | 33 // codings. |
34 int get transferLength => _transferLength; | 34 int get transferLength => _transferLength; |
35 | 35 |
36 _HttpIncoming(_HttpHeaders this.headers, | 36 _HttpIncoming(this.headers, this._transferLength, this._stream); |
37 int this._transferLength, | |
38 Stream<List<int>> this._stream) { | |
39 } | |
40 | 37 |
41 StreamSubscription<List<int>> listen(void onData(List<int> event), | 38 StreamSubscription<List<int>> listen(void onData(List<int> event), |
42 {Function onError, | 39 {Function onError, |
43 void onDone(), | 40 void onDone(), |
44 bool cancelOnError}) { | 41 bool cancelOnError}) { |
45 hasSubscriber = true; | 42 hasSubscriber = true; |
46 return _stream | 43 return _stream |
47 .handleError((error) { | 44 .handleError((error) { |
48 throw new HttpException(error.message, uri: uri); | 45 throw new HttpException(error.message, uri: uri); |
49 }) | 46 }) |
(...skipping 10 matching lines...) Expand all Loading... |
60 fullBodyRead = true; | 57 fullBodyRead = true; |
61 hasSubscriber = true; | 58 hasSubscriber = true; |
62 _dataCompleter.complete(closing); | 59 _dataCompleter.complete(closing); |
63 } | 60 } |
64 } | 61 } |
65 | 62 |
66 abstract class _HttpInboundMessage extends Stream<List<int>> { | 63 abstract class _HttpInboundMessage extends Stream<List<int>> { |
67 final _HttpIncoming _incoming; | 64 final _HttpIncoming _incoming; |
68 List<Cookie> _cookies; | 65 List<Cookie> _cookies; |
69 | 66 |
70 _HttpInboundMessage(_HttpIncoming this._incoming); | 67 _HttpInboundMessage(this._incoming); |
71 | 68 |
72 List<Cookie> get cookies { | 69 List<Cookie> get cookies { |
73 if (_cookies != null) return _cookies; | 70 if (_cookies != null) return _cookies; |
74 return _cookies = headers._parseCookies(); | 71 return _cookies = headers._parseCookies(); |
75 } | 72 } |
76 | 73 |
77 _HttpHeaders get headers => _incoming.headers; | 74 _HttpHeaders get headers => _incoming.headers; |
78 String get protocolVersion => headers.protocolVersion; | 75 String get protocolVersion => headers.protocolVersion; |
79 int get contentLength => headers.contentLength; | 76 int get contentLength => headers.contentLength; |
80 bool get persistentConnection => headers.persistentConnection; | 77 bool get persistentConnection => headers.persistentConnection; |
81 } | 78 } |
82 | 79 |
83 | 80 |
84 class _HttpRequest extends _HttpInboundMessage implements HttpRequest { | 81 class _HttpRequest extends _HttpInboundMessage implements HttpRequest { |
85 final HttpResponse response; | 82 final HttpResponse response; |
86 | 83 |
87 final _HttpServer _httpServer; | 84 final _HttpServer _httpServer; |
88 | 85 |
89 final _HttpConnection _httpConnection; | 86 final _HttpConnection _httpConnection; |
90 | 87 |
91 _HttpSession _session; | 88 _HttpSession _session; |
92 | 89 |
93 _HttpRequest(_HttpResponse this.response, | 90 _HttpRequest(this.response, _HttpIncoming _incoming, this._httpServer, |
94 _HttpIncoming _incoming, | 91 this._httpConnection) : super(_incoming) { |
95 _HttpServer this._httpServer, | |
96 _HttpConnection this._httpConnection) | |
97 : super(_incoming) { | |
98 if (headers.protocolVersion == "1.1") { | 92 if (headers.protocolVersion == "1.1") { |
99 response.headers.chunkedTransferEncoding = true; | 93 response.headers |
100 response.headers.persistentConnection = headers.persistentConnection; | 94 ..chunkedTransferEncoding = true |
| 95 ..persistentConnection = headers.persistentConnection; |
101 } | 96 } |
102 | 97 |
103 if (_httpServer._sessionManagerInstance != null) { | 98 if (_httpServer._sessionManagerInstance != null) { |
104 // Map to session if exists. | 99 // Map to session if exists. |
105 var sessionIds = cookies | 100 var sessionIds = cookies |
106 .where((cookie) => cookie.name.toUpperCase() == _DART_SESSION_ID) | 101 .where((cookie) => cookie.name.toUpperCase() == _DART_SESSION_ID) |
107 .map((cookie) => cookie.value); | 102 .map((cookie) => cookie.value); |
108 for (var sessionId in sessionIds) { | 103 for (var sessionId in sessionIds) { |
109 _session = _httpServer._sessionManager.getSession(sessionId); | 104 _session = _httpServer._sessionManager.getSession(sessionId); |
110 if (_session != null) { | 105 if (_session != null) { |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
159 List<RedirectInfo> get redirects => _httpRequest._responseRedirects; | 154 List<RedirectInfo> get redirects => _httpRequest._responseRedirects; |
160 | 155 |
161 // The HttpClient this response belongs to. | 156 // The HttpClient this response belongs to. |
162 final _HttpClient _httpClient; | 157 final _HttpClient _httpClient; |
163 | 158 |
164 // The HttpClientRequest of this response. | 159 // The HttpClientRequest of this response. |
165 final _HttpClientRequest _httpRequest; | 160 final _HttpClientRequest _httpRequest; |
166 | 161 |
167 List<Cookie> _cookies; | 162 List<Cookie> _cookies; |
168 | 163 |
169 _HttpClientResponse(_HttpIncoming _incoming, | 164 _HttpClientResponse(_HttpIncoming _incoming, this._httpRequest, |
170 _HttpClientRequest this._httpRequest, | 165 this._httpClient) : super(_incoming) { |
171 _HttpClient this._httpClient) | |
172 : super(_incoming) { | |
173 // Set uri for potential exceptions. | 166 // Set uri for potential exceptions. |
174 _incoming.uri = _httpRequest.uri; | 167 _incoming.uri = _httpRequest.uri; |
175 } | 168 } |
176 | 169 |
177 int get statusCode => _incoming.statusCode; | 170 int get statusCode => _incoming.statusCode; |
178 String get reasonPhrase => _incoming.reasonPhrase; | 171 String get reasonPhrase => _incoming.reasonPhrase; |
179 | 172 |
180 X509Certificate get certificate { | 173 X509Certificate get certificate => |
181 var socket = _httpRequest._httpClientConnection._socket; | 174 _httpRequest._httpClientConnection._socket.peerCertificate; |
182 return socket.peerCertificate; | |
183 } | |
184 | 175 |
185 List<Cookie> get cookies { | 176 List<Cookie> get cookies { |
186 if (_cookies != null) return _cookies; | 177 if (_cookies != null) return _cookies; |
187 _cookies = new List<Cookie>(); | 178 _cookies = new List<Cookie>(); |
188 List<String> values = headers[HttpHeaders.SET_COOKIE]; | 179 List<String> values = headers[HttpHeaders.SET_COOKIE]; |
189 if (values != null) { | 180 if (values != null) { |
190 values.forEach((value) { | 181 values.forEach((value) { |
191 _cookies.add(new Cookie.fromSetCookieValue(value)); | 182 _cookies.add(new Cookie.fromSetCookieValue(value)); |
192 }); | 183 }); |
193 } | 184 } |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
227 if (followLoops != true) { | 218 if (followLoops != true) { |
228 for (var redirect in redirects) { | 219 for (var redirect in redirects) { |
229 if (redirect.location == url) { | 220 if (redirect.location == url) { |
230 return new Future.error( | 221 return new Future.error( |
231 new RedirectException("Redirect loop detected", redirects)); | 222 new RedirectException("Redirect loop detected", redirects)); |
232 } | 223 } |
233 } | 224 } |
234 } | 225 } |
235 return _httpClient._openUrlFromRequest(method, url, _httpRequest) | 226 return _httpClient._openUrlFromRequest(method, url, _httpRequest) |
236 .then((request) { | 227 .then((request) { |
237 request._responseRedirects.addAll(this.redirects); | 228 request._responseRedirects |
238 request._responseRedirects.add(new _RedirectInfo(statusCode, | 229 ..addAll(this.redirects) |
239 method, | 230 ..add(new _RedirectInfo(statusCode, method, url)); |
240 url)); | |
241 return request.close(); | 231 return request.close(); |
242 }); | 232 }); |
243 } | 233 } |
244 | 234 |
245 StreamSubscription<List<int>> listen(void onData(List<int> event), | 235 StreamSubscription<List<int>> listen(void onData(List<int> event), |
246 {Function onError, | 236 {Function onError, |
247 void onDone(), | 237 void onDone(), |
248 bool cancelOnError}) { | 238 bool cancelOnError}) { |
249 var stream = _incoming; | 239 var stream = _incoming; |
250 if (headers.value(HttpHeaders.CONTENT_ENCODING) == "gzip") { | 240 if (headers.value(HttpHeaders.CONTENT_ENCODING) == "gzip") { |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
282 // Drain body and retry. | 272 // Drain body and retry. |
283 return drain().then((_) { | 273 return drain().then((_) { |
284 return _httpClient._openUrlFromRequest(_httpRequest.method, | 274 return _httpClient._openUrlFromRequest(_httpRequest.method, |
285 _httpRequest.uri, | 275 _httpRequest.uri, |
286 _httpRequest) | 276 _httpRequest) |
287 .then((request) => request.close()); | 277 .then((request) => request.close()); |
288 }); | 278 }); |
289 } | 279 } |
290 | 280 |
291 List<String> authChallenge() { | 281 List<String> authChallenge() { |
292 if (proxyAuth) { | 282 return proxyAuth ? headers[HttpHeaders.PROXY_AUTHENTICATE] |
293 return headers[HttpHeaders.PROXY_AUTHENTICATE]; | 283 : headers[HttpHeaders.WWW_AUTHENTICATE]; |
294 } else { | |
295 return headers[HttpHeaders.WWW_AUTHENTICATE]; | |
296 } | |
297 } | 284 } |
298 | 285 |
299 _Credentials findCredentials(_AuthenticationScheme scheme) { | 286 _Credentials findCredentials(_AuthenticationScheme scheme) { |
300 if (proxyAuth) { | 287 return proxyAuth ? _httpClient._findProxyCredentials(_httpRequest._proxy,
scheme) |
301 return _httpClient._findProxyCredentials(_httpRequest._proxy, scheme); | 288 : _httpClient._findCredentials(_httpRequest.uri, scheme); |
302 } else { | |
303 return _httpClient._findCredentials(_httpRequest.uri, scheme); | |
304 } | |
305 } | 289 } |
306 | 290 |
307 void removeCredentials(_Credentials cr) { | 291 void removeCredentials(_Credentials cr) { |
308 if (proxyAuth) { | 292 if (proxyAuth) { |
309 _httpClient._removeProxyCredentials(cr); | 293 _httpClient._removeProxyCredentials(cr); |
310 } else { | 294 } else { |
311 _httpClient._removeCredentials(cr); | 295 _httpClient._removeCredentials(cr); |
312 } | 296 } |
313 } | 297 } |
314 | 298 |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
352 } | 336 } |
353 | 337 |
354 // Digest authentication only supports the MD5 algorithm. | 338 // Digest authentication only supports the MD5 algorithm. |
355 if (cr.scheme == _AuthenticationScheme.DIGEST && | 339 if (cr.scheme == _AuthenticationScheme.DIGEST && |
356 (header.parameters["algorithm"] == null || | 340 (header.parameters["algorithm"] == null || |
357 header.parameters["algorithm"].toLowerCase() == "md5")) { | 341 header.parameters["algorithm"].toLowerCase() == "md5")) { |
358 if (cr.nonce == null || cr.nonce == header.parameters["nonce"]) { | 342 if (cr.nonce == null || cr.nonce == header.parameters["nonce"]) { |
359 // If the nonce is not set then this is the first authenticate | 343 // If the nonce is not set then this is the first authenticate |
360 // response for these credentials. Set up authentication state. | 344 // response for these credentials. Set up authentication state. |
361 if (cr.nonce == null) { | 345 if (cr.nonce == null) { |
362 cr.nonce = header.parameters["nonce"]; | 346 cr..nonce = header.parameters["nonce"] |
363 cr.algorithm = "MD5"; | 347 ..algorithm = "MD5" |
364 cr.qop = header.parameters["qop"]; | 348 ..qop = header.parameters["qop"] |
365 cr.nonceCount = 0; | 349 ..nonceCount = 0; |
366 } | 350 } |
367 // Credentials where found, prepare for retrying the request. | 351 // Credentials where found, prepare for retrying the request. |
368 return retry(); | 352 return retry(); |
369 } else if (header.parameters["stale"] != null && | 353 } else if (header.parameters["stale"] != null && |
370 header.parameters["stale"].toLowerCase() == "true") { | 354 header.parameters["stale"].toLowerCase() == "true") { |
371 // If stale is true retry with new nonce. | 355 // If stale is true retry with new nonce. |
372 cr.nonce = header.parameters["nonce"]; | 356 cr.nonce = header.parameters["nonce"]; |
373 // Credentials where found, prepare for retrying the request. | 357 // Credentials where found, prepare for retrying the request. |
374 return retry(); | 358 return retry(); |
375 } | 359 } |
(...skipping 28 matching lines...) Expand all Loading... |
404 bool _asGZip = false; | 388 bool _asGZip = false; |
405 | 389 |
406 IOSink _headersSink; | 390 IOSink _headersSink; |
407 IOSink _dataSink; | 391 IOSink _dataSink; |
408 | 392 |
409 final _HttpOutgoing _outgoing; | 393 final _HttpOutgoing _outgoing; |
410 final Uri _uri; | 394 final Uri _uri; |
411 | 395 |
412 final _HttpHeaders headers; | 396 final _HttpHeaders headers; |
413 | 397 |
414 _HttpOutboundMessage(Uri this._uri, | 398 _HttpOutboundMessage(this._uri, |
415 String protocolVersion, | 399 String protocolVersion, |
416 _HttpOutgoing outgoing) | 400 _HttpOutgoing outgoing) |
417 : _outgoing = outgoing, | 401 : _outgoing = outgoing, |
418 _headersSink = new IOSink(outgoing, encoding: ASCII), | 402 _headersSink = new IOSink(outgoing, encoding: ASCII), |
419 headers = new _HttpHeaders(protocolVersion) { | 403 headers = new _HttpHeaders(protocolVersion) { |
420 _dataSink = new IOSink(new _HttpOutboundConsumer(this)); | 404 _dataSink = new IOSink(new _HttpOutboundConsumer(this)); |
421 } | 405 } |
422 | 406 |
423 int get contentLength => headers.contentLength; | 407 int get contentLength => headers.contentLength; |
424 void set contentLength(int contentLength) { | 408 void set contentLength(int contentLength) { |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
462 void writeCharCode(int charCode) { | 446 void writeCharCode(int charCode) { |
463 if (!_headersWritten) _dataSink.encoding = encoding; | 447 if (!_headersWritten) _dataSink.encoding = encoding; |
464 _dataSink.writeCharCode(charCode); | 448 _dataSink.writeCharCode(charCode); |
465 } | 449 } |
466 | 450 |
467 void add(List<int> data) { | 451 void add(List<int> data) { |
468 if (data.length == 0) return; | 452 if (data.length == 0) return; |
469 _dataSink.add(data); | 453 _dataSink.add(data); |
470 } | 454 } |
471 | 455 |
472 void addError(error, [StackTrace stackTrace]) { | 456 void addError(error, [StackTrace stackTrace]) => |
473 _dataSink.addError(error, stackTrace); | 457 _dataSink.addError(error, stackTrace); |
474 } | |
475 | 458 |
476 Future<T> addStream(Stream<List<int>> stream) { | 459 Future<T> addStream(Stream<List<int>> stream) => _dataSink.addStream(stream); |
477 return _dataSink.addStream(stream); | |
478 } | |
479 | 460 |
480 Future flush() { | 461 Future flush() => _dataSink.flush(); |
481 return _dataSink.flush(); | |
482 } | |
483 | 462 |
484 Future close() { | 463 Future close() => _dataSink.close(); |
485 return _dataSink.close(); | |
486 } | |
487 | 464 |
488 Future<T> get done => _dataSink.done; | 465 Future<T> get done => _dataSink.done; |
489 | 466 |
490 Future _writeHeaders({bool drainRequest: true}) { | 467 Future _writeHeaders({bool drainRequest: true}) { |
491 void write() { | 468 void write() { |
492 try { | 469 try { |
493 _writeHeader(); | 470 _writeHeader(); |
494 } catch (error) { | 471 } catch (error) { |
495 // Headers too large. | 472 // Headers too large. |
496 throw new HttpException( | 473 throw new HttpException( |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
572 | 549 |
573 | 550 |
574 class _HttpOutboundConsumer implements StreamConsumer { | 551 class _HttpOutboundConsumer implements StreamConsumer { |
575 final _HttpOutboundMessage _outbound; | 552 final _HttpOutboundMessage _outbound; |
576 StreamController _controller; | 553 StreamController _controller; |
577 StreamSubscription _subscription; | 554 StreamSubscription _subscription; |
578 Completer _closeCompleter = new Completer(); | 555 Completer _closeCompleter = new Completer(); |
579 Completer _completer; | 556 Completer _completer; |
580 bool _socketError = false; | 557 bool _socketError = false; |
581 | 558 |
582 _HttpOutboundConsumer(_HttpOutboundMessage this._outbound); | 559 _HttpOutboundConsumer(this._outbound); |
583 | 560 |
584 void _cancel() { | 561 void _cancel() { |
585 if (_subscription != null) { | 562 if (_subscription != null) { |
586 StreamSubscription subscription = _subscription; | 563 StreamSubscription subscription = _subscription; |
587 _subscription = null; | 564 _subscription = null; |
588 subscription.cancel(); | 565 subscription.cancel(); |
589 } | 566 } |
590 } | 567 } |
591 | 568 |
592 bool _ignoreError(error) | 569 bool _ignoreError(error) |
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
810 buffer[offset++] = _CharCode.LF; | 787 buffer[offset++] = _CharCode.LF; |
811 | 788 |
812 var session = _httpRequest._session; | 789 var session = _httpRequest._session; |
813 if (session != null && !session._destroyed) { | 790 if (session != null && !session._destroyed) { |
814 // Mark as not new. | 791 // Mark as not new. |
815 session._isNew = false; | 792 session._isNew = false; |
816 // Make sure we only send the current session id. | 793 // Make sure we only send the current session id. |
817 bool found = false; | 794 bool found = false; |
818 for (int i = 0; i < cookies.length; i++) { | 795 for (int i = 0; i < cookies.length; i++) { |
819 if (cookies[i].name.toUpperCase() == _DART_SESSION_ID) { | 796 if (cookies[i].name.toUpperCase() == _DART_SESSION_ID) { |
820 cookies[i].value = session.id; | 797 cookies[i] |
821 cookies[i].httpOnly = true; | 798 ..value = session.id |
822 cookies[i].path = "/"; | 799 ..httpOnly = true |
| 800 ..path = "/"; |
823 found = true; | 801 found = true; |
824 } | 802 } |
825 } | 803 } |
826 if (!found) { | 804 if (!found) { |
827 var cookie = new Cookie(_DART_SESSION_ID, session.id); | 805 var cookie = new Cookie(_DART_SESSION_ID, session.id); |
828 cookie.httpOnly = true; | 806 cookies.add(cookie |
829 cookie.path = "/"; | 807 ..httpOnly = true |
830 cookies.add(cookie); | 808 ..path = "/"); |
831 } | 809 } |
832 } | 810 } |
833 // Add all the cookies set to the headers. | 811 // Add all the cookies set to the headers. |
834 if (_cookies != null) { | 812 if (_cookies != null) { |
835 _cookies.forEach((cookie) { | 813 _cookies.forEach((cookie) { |
836 headers.add(HttpHeaders.SET_COOKIE, cookie); | 814 headers.add(HttpHeaders.SET_COOKIE, cookie); |
837 }); | 815 }); |
838 } | 816 } |
839 | 817 |
840 headers._finalize(); | 818 headers._finalize(); |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
920 | 898 |
921 Future<HttpClientResponse> _response; | 899 Future<HttpClientResponse> _response; |
922 | 900 |
923 // TODO(ajohnsen): Get default value from client? | 901 // TODO(ajohnsen): Get default value from client? |
924 bool _followRedirects = true; | 902 bool _followRedirects = true; |
925 | 903 |
926 int _maxRedirects = 5; | 904 int _maxRedirects = 5; |
927 | 905 |
928 List<RedirectInfo> _responseRedirects = []; | 906 List<RedirectInfo> _responseRedirects = []; |
929 | 907 |
930 _HttpClientRequest(_HttpOutgoing outgoing, | 908 _HttpClientRequest(_HttpOutgoing outgoing, Uri uri, this.method, this._proxy, |
931 Uri uri, | 909 this._httpClient, this._httpClientConnection) |
932 String this.method, | |
933 _Proxy this._proxy, | |
934 _HttpClient this._httpClient, | |
935 _HttpClientConnection this._httpClientConnection) | |
936 : super(uri, "1.1", outgoing), | 910 : super(uri, "1.1", outgoing), |
937 uri = uri { | 911 uri = uri { |
938 // GET and HEAD have 'content-length: 0' by default. | 912 // GET and HEAD have 'content-length: 0' by default. |
939 if (method == "GET" || method == "HEAD") { | 913 if (method == "GET" || method == "HEAD") { |
940 contentLength = 0; | 914 contentLength = 0; |
941 } else { | 915 } else { |
942 headers.chunkedTransferEncoding = true; | 916 headers.chunkedTransferEncoding = true; |
943 } | 917 } |
944 } | 918 } |
945 | 919 |
(...skipping 19 matching lines...) Expand all Loading... |
965 | 939 |
966 bool get followRedirects => _followRedirects; | 940 bool get followRedirects => _followRedirects; |
967 void set followRedirects(bool followRedirects) { | 941 void set followRedirects(bool followRedirects) { |
968 if (_headersWritten) throw new StateError("Request already sent"); | 942 if (_headersWritten) throw new StateError("Request already sent"); |
969 _followRedirects = followRedirects; | 943 _followRedirects = followRedirects; |
970 } | 944 } |
971 | 945 |
972 HttpConnectionInfo get connectionInfo => _httpClientConnection.connectionInfo; | 946 HttpConnectionInfo get connectionInfo => _httpClientConnection.connectionInfo; |
973 | 947 |
974 void _onIncoming(_HttpIncoming incoming) { | 948 void _onIncoming(_HttpIncoming incoming) { |
975 var response = new _HttpClientResponse(incoming, | 949 var response = new _HttpClientResponse(incoming, this, _httpClient); |
976 this, | |
977 _httpClient); | |
978 Future<HttpClientResponse> future; | 950 Future<HttpClientResponse> future; |
979 if (followRedirects && response.isRedirect) { | 951 if (followRedirects && response.isRedirect) { |
980 if (response.redirects.length < maxRedirects) { | 952 if (response.redirects.length < maxRedirects) { |
981 // Redirect and drain response. | 953 // Redirect and drain response. |
982 future = response.drain() | 954 future = response.drain().then((_) => response.redirect()); |
983 .then((_) => response.redirect()); | |
984 } else { | 955 } else { |
985 // End with exception, too many redirects. | 956 // End with exception, too many redirects. |
986 future = response.drain() | 957 future = response.drain() |
987 .then((_) => new Future.error( | 958 .then((_) => new Future.error( |
988 new RedirectException("Redirect limit exceeded", | 959 new RedirectException("Redirect limit exceeded", |
989 response.redirects))); | 960 response.redirects))); |
990 } | 961 } |
991 } else if (response._shouldAuthenticateProxy) { | 962 } else if (response._shouldAuthenticateProxy) { |
992 future = response._authenticate(true); | 963 future = response._authenticate(true); |
993 } else if (response._shouldAuthenticate) { | 964 } else if (response._shouldAuthenticate) { |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1059 // Write HTTP/1.1. | 1030 // Write HTTP/1.1. |
1060 write(_Const.HTTP11); | 1031 write(_Const.HTTP11); |
1061 buffer[offset++] = _CharCode.CR; | 1032 buffer[offset++] = _CharCode.CR; |
1062 buffer[offset++] = _CharCode.LF; | 1033 buffer[offset++] = _CharCode.LF; |
1063 | 1034 |
1064 // Add the cookies to the headers. | 1035 // Add the cookies to the headers. |
1065 if (!cookies.isEmpty) { | 1036 if (!cookies.isEmpty) { |
1066 StringBuffer sb = new StringBuffer(); | 1037 StringBuffer sb = new StringBuffer(); |
1067 for (int i = 0; i < cookies.length; i++) { | 1038 for (int i = 0; i < cookies.length; i++) { |
1068 if (i > 0) sb.write("; "); | 1039 if (i > 0) sb.write("; "); |
1069 sb.write(cookies[i].name); | 1040 sb..write(cookies[i].name)..write("=")..write(cookies[i].value); |
1070 sb.write("="); | |
1071 sb.write(cookies[i].value); | |
1072 } | 1041 } |
1073 headers.add(HttpHeaders.COOKIE, sb.toString()); | 1042 headers.add(HttpHeaders.COOKIE, sb.toString()); |
1074 } | 1043 } |
1075 | 1044 |
1076 headers._finalize(); | 1045 headers._finalize(); |
1077 | 1046 |
1078 // Write headers. | 1047 // Write headers. |
1079 offset = headers._write(buffer, offset); | 1048 offset = headers._write(buffer, offset); |
1080 buffer[offset++] = _CharCode.CR; | 1049 buffer[offset++] = _CharCode.CR; |
1081 buffer[offset++] = _CharCode.LF; | 1050 buffer[offset++] = _CharCode.LF; |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1156 | 1125 |
1157 // Transformer that validates the content length. | 1126 // Transformer that validates the content length. |
1158 class _ContentLengthValidator | 1127 class _ContentLengthValidator |
1159 implements StreamTransformer<List<int>, List<int>>, EventSink<List<int>> { | 1128 implements StreamTransformer<List<int>, List<int>>, EventSink<List<int>> { |
1160 final int expectedContentLength; | 1129 final int expectedContentLength; |
1161 final Uri uri; | 1130 final Uri uri; |
1162 int _bytesWritten = 0; | 1131 int _bytesWritten = 0; |
1163 | 1132 |
1164 EventSink<List<int>> _outSink; | 1133 EventSink<List<int>> _outSink; |
1165 | 1134 |
1166 _ContentLengthValidator(int this.expectedContentLength, Uri this.uri); | 1135 _ContentLengthValidator(this.expectedContentLength, this.uri); |
1167 | 1136 |
1168 Stream<List<int>> bind(Stream<List<int>> stream) { | 1137 Stream<List<int>> bind(Stream<List<int>> stream) { |
1169 return new Stream.eventTransformed( | 1138 return new Stream.eventTransformed( |
1170 stream, | 1139 stream, |
1171 (EventSink sink) { | 1140 (EventSink sink) { |
1172 if (_outSink != null) { | 1141 if (_outSink != null) { |
1173 throw new StateError("Validator transformer already used"); | 1142 throw new StateError("Validator transformer already used"); |
1174 } | 1143 } |
1175 _outSink = sink; | 1144 _outSink = sink; |
1176 return this; | 1145 return this; |
(...skipping 30 matching lines...) Expand all Loading... |
1207 _outSink.close(); | 1176 _outSink.close(); |
1208 } | 1177 } |
1209 } | 1178 } |
1210 | 1179 |
1211 | 1180 |
1212 // Extends StreamConsumer as this is an internal type, only used to pipe to. | 1181 // Extends StreamConsumer as this is an internal type, only used to pipe to. |
1213 class _HttpOutgoing implements StreamConsumer<List<int>> { | 1182 class _HttpOutgoing implements StreamConsumer<List<int>> { |
1214 final Completer _doneCompleter = new Completer(); | 1183 final Completer _doneCompleter = new Completer(); |
1215 final Socket socket; | 1184 final Socket socket; |
1216 | 1185 |
1217 _HttpOutgoing(Socket this.socket); | 1186 _HttpOutgoing(this.socket); |
1218 | 1187 |
1219 Future addStream(Stream<List<int>> stream) { | 1188 Future addStream(Stream<List<int>> stream) { |
1220 return socket.addStream(stream) | 1189 return socket.addStream(stream) |
1221 .catchError((error) { | 1190 .catchError((error) { |
1222 _doneCompleter.completeError(error); | 1191 _doneCompleter.completeError(error); |
1223 throw error; | 1192 throw error; |
1224 }); | 1193 }); |
1225 } | 1194 } |
1226 | 1195 |
1227 Future close() { | 1196 Future close() { |
(...skipping 13 matching lines...) Expand all Loading... |
1241 final _HttpClient _httpClient; | 1210 final _HttpClient _httpClient; |
1242 bool _dispose = false; | 1211 bool _dispose = false; |
1243 Timer _idleTimer; | 1212 Timer _idleTimer; |
1244 bool closed = false; | 1213 bool closed = false; |
1245 Uri _currentUri; | 1214 Uri _currentUri; |
1246 final Uint8List _headersBuffer = new Uint8List(_HEADERS_BUFFER_SIZE); | 1215 final Uint8List _headersBuffer = new Uint8List(_HEADERS_BUFFER_SIZE); |
1247 | 1216 |
1248 Completer<_HttpIncoming> _nextResponseCompleter; | 1217 Completer<_HttpIncoming> _nextResponseCompleter; |
1249 Future _streamFuture; | 1218 Future _streamFuture; |
1250 | 1219 |
1251 _HttpClientConnection(String this.key, | 1220 _HttpClientConnection(this.key, this._socket, this._httpClient, |
1252 Socket this._socket, | |
1253 _HttpClient this._httpClient, | |
1254 [this._proxyTunnel = false]) | 1221 [this._proxyTunnel = false]) |
1255 : _httpParser = new _HttpParser.responseParser() { | 1222 : _httpParser = new _HttpParser.responseParser() { |
1256 _socket.pipe(_httpParser); | 1223 _socket.pipe(_httpParser); |
1257 | 1224 |
1258 // Set up handlers on the parser here, so we are sure to get 'onDone' from | 1225 // Set up handlers on the parser here, so we are sure to get 'onDone' from |
1259 // the parser. | 1226 // the parser. |
1260 _subscription = _httpParser.listen( | 1227 _subscription = _httpParser.listen( |
1261 (incoming) { | 1228 (incoming) { |
1262 // Only handle one incoming response at the time. Keep the | 1229 // Only handle one incoming response at the time. Keep the |
1263 // stream paused until the response have been processed. | 1230 // stream paused until the response have been processed. |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1299 _ProxyCredentials proxyCreds; // Credentials used to authorize proxy. | 1266 _ProxyCredentials proxyCreds; // Credentials used to authorize proxy. |
1300 _SiteCredentials creds; // Credentials used to authorize this request. | 1267 _SiteCredentials creds; // Credentials used to authorize this request. |
1301 var outgoing = new _HttpOutgoing(_socket); | 1268 var outgoing = new _HttpOutgoing(_socket); |
1302 // Create new request object, wrapping the outgoing connection. | 1269 // Create new request object, wrapping the outgoing connection. |
1303 var request = new _HttpClientRequest(outgoing, | 1270 var request = new _HttpClientRequest(outgoing, |
1304 uri, | 1271 uri, |
1305 method, | 1272 method, |
1306 proxy, | 1273 proxy, |
1307 _httpClient, | 1274 _httpClient, |
1308 this); | 1275 this); |
1309 request.headers.host = uri.host; | 1276 request.headers |
1310 request.headers.port = port; | 1277 ..host = uri.host |
1311 request.headers._add(HttpHeaders.ACCEPT_ENCODING, "gzip"); | 1278 ..port = port |
| 1279 .._add(HttpHeaders.ACCEPT_ENCODING, "gzip"); |
1312 if (_httpClient.userAgent != null) { | 1280 if (_httpClient.userAgent != null) { |
1313 request.headers._add('user-agent', _httpClient.userAgent); | 1281 request.headers._add('user-agent', _httpClient.userAgent); |
1314 } | 1282 } |
1315 if (proxy.isAuthenticated) { | 1283 if (proxy.isAuthenticated) { |
1316 // If the proxy configuration contains user information use that | 1284 // If the proxy configuration contains user information use that |
1317 // for proxy basic authorization. | 1285 // for proxy basic authorization. |
1318 String auth = _CryptoUtils.bytesToBase64( | 1286 String auth = _CryptoUtils.bytesToBase64( |
1319 UTF8.encode("${proxy.username}:${proxy.password}")); | 1287 UTF8.encode("${proxy.username}:${proxy.password}")); |
1320 request.headers.set(HttpHeaders.PROXY_AUTHORIZATION, "Basic $auth"); | 1288 request.headers.set(HttpHeaders.PROXY_AUTHORIZATION, "Basic $auth"); |
1321 } else if (!proxy.isDirect && _httpClient._proxyCredentials.length > 0) { | 1289 } else if (!proxy.isDirect && _httpClient._proxyCredentials.length > 0) { |
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1477 _idleTimer = new Timer( | 1445 _idleTimer = new Timer( |
1478 _httpClient.idleTimeout, | 1446 _httpClient.idleTimeout, |
1479 () { | 1447 () { |
1480 _idleTimer = null; | 1448 _idleTimer = null; |
1481 close(); | 1449 close(); |
1482 }); | 1450 }); |
1483 } | 1451 } |
1484 } | 1452 } |
1485 | 1453 |
1486 class _ConnnectionInfo { | 1454 class _ConnnectionInfo { |
1487 _ConnnectionInfo(_HttpClientConnection this.connection, _Proxy this.proxy); | |
1488 final _HttpClientConnection connection; | 1455 final _HttpClientConnection connection; |
1489 final _Proxy proxy; | 1456 final _Proxy proxy; |
| 1457 |
| 1458 _ConnnectionInfo(this.connection, this.proxy); |
1490 } | 1459 } |
1491 | 1460 |
1492 | 1461 |
1493 class _HttpClient implements HttpClient { | 1462 class _HttpClient implements HttpClient { |
1494 // TODO(ajohnsen): Use eviction timeout. | 1463 // TODO(ajohnsen): Use eviction timeout. |
1495 bool _closing = false; | 1464 bool _closing = false; |
1496 | 1465 |
1497 final Map<String, Set<_HttpClientConnection>> _idleConnections | 1466 final Map<String, Set<_HttpClientConnection>> _idleConnections |
1498 = new HashMap<String, Set<_HttpClientConnection>>(); | 1467 = new HashMap<String, Set<_HttpClientConnection>>(); |
1499 final Set<_HttpClientConnection> _activeConnections | 1468 final Set<_HttpClientConnection> _activeConnections |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1583 } | 1552 } |
1584 assert(_activeConnections.isEmpty); | 1553 assert(_activeConnections.isEmpty); |
1585 _activeConnections.clear(); | 1554 _activeConnections.clear(); |
1586 } | 1555 } |
1587 } | 1556 } |
1588 | 1557 |
1589 set authenticate(Future<bool> f(Uri url, String scheme, String realm)) { | 1558 set authenticate(Future<bool> f(Uri url, String scheme, String realm)) { |
1590 _authenticate = f; | 1559 _authenticate = f; |
1591 } | 1560 } |
1592 | 1561 |
1593 void addCredentials(Uri url, String realm, HttpClientCredentials cr) { | 1562 void addCredentials(Uri url, String realm, HttpClientCredentials cr) => |
1594 _credentials.add(new _SiteCredentials(url, realm, cr)); | 1563 _credentials.add(new _SiteCredentials(url, realm, cr)); |
1595 } | |
1596 | 1564 |
1597 set authenticateProxy( | 1565 set authenticateProxy( |
1598 Future<bool> f(String host, int port, String scheme, String realm)) { | 1566 Future<bool> f(String host, int port, String scheme, String realm)) { |
1599 _authenticateProxy = f; | 1567 _authenticateProxy = f; |
1600 } | 1568 } |
1601 | 1569 |
1602 void addProxyCredentials(String host, | 1570 void addProxyCredentials(String host, |
1603 int port, | 1571 int port, |
1604 String realm, | 1572 String realm, |
1605 HttpClientCredentials cr) { | 1573 HttpClientCredentials cr) => |
1606 _proxyCredentials.add(new _ProxyCredentials(host, port, realm, cr)); | 1574 _proxyCredentials.add(new _ProxyCredentials(host, port, realm, cr)); |
1607 } | |
1608 | 1575 |
1609 set findProxy(String f(Uri uri)) => _findProxy = f; | 1576 set findProxy(String f(Uri uri)) => _findProxy = f; |
1610 | 1577 |
1611 Future<HttpClientRequest> _openUrl(String method, Uri uri) { | 1578 Future<HttpClientRequest> _openUrl(String method, Uri uri) { |
1612 if (method == null) { | 1579 if (method == null) { |
1613 throw new ArgumentError(method); | 1580 throw new ArgumentError(method); |
1614 } | 1581 } |
1615 if (method != "CONNECT") { | 1582 if (method != "CONNECT") { |
1616 if (uri.host.isEmpty) { | 1583 if (uri.host.isEmpty) { |
1617 throw new ArgumentError("No host specified in URI $uri"); | 1584 throw new ArgumentError("No host specified in URI $uri"); |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1657 }); | 1624 }); |
1658 } | 1625 } |
1659 | 1626 |
1660 Future<HttpClientRequest> _openUrlFromRequest(String method, | 1627 Future<HttpClientRequest> _openUrlFromRequest(String method, |
1661 Uri uri, | 1628 Uri uri, |
1662 _HttpClientRequest previous) { | 1629 _HttpClientRequest previous) { |
1663 // If the new URI is relative (to either '/' or some sub-path), | 1630 // If the new URI is relative (to either '/' or some sub-path), |
1664 // construct a full URI from the previous one. | 1631 // construct a full URI from the previous one. |
1665 Uri resolved = previous.uri.resolveUri(uri); | 1632 Uri resolved = previous.uri.resolveUri(uri); |
1666 return openUrl(method, resolved).then((_HttpClientRequest request) { | 1633 return openUrl(method, resolved).then((_HttpClientRequest request) { |
1667 // Only follow redirects if initial request did. | 1634 |
1668 request.followRedirects = previous.followRedirects; | 1635 request |
1669 // Allow same number of redirects. | 1636 // Only follow redirects if initial request did. |
1670 request.maxRedirects = previous.maxRedirects; | 1637 ..followRedirects = previous.followRedirects |
| 1638 // Allow same number of redirects. |
| 1639 ..maxRedirects = previous.maxRedirects; |
1671 // Copy headers. | 1640 // Copy headers. |
1672 for (var header in previous.headers._headers.keys) { | 1641 for (var header in previous.headers._headers.keys) { |
1673 if (request.headers[header] == null) { | 1642 if (request.headers[header] == null) { |
1674 request.headers.set(header, previous.headers[header]); | 1643 request.headers.set(header, previous.headers[header]); |
1675 } | 1644 } |
1676 } | 1645 } |
1677 request.headers.chunkedTransferEncoding = false; | 1646 return request |
1678 request.contentLength = 0; | 1647 ..headers.chunkedTransferEncoding = false |
1679 return request; | 1648 ..contentLength = 0; |
1680 }); | 1649 }); |
1681 } | 1650 } |
1682 | 1651 |
1683 // Return a live connection to the idle pool. | 1652 // Return a live connection to the idle pool. |
1684 void _returnConnection(_HttpClientConnection connection) { | 1653 void _returnConnection(_HttpClientConnection connection) { |
1685 _activeConnections.remove(connection); | 1654 _activeConnections.remove(connection); |
1686 if (_closing) { | 1655 if (_closing) { |
1687 connection.close(); | 1656 connection.close(); |
1688 return; | 1657 return; |
1689 } | 1658 } |
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1903 | 1872 |
1904 final Socket _socket; | 1873 final Socket _socket; |
1905 final _HttpServer _httpServer; | 1874 final _HttpServer _httpServer; |
1906 final _HttpParser _httpParser; | 1875 final _HttpParser _httpParser; |
1907 StreamSubscription _subscription; | 1876 StreamSubscription _subscription; |
1908 Timer _idleTimer; | 1877 Timer _idleTimer; |
1909 final Uint8List _headersBuffer = new Uint8List(_HEADERS_BUFFER_SIZE); | 1878 final Uint8List _headersBuffer = new Uint8List(_HEADERS_BUFFER_SIZE); |
1910 | 1879 |
1911 Future _streamFuture; | 1880 Future _streamFuture; |
1912 | 1881 |
1913 _HttpConnection(Socket this._socket, _HttpServer this._httpServer) | 1882 _HttpConnection(this._socket, this._httpServer) |
1914 : _httpParser = new _HttpParser.requestParser() { | 1883 : _httpParser = new _HttpParser.requestParser() { |
1915 _startTimeout(); | 1884 _startTimeout(); |
1916 _socket.pipe(_httpParser); | 1885 _socket.pipe(_httpParser); |
1917 _subscription = _httpParser.listen( | 1886 _subscription = _httpParser.listen( |
1918 (incoming) { | 1887 (incoming) { |
1919 _stopTimeout(); | 1888 _stopTimeout(); |
1920 // If the incoming was closed, close the connection. | 1889 // If the incoming was closed, close the connection. |
1921 incoming.dataDone.then((closing) { | 1890 incoming.dataDone.then((closing) { |
1922 if (closing) destroy(); | 1891 if (closing) destroy(); |
1923 }); | 1892 }); |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2036 .then((socket) { | 2005 .then((socket) { |
2037 return new _HttpServer._(socket, true); | 2006 return new _HttpServer._(socket, true); |
2038 }); | 2007 }); |
2039 } | 2008 } |
2040 | 2009 |
2041 _HttpServer._(this._serverSocket, this._closeServer) { | 2010 _HttpServer._(this._serverSocket, this._closeServer) { |
2042 _controller = new StreamController<HttpRequest>(sync: true, | 2011 _controller = new StreamController<HttpRequest>(sync: true, |
2043 onCancel: close); | 2012 onCancel: close); |
2044 } | 2013 } |
2045 | 2014 |
2046 _HttpServer.listenOn(ServerSocket this._serverSocket) | 2015 _HttpServer.listenOn(this._serverSocket) : _closeServer = false { |
2047 : _closeServer = false { | |
2048 _controller = new StreamController<HttpRequest>(sync: true, | 2016 _controller = new StreamController<HttpRequest>(sync: true, |
2049 onCancel: close); | 2017 onCancel: close); |
2050 } | 2018 } |
2051 | 2019 |
2052 StreamSubscription<HttpRequest> listen(void onData(HttpRequest event), | 2020 StreamSubscription<HttpRequest> listen(void onData(HttpRequest event), |
2053 {Function onError, | 2021 {Function onError, |
2054 void onDone(), | 2022 void onDone(), |
2055 bool cancelOnError}) { | 2023 bool cancelOnError}) { |
2056 _serverSocket.listen( | 2024 _serverSocket.listen( |
2057 (Socket socket) { | 2025 (Socket socket) { |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2112 | 2080 |
2113 InternetAddress get address { | 2081 InternetAddress get address { |
2114 if (closed) throw new HttpException("HttpServer is not bound to a socket"); | 2082 if (closed) throw new HttpException("HttpServer is not bound to a socket"); |
2115 return _serverSocket.address; | 2083 return _serverSocket.address; |
2116 } | 2084 } |
2117 | 2085 |
2118 set sessionTimeout(int timeout) { | 2086 set sessionTimeout(int timeout) { |
2119 _sessionManager.sessionTimeout = timeout; | 2087 _sessionManager.sessionTimeout = timeout; |
2120 } | 2088 } |
2121 | 2089 |
2122 void _handleRequest(HttpRequest request) { | 2090 void _handleRequest(HttpRequest request) => _controller.add(request); |
2123 _controller.add(request); | |
2124 } | |
2125 | 2091 |
2126 void _handleError(error) { | 2092 void _handleError(error) { |
2127 if (!closed) _controller.addError(error); | 2093 if (!closed) _controller.addError(error); |
2128 } | 2094 } |
2129 | 2095 |
2130 void _connectionClosed(_HttpConnection connection) { | 2096 void _connectionClosed(_HttpConnection connection) { |
2131 _connections.remove(connection); | 2097 _connections.remove(connection); |
2132 _maybeCloseSessionManager(); | 2098 _maybeCloseSessionManager(); |
2133 } | 2099 } |
2134 | 2100 |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2234 } | 2200 } |
2235 | 2201 |
2236 const _ProxyConfiguration.direct() | 2202 const _ProxyConfiguration.direct() |
2237 : proxies = const [const _Proxy.direct()]; | 2203 : proxies = const [const _Proxy.direct()]; |
2238 | 2204 |
2239 final List<_Proxy> proxies; | 2205 final List<_Proxy> proxies; |
2240 } | 2206 } |
2241 | 2207 |
2242 | 2208 |
2243 class _Proxy { | 2209 class _Proxy { |
2244 const _Proxy( | |
2245 this.host, this.port, this.username, this.password) : isDirect = false; | |
2246 const _Proxy.direct() : host = null, port = null, | |
2247 username = null, password = null, isDirect = true; | |
2248 | |
2249 bool get isAuthenticated => username != null; | |
2250 | |
2251 final String host; | 2210 final String host; |
2252 final int port; | 2211 final int port; |
2253 final String username; | 2212 final String username; |
2254 final String password; | 2213 final String password; |
2255 final bool isDirect; | 2214 final bool isDirect; |
| 2215 |
| 2216 const _Proxy(this.host, this.port, this.username, this.password) |
| 2217 : isDirect = false; |
| 2218 const _Proxy.direct() : host = null, port = null, |
| 2219 username = null, password = null, isDirect = true; |
| 2220 |
| 2221 bool get isAuthenticated => username != null; |
2256 } | 2222 } |
2257 | 2223 |
2258 | 2224 |
2259 class _HttpConnectionInfo implements HttpConnectionInfo { | 2225 class _HttpConnectionInfo implements HttpConnectionInfo { |
| 2226 InternetAddress remoteAddress; |
| 2227 int remotePort; |
| 2228 int localPort; |
| 2229 |
2260 static _HttpConnectionInfo create(Socket socket) { | 2230 static _HttpConnectionInfo create(Socket socket) { |
2261 if (socket == null) return null; | 2231 if (socket == null) return null; |
2262 try { | 2232 try { |
2263 _HttpConnectionInfo info = new _HttpConnectionInfo(); | 2233 _HttpConnectionInfo info = new _HttpConnectionInfo(); |
2264 info.remoteAddress = socket.remoteAddress; | 2234 return info |
2265 info.remotePort = socket.remotePort; | 2235 ..remoteAddress = socket.remoteAddress |
2266 info.localPort = socket.port; | 2236 ..remotePort = socket.remotePort |
2267 return info; | 2237 ..localPort = socket.port; |
2268 } catch (e) { } | 2238 } catch (e) { } |
2269 return null; | 2239 return null; |
2270 } | 2240 } |
2271 | |
2272 InternetAddress remoteAddress; | |
2273 int remotePort; | |
2274 int localPort; | |
2275 } | 2241 } |
2276 | 2242 |
2277 | 2243 |
2278 class _DetachedSocket extends Stream<List<int>> implements Socket { | 2244 class _DetachedSocket extends Stream<List<int>> implements Socket { |
2279 final Stream<List<int>> _incoming; | 2245 final Stream<List<int>> _incoming; |
2280 final Socket _socket; | 2246 final Socket _socket; |
2281 | 2247 |
2282 _DetachedSocket(this._socket, this._incoming); | 2248 _DetachedSocket(this._socket, this._incoming); |
2283 | 2249 |
2284 StreamSubscription<List<int>> listen(void onData(List<int> event), | 2250 StreamSubscription<List<int>> listen(void onData(List<int> event), |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2332 | 2298 |
2333 int get remotePort => _socket.remotePort; | 2299 int get remotePort => _socket.remotePort; |
2334 | 2300 |
2335 bool setOption(SocketOption option, bool enabled) { | 2301 bool setOption(SocketOption option, bool enabled) { |
2336 return _socket.setOption(option, enabled); | 2302 return _socket.setOption(option, enabled); |
2337 } | 2303 } |
2338 } | 2304 } |
2339 | 2305 |
2340 | 2306 |
2341 class _AuthenticationScheme { | 2307 class _AuthenticationScheme { |
| 2308 final int _scheme; |
| 2309 |
2342 static const UNKNOWN = const _AuthenticationScheme(-1); | 2310 static const UNKNOWN = const _AuthenticationScheme(-1); |
2343 static const BASIC = const _AuthenticationScheme(0); | 2311 static const BASIC = const _AuthenticationScheme(0); |
2344 static const DIGEST = const _AuthenticationScheme(1); | 2312 static const DIGEST = const _AuthenticationScheme(1); |
2345 | 2313 |
2346 const _AuthenticationScheme(this._scheme); | 2314 const _AuthenticationScheme(this._scheme); |
2347 | 2315 |
2348 factory _AuthenticationScheme.fromString(String scheme) { | 2316 factory _AuthenticationScheme.fromString(String scheme) { |
2349 if (scheme.toLowerCase() == "basic") return BASIC; | 2317 if (scheme.toLowerCase() == "basic") return BASIC; |
2350 if (scheme.toLowerCase() == "digest") return DIGEST; | 2318 if (scheme.toLowerCase() == "digest") return DIGEST; |
2351 return UNKNOWN; | 2319 return UNKNOWN; |
2352 } | 2320 } |
2353 | 2321 |
2354 String toString() { | 2322 String toString() { |
2355 if (this == BASIC) return "Basic"; | 2323 if (this == BASIC) return "Basic"; |
2356 if (this == DIGEST) return "Digest"; | 2324 if (this == DIGEST) return "Digest"; |
2357 return "Unknown"; | 2325 return "Unknown"; |
2358 } | 2326 } |
2359 | |
2360 final int _scheme; | |
2361 } | 2327 } |
2362 | 2328 |
2363 | 2329 |
2364 abstract class _Credentials { | 2330 abstract class _Credentials { |
2365 _HttpClientCredentials credentials; | 2331 _HttpClientCredentials credentials; |
2366 String realm; | 2332 String realm; |
2367 bool used = false; | 2333 bool used = false; |
2368 | 2334 |
2369 // Digest specific fields. | 2335 // Digest specific fields. |
2370 String ha1; | 2336 String ha1; |
2371 String nonce; | 2337 String nonce; |
2372 String algorithm; | 2338 String algorithm; |
2373 String qop; | 2339 String qop; |
2374 int nonceCount; | 2340 int nonceCount; |
2375 | 2341 |
2376 _Credentials(this.credentials, this.realm) { | 2342 _Credentials(this.credentials, this.realm) { |
2377 if (credentials.scheme == _AuthenticationScheme.DIGEST) { | 2343 if (credentials.scheme == _AuthenticationScheme.DIGEST) { |
2378 // Calculate the H(A1) value once. There is no mentioning of | 2344 // Calculate the H(A1) value once. There is no mentioning of |
2379 // username/password encoding in RFC 2617. However there is an | 2345 // username/password encoding in RFC 2617. However there is an |
2380 // open draft for adding an additional accept-charset parameter to | 2346 // open draft for adding an additional accept-charset parameter to |
2381 // the WWW-Authenticate and Proxy-Authenticate headers, see | 2347 // the WWW-Authenticate and Proxy-Authenticate headers, see |
2382 // http://tools.ietf.org/html/draft-reschke-basicauth-enc-06. For | 2348 // http://tools.ietf.org/html/draft-reschke-basicauth-enc-06. For |
2383 // now always use UTF-8 encoding. | 2349 // now always use UTF-8 encoding. |
2384 _HttpClientDigestCredentials creds = credentials; | 2350 _HttpClientDigestCredentials creds = credentials; |
2385 var hasher = new _MD5(); | 2351 var hasher = new _MD5() |
2386 hasher.add(UTF8.encode(creds.username)); | 2352 ..add(UTF8.encode(creds.username)) |
2387 hasher.add([_CharCode.COLON]); | 2353 ..add([_CharCode.COLON]) |
2388 hasher.add(realm.codeUnits); | 2354 ..add(realm.codeUnits) |
2389 hasher.add([_CharCode.COLON]); | 2355 ..add([_CharCode.COLON]) |
2390 hasher.add(UTF8.encode(creds.password)); | 2356 ..add(UTF8.encode(creds.password)); |
2391 ha1 = _CryptoUtils.bytesToHex(hasher.close()); | 2357 ha1 = _CryptoUtils.bytesToHex(hasher.close()); |
2392 } | 2358 } |
2393 } | 2359 } |
2394 | 2360 |
2395 _AuthenticationScheme get scheme => credentials.scheme; | 2361 _AuthenticationScheme get scheme => credentials.scheme; |
2396 | 2362 |
2397 void authorize(HttpClientRequest request); | 2363 void authorize(HttpClientRequest request); |
2398 } | 2364 } |
2399 | 2365 |
2400 class _SiteCredentials extends _Credentials { | 2366 class _SiteCredentials extends _Credentials { |
2401 Uri uri; | 2367 Uri uri; |
2402 | 2368 |
2403 _SiteCredentials(this.uri, realm, _HttpClientCredentials creds) | 2369 _SiteCredentials(this.uri, realm, _HttpClientCredentials creds) |
2404 : super(creds, realm); | 2370 : super(creds, realm); |
2405 | 2371 |
2406 bool applies(Uri uri, _AuthenticationScheme scheme) { | 2372 bool applies(Uri uri, _AuthenticationScheme scheme) { |
2407 if (scheme != null && credentials.scheme != scheme) return false; | 2373 if (scheme != null && credentials.scheme != scheme) return false; |
2408 if (uri.host != this.uri.host) return false; | 2374 if (uri.host != this.uri.host) return false; |
2409 int thisPort = | 2375 int thisPort = |
2410 this.uri.port == 0 ? HttpClient.DEFAULT_HTTP_PORT : this.uri.port; | 2376 this.uri.port == 0 ? HttpClient.DEFAULT_HTTP_PORT : this.uri.port; |
2411 int otherPort = uri.port == 0 ? HttpClient.DEFAULT_HTTP_PORT : uri.port; | 2377 int otherPort = uri.port == 0 ? HttpClient.DEFAULT_HTTP_PORT : uri.port; |
2412 if (otherPort != thisPort) return false; | 2378 if (otherPort != thisPort) return false; |
2413 return uri.path.startsWith(this.uri.path); | 2379 return uri.path.startsWith(this.uri.path); |
2414 } | 2380 } |
(...skipping 12 matching lines...) Expand all Loading... |
2427 | 2393 |
2428 | 2394 |
2429 class _ProxyCredentials extends _Credentials { | 2395 class _ProxyCredentials extends _Credentials { |
2430 String host; | 2396 String host; |
2431 int port; | 2397 int port; |
2432 | 2398 |
2433 _ProxyCredentials(this.host, | 2399 _ProxyCredentials(this.host, |
2434 this.port, | 2400 this.port, |
2435 realm, | 2401 realm, |
2436 _HttpClientCredentials creds) | 2402 _HttpClientCredentials creds) |
2437 : super(creds, realm); | 2403 : super(creds, realm); |
2438 | 2404 |
2439 bool applies(_Proxy proxy, _AuthenticationScheme scheme) { | 2405 bool applies(_Proxy proxy, _AuthenticationScheme scheme) { |
2440 if (scheme != null && credentials.scheme != scheme) return false; | 2406 if (scheme != null && credentials.scheme != scheme) return false; |
2441 return proxy.host == host && proxy.port == port; | 2407 return proxy.host == host && proxy.port == port; |
2442 } | 2408 } |
2443 | 2409 |
2444 void authorize(HttpClientRequest request) { | 2410 void authorize(HttpClientRequest request) { |
2445 // Digest credentials cannot be used without a nonce from the | 2411 // Digest credentials cannot be used without a nonce from the |
2446 // server. | 2412 // server. |
2447 if (credentials.scheme == _AuthenticationScheme.DIGEST && | 2413 if (credentials.scheme == _AuthenticationScheme.DIGEST && |
2448 nonce == null) { | 2414 nonce == null) { |
2449 return; | 2415 return; |
2450 } | 2416 } |
2451 credentials.authorizeProxy(this, request); | 2417 credentials.authorizeProxy(this, request); |
2452 } | 2418 } |
2453 } | 2419 } |
2454 | 2420 |
2455 | 2421 |
2456 abstract class _HttpClientCredentials implements HttpClientCredentials { | 2422 abstract class _HttpClientCredentials implements HttpClientCredentials { |
2457 _AuthenticationScheme get scheme; | 2423 _AuthenticationScheme get scheme; |
2458 void authorize(_Credentials credentials, HttpClientRequest request); | 2424 void authorize(_Credentials credentials, HttpClientRequest request); |
2459 void authorizeProxy(_ProxyCredentials credentials, HttpClientRequest request); | 2425 void authorizeProxy(_ProxyCredentials credentials, HttpClientRequest request); |
2460 } | 2426 } |
2461 | 2427 |
2462 | 2428 |
2463 class _HttpClientBasicCredentials | 2429 class _HttpClientBasicCredentials |
2464 extends _HttpClientCredentials | 2430 extends _HttpClientCredentials |
2465 implements HttpClientBasicCredentials { | 2431 implements HttpClientBasicCredentials { |
2466 _HttpClientBasicCredentials(this.username, | 2432 String username; |
2467 this.password); | 2433 String password; |
| 2434 |
| 2435 _HttpClientBasicCredentials(this.username, this.password); |
2468 | 2436 |
2469 _AuthenticationScheme get scheme => _AuthenticationScheme.BASIC; | 2437 _AuthenticationScheme get scheme => _AuthenticationScheme.BASIC; |
2470 | 2438 |
2471 String authorization() { | 2439 String authorization() { |
2472 // There is no mentioning of username/password encoding in RFC | 2440 // There is no mentioning of username/password encoding in RFC |
2473 // 2617. However there is an open draft for adding an additional | 2441 // 2617. However there is an open draft for adding an additional |
2474 // accept-charset parameter to the WWW-Authenticate and | 2442 // accept-charset parameter to the WWW-Authenticate and |
2475 // Proxy-Authenticate headers, see | 2443 // Proxy-Authenticate headers, see |
2476 // http://tools.ietf.org/html/draft-reschke-basicauth-enc-06. For | 2444 // http://tools.ietf.org/html/draft-reschke-basicauth-enc-06. For |
2477 // now always use UTF-8 encoding. | 2445 // now always use UTF-8 encoding. |
2478 String auth = | 2446 String auth = |
2479 _CryptoUtils.bytesToBase64(UTF8.encode("$username:$password")); | 2447 _CryptoUtils.bytesToBase64(UTF8.encode("$username:$password")); |
2480 return "Basic $auth"; | 2448 return "Basic $auth"; |
2481 } | 2449 } |
2482 | 2450 |
2483 void authorize(_Credentials _, HttpClientRequest request) { | 2451 void authorize(_Credentials _, HttpClientRequest request) => |
2484 request.headers.set(HttpHeaders.AUTHORIZATION, authorization()); | 2452 request.headers.set(HttpHeaders.AUTHORIZATION, authorization()); |
2485 } | |
2486 | 2453 |
2487 void authorizeProxy(_ProxyCredentials _, HttpClientRequest request) { | 2454 void authorizeProxy(_ProxyCredentials _, HttpClientRequest request) => |
2488 request.headers.set(HttpHeaders.PROXY_AUTHORIZATION, authorization()); | 2455 request.headers.set(HttpHeaders.PROXY_AUTHORIZATION, authorization()); |
2489 } | |
2490 | |
2491 String username; | |
2492 String password; | |
2493 } | 2456 } |
2494 | 2457 |
2495 | 2458 |
2496 class _HttpClientDigestCredentials | 2459 class _HttpClientDigestCredentials |
2497 extends _HttpClientCredentials | 2460 extends _HttpClientCredentials |
2498 implements HttpClientDigestCredentials { | 2461 implements HttpClientDigestCredentials { |
2499 _HttpClientDigestCredentials(this.username, | 2462 String username; |
2500 this.password); | 2463 String password; |
| 2464 |
| 2465 _HttpClientDigestCredentials(this.username, this.password); |
2501 | 2466 |
2502 _AuthenticationScheme get scheme => _AuthenticationScheme.DIGEST; | 2467 _AuthenticationScheme get scheme => _AuthenticationScheme.DIGEST; |
2503 | 2468 |
2504 String authorization(_Credentials credentials, _HttpClientRequest request) { | 2469 String authorization(_Credentials credentials, _HttpClientRequest request) { |
2505 String requestUri = request._requestUri(); | 2470 String requestUri = request._requestUri(); |
2506 _MD5 hasher = new _MD5(); | 2471 _MD5 hasher = new _MD5() |
2507 hasher.add(request.method.codeUnits); | 2472 ..add(request.method.codeUnits) |
2508 hasher.add([_CharCode.COLON]); | 2473 ..add([_CharCode.COLON]) |
2509 hasher.add(requestUri.codeUnits); | 2474 ..add(requestUri.codeUnits); |
2510 var ha2 = _CryptoUtils.bytesToHex(hasher.close()); | 2475 var ha2 = _CryptoUtils.bytesToHex(hasher.close()); |
2511 | 2476 |
2512 String qop; | 2477 String qop; |
2513 String cnonce; | 2478 String cnonce; |
2514 String nc; | 2479 String nc; |
2515 var x; | 2480 var x; |
2516 hasher = new _MD5(); | 2481 hasher = new _MD5() |
2517 hasher.add(credentials.ha1.codeUnits); | 2482 ..add(credentials.ha1.codeUnits) |
2518 hasher.add([_CharCode.COLON]); | 2483 ..add([_CharCode.COLON]); |
2519 if (credentials.qop == "auth") { | 2484 if (credentials.qop == "auth") { |
2520 qop = credentials.qop; | 2485 qop = credentials.qop; |
2521 cnonce = _CryptoUtils.bytesToHex(_IOCrypto.getRandomBytes(4)); | 2486 cnonce = _CryptoUtils.bytesToHex(_IOCrypto.getRandomBytes(4)); |
2522 ++credentials.nonceCount; | 2487 ++credentials.nonceCount; |
2523 nc = credentials.nonceCount.toRadixString(16); | 2488 nc = credentials.nonceCount.toRadixString(16); |
2524 nc = "00000000".substring(0, 8 - nc.length + 1) + nc; | 2489 nc = "00000000".substring(0, 8 - nc.length + 1) + nc; |
2525 hasher.add(credentials.nonce.codeUnits); | 2490 hasher |
2526 hasher.add([_CharCode.COLON]); | 2491 ..add(credentials.nonce.codeUnits) |
2527 hasher.add(nc.codeUnits); | 2492 ..add([_CharCode.COLON]) |
2528 hasher.add([_CharCode.COLON]); | 2493 ..add(nc.codeUnits) |
2529 hasher.add(cnonce.codeUnits); | 2494 ..add([_CharCode.COLON]) |
2530 hasher.add([_CharCode.COLON]); | 2495 ..add(cnonce.codeUnits) |
2531 hasher.add(credentials.qop.codeUnits); | 2496 ..add([_CharCode.COLON]) |
2532 hasher.add([_CharCode.COLON]); | 2497 ..add(credentials.qop.codeUnits) |
2533 hasher.add(ha2.codeUnits); | 2498 ..add([_CharCode.COLON]) |
| 2499 ..add(ha2.codeUnits); |
2534 } else { | 2500 } else { |
2535 hasher.add(credentials.nonce.codeUnits); | 2501 hasher |
2536 hasher.add([_CharCode.COLON]); | 2502 ..add(credentials.nonce.codeUnits) |
2537 hasher.add(ha2.codeUnits); | 2503 ..add([_CharCode.COLON]) |
| 2504 ..add(ha2.codeUnits); |
2538 } | 2505 } |
2539 var response = _CryptoUtils.bytesToHex(hasher.close()); | 2506 var response = _CryptoUtils.bytesToHex(hasher.close()); |
2540 | 2507 |
2541 StringBuffer buffer = new StringBuffer(); | 2508 StringBuffer buffer = new StringBuffer() |
2542 buffer.write('Digest '); | 2509 ..write('Digest ') |
2543 buffer.write('username="$username"'); | 2510 ..write('username="$username"') |
2544 buffer.write(', realm="${credentials.realm}"'); | 2511 ..write(', realm="${credentials.realm}"') |
2545 buffer.write(', nonce="${credentials.nonce}"'); | 2512 ..write(', nonce="${credentials.nonce}"') |
2546 buffer.write(', uri="$requestUri"'); | 2513 ..write(', uri="$requestUri"') |
2547 buffer.write(', algorithm="${credentials.algorithm}"'); | 2514 ..write(', algorithm="${credentials.algorithm}"'); |
2548 if (qop == "auth") { | 2515 if (qop == "auth") { |
2549 buffer.write(', qop="$qop"'); | 2516 buffer |
2550 buffer.write(', cnonce="$cnonce"'); | 2517 ..write(', qop="$qop"') |
2551 buffer.write(', nc="$nc"'); | 2518 ..write(', cnonce="$cnonce"') |
| 2519 ..write(', nc="$nc"'); |
2552 } | 2520 } |
2553 buffer.write(', response="$response"'); | 2521 buffer.write(', response="$response"'); |
2554 return buffer.toString(); | 2522 return buffer.toString(); |
2555 } | 2523 } |
2556 | 2524 |
2557 void authorize(_Credentials credentials, HttpClientRequest request) { | 2525 void authorize(_Credentials credentials, HttpClientRequest request) { |
2558 request.headers.set(HttpHeaders.AUTHORIZATION, | 2526 request.headers.set(HttpHeaders.AUTHORIZATION, |
2559 authorization(credentials, request)); | 2527 authorization(credentials, request)); |
2560 } | 2528 } |
2561 | 2529 |
2562 void authorizeProxy(_ProxyCredentials credentials, | 2530 void authorizeProxy(_ProxyCredentials credentials, |
2563 HttpClientRequest request) { | 2531 HttpClientRequest request) { |
2564 request.headers.set(HttpHeaders.PROXY_AUTHORIZATION, | 2532 request.headers.set(HttpHeaders.PROXY_AUTHORIZATION, |
2565 authorization(credentials, request)); | 2533 authorization(credentials, request)); |
2566 } | 2534 } |
2567 | |
2568 String username; | |
2569 String password; | |
2570 } | 2535 } |
2571 | 2536 |
2572 | 2537 |
2573 class _RedirectInfo implements RedirectInfo { | 2538 class _RedirectInfo implements RedirectInfo { |
2574 const _RedirectInfo(int this.statusCode, | |
2575 String this.method, | |
2576 Uri this.location); | |
2577 final int statusCode; | 2539 final int statusCode; |
2578 final String method; | 2540 final String method; |
2579 final Uri location; | 2541 final Uri location; |
| 2542 const _RedirectInfo(this.statusCode, this.method, this.location); |
2580 } | 2543 } |
2581 | 2544 |
2582 String _getHttpVersion() { | 2545 String _getHttpVersion() { |
2583 var version = Platform.version; | 2546 var version = Platform.version; |
2584 // Only include major and minor version numbers. | 2547 // Only include major and minor version numbers. |
2585 int index = version.indexOf('.', version.indexOf('.') + 1); | 2548 int index = version.indexOf('.', version.indexOf('.') + 1); |
2586 version = version.substring(0, index); | 2549 version = version.substring(0, index); |
2587 return 'Dart/$version (dart:io)'; | 2550 return 'Dart/$version (dart:io)'; |
2588 } | 2551 } |
2589 | |
2590 | |
OLD | NEW |