| 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 _OUTGOING_BUFFER_SIZE = 8 * 1024; | 7 const int _OUTGOING_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 292 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 303 .then((request) => request.close()); | 303 .then((request) => request.close()); |
| 304 }); | 304 }); |
| 305 } | 305 } |
| 306 | 306 |
| 307 List<String> authChallenge() { | 307 List<String> authChallenge() { |
| 308 return proxyAuth ? headers[HttpHeaders.PROXY_AUTHENTICATE] | 308 return proxyAuth ? headers[HttpHeaders.PROXY_AUTHENTICATE] |
| 309 : headers[HttpHeaders.WWW_AUTHENTICATE]; | 309 : headers[HttpHeaders.WWW_AUTHENTICATE]; |
| 310 } | 310 } |
| 311 | 311 |
| 312 _Credentials findCredentials(_AuthenticationScheme scheme) { | 312 _Credentials findCredentials(_AuthenticationScheme scheme) { |
| 313 return proxyAuth ? _httpClient._findProxyCredentials(_httpRequest._proxy,
scheme) | 313 return proxyAuth ? _httpClient._findProxyCredentials(_httpRequest._proxy, |
| 314 scheme) |
| 314 : _httpClient._findCredentials(_httpRequest.uri, scheme); | 315 : _httpClient._findCredentials(_httpRequest.uri, scheme); |
| 315 } | 316 } |
| 316 | 317 |
| 317 void removeCredentials(_Credentials cr) { | 318 void removeCredentials(_Credentials cr) { |
| 318 if (proxyAuth) { | 319 if (proxyAuth) { |
| 319 _httpClient._removeProxyCredentials(cr); | 320 _httpClient._removeProxyCredentials(cr); |
| 320 } else { | 321 } else { |
| 321 _httpClient._removeCredentials(cr); | 322 _httpClient._removeCredentials(cr); |
| 322 } | 323 } |
| 323 } | 324 } |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 404 }); | 405 }); |
| 405 } | 406 } |
| 406 } | 407 } |
| 407 | 408 |
| 408 | 409 |
| 409 abstract class _HttpOutboundMessage<T> extends _IOSinkImpl { | 410 abstract class _HttpOutboundMessage<T> extends _IOSinkImpl { |
| 410 // Used to mark when the body should be written. This is used for HEAD | 411 // Used to mark when the body should be written. This is used for HEAD |
| 411 // requests and in error handling. | 412 // requests and in error handling. |
| 412 bool _encodingSet = false; | 413 bool _encodingSet = false; |
| 413 | 414 |
| 415 bool _bufferOutput = true; |
| 416 |
| 414 final Uri _uri; | 417 final Uri _uri; |
| 415 final _HttpOutgoing _outgoing; | 418 final _HttpOutgoing _outgoing; |
| 416 | 419 |
| 417 final _HttpHeaders headers; | 420 final _HttpHeaders headers; |
| 418 | 421 |
| 419 _HttpOutboundMessage(Uri uri, | 422 _HttpOutboundMessage(Uri uri, |
| 420 String protocolVersion, | 423 String protocolVersion, |
| 421 _HttpOutgoing outgoing) | 424 _HttpOutgoing outgoing) |
| 422 : super(outgoing, null), | 425 : super(outgoing, null), |
| 423 _uri = uri, | 426 _uri = uri, |
| (...skipping 10 matching lines...) Expand all Loading... |
| 434 int get contentLength => headers.contentLength; | 437 int get contentLength => headers.contentLength; |
| 435 void set contentLength(int contentLength) { | 438 void set contentLength(int contentLength) { |
| 436 headers.contentLength = contentLength; | 439 headers.contentLength = contentLength; |
| 437 } | 440 } |
| 438 | 441 |
| 439 bool get persistentConnection => headers.persistentConnection; | 442 bool get persistentConnection => headers.persistentConnection; |
| 440 void set persistentConnection(bool p) { | 443 void set persistentConnection(bool p) { |
| 441 headers.persistentConnection = p; | 444 headers.persistentConnection = p; |
| 442 } | 445 } |
| 443 | 446 |
| 447 bool get bufferOutput => _bufferOutput; |
| 448 void set bufferOutput(bool bufferOutput) { |
| 449 if (_outgoing.headersWritten) throw new StateError("Header already sent"); |
| 450 _bufferOutput = bufferOutput; |
| 451 } |
| 452 |
| 453 |
| 444 Encoding get encoding { | 454 Encoding get encoding { |
| 445 if (_encodingSet && _outgoing.headersWritten) { | 455 if (_encodingSet && _outgoing.headersWritten) { |
| 446 return _encoding; | 456 return _encoding; |
| 447 } | 457 } |
| 448 var charset; | 458 var charset; |
| 449 if (headers.contentType != null && headers.contentType.charset != null) { | 459 if (headers.contentType != null && headers.contentType.charset != null) { |
| 450 charset = headers.contentType.charset; | 460 charset = headers.contentType.charset; |
| 451 } else { | 461 } else { |
| 452 charset = "iso-8859-1"; | 462 charset = "iso-8859-1"; |
| 453 } | 463 } |
| 454 return Encoding.getByName(charset); | 464 return Encoding.getByName(charset); |
| 455 } | 465 } |
| 456 | 466 |
| 457 void add(List<int> data) { | 467 void add(List<int> data) { |
| 458 if (data.length == 0) return; | 468 if (data.length == 0) return; |
| 459 super.add(data); | 469 super.add(data); |
| 460 } | 470 } |
| 461 | 471 |
| 462 void write(Object obj) { | 472 void write(Object obj) { |
| 463 if (!_encodingSet) { | 473 if (!_encodingSet) { |
| 464 _encoding = encoding; | 474 _encoding = encoding; |
| 465 _encodingSet = true; | 475 _encodingSet = true; |
| 466 } | 476 } |
| 467 super.write(obj); | 477 super.write(obj); |
| 468 } | 478 } |
| 469 | 479 |
| 470 void _writeHeader(); | 480 void _writeHeader(); |
| 481 |
| 482 bool get _isConnectionClosed => false; |
| 471 } | 483 } |
| 472 | 484 |
| 473 | 485 |
| 474 class _HttpResponse extends _HttpOutboundMessage<HttpResponse> | 486 class _HttpResponse extends _HttpOutboundMessage<HttpResponse> |
| 475 implements HttpResponse { | 487 implements HttpResponse { |
| 476 int _statusCode = 200; | 488 int _statusCode = 200; |
| 477 String _reasonPhrase; | 489 String _reasonPhrase; |
| 478 List<Cookie> _cookies; | 490 List<Cookie> _cookies; |
| 479 _HttpRequest _httpRequest; | 491 _HttpRequest _httpRequest; |
| 480 Duration _deadline; | 492 Duration _deadline; |
| 481 Timer _deadlineTimer; | 493 Timer _deadlineTimer; |
| 482 | 494 |
| 483 _HttpResponse(Uri uri, | 495 _HttpResponse(Uri uri, |
| 484 String protocolVersion, | 496 String protocolVersion, |
| 485 _HttpOutgoing outgoing, | 497 _HttpOutgoing outgoing, |
| 486 String serverHeader) | 498 String serverHeader) |
| 487 : super(uri, protocolVersion, outgoing) { | 499 : super(uri, protocolVersion, outgoing) { |
| 488 if (serverHeader != null) headers._add('server', serverHeader); | 500 if (serverHeader != null) headers._add('server', serverHeader); |
| 489 } | 501 } |
| 490 | 502 |
| 503 bool get _isConnectionClosed => _httpRequest._httpConnection._isClosing; |
| 504 |
| 491 List<Cookie> get cookies { | 505 List<Cookie> get cookies { |
| 492 if (_cookies == null) _cookies = new List<Cookie>(); | 506 if (_cookies == null) _cookies = new List<Cookie>(); |
| 493 return _cookies; | 507 return _cookies; |
| 494 } | 508 } |
| 495 | 509 |
| 496 int get statusCode => _statusCode; | 510 int get statusCode => _statusCode; |
| 497 void set statusCode(int statusCode) { | 511 void set statusCode(int statusCode) { |
| 498 if (_outgoing.headersWritten) throw new StateError("Header already sent"); | 512 if (_outgoing.headersWritten) throw new StateError("Header already sent"); |
| 499 _statusCode = statusCode; | 513 _statusCode = statusCode; |
| 500 } | 514 } |
| (...skipping 30 matching lines...) Expand all Loading... |
| 531 HttpConnectionInfo get connectionInfo => _httpRequest.connectionInfo; | 545 HttpConnectionInfo get connectionInfo => _httpRequest.connectionInfo; |
| 532 | 546 |
| 533 Duration get deadline => _deadline; | 547 Duration get deadline => _deadline; |
| 534 | 548 |
| 535 void set deadline(Duration d) { | 549 void set deadline(Duration d) { |
| 536 if (_deadlineTimer != null) _deadlineTimer.cancel(); | 550 if (_deadlineTimer != null) _deadlineTimer.cancel(); |
| 537 _deadline = d; | 551 _deadline = d; |
| 538 | 552 |
| 539 if (_deadline == null) return; | 553 if (_deadline == null) return; |
| 540 _deadlineTimer = new Timer(_deadline, () { | 554 _deadlineTimer = new Timer(_deadline, () { |
| 541 _outgoing._socketError = true; | 555 _httpRequest._httpConnection.destroy(); |
| 542 _outgoing.socket.destroy(); | |
| 543 }); | 556 }); |
| 544 } | 557 } |
| 545 | 558 |
| 546 void _writeHeader() { | 559 void _writeHeader() { |
| 547 Uint8List buffer = new Uint8List(_OUTGOING_BUFFER_SIZE); | 560 Uint8List buffer = new Uint8List(_OUTGOING_BUFFER_SIZE); |
| 548 int offset = 0; | 561 int offset = 0; |
| 549 | 562 |
| 550 void write(List<int> bytes) { | 563 void write(List<int> bytes) { |
| 551 int len = bytes.length; | 564 int len = bytes.length; |
| 552 for (int i = 0; i < len; i++) { | 565 for (int i = 0; i < len; i++) { |
| (...skipping 359 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 912 " bytes")); | 925 " bytes")); |
| 913 } | 926 } |
| 914 } | 927 } |
| 915 if (headersWritten) return null; | 928 if (headersWritten) return null; |
| 916 headersWritten = true; | 929 headersWritten = true; |
| 917 Future drainFuture; | 930 Future drainFuture; |
| 918 bool isServerSide = outbound is _HttpResponse; | 931 bool isServerSide = outbound is _HttpResponse; |
| 919 bool gzip = false; | 932 bool gzip = false; |
| 920 if (isServerSide) { | 933 if (isServerSide) { |
| 921 var response = outbound; | 934 var response = outbound; |
| 922 if (outbound.headers.chunkedTransferEncoding) { | 935 if (outbound.bufferOutput && outbound.headers.chunkedTransferEncoding) { |
| 923 List acceptEncodings = | 936 List acceptEncodings = |
| 924 response._httpRequest.headers[HttpHeaders.ACCEPT_ENCODING]; | 937 response._httpRequest.headers[HttpHeaders.ACCEPT_ENCODING]; |
| 925 List contentEncoding = outbound.headers[HttpHeaders.CONTENT_ENCODING]; | 938 List contentEncoding = outbound.headers[HttpHeaders.CONTENT_ENCODING]; |
| 926 if (acceptEncodings != null && | 939 if (acceptEncodings != null && |
| 927 acceptEncodings | 940 acceptEncodings |
| 928 .expand((list) => list.split(",")) | 941 .expand((list) => list.split(",")) |
| 929 .any((encoding) => encoding.trim().toLowerCase() == "gzip") && | 942 .any((encoding) => encoding.trim().toLowerCase() == "gzip") && |
| 930 contentEncoding == null) { | 943 contentEncoding == null) { |
| 931 outbound.headers.set(HttpHeaders.CONTENT_ENCODING, "gzip"); | 944 outbound.headers.set(HttpHeaders.CONTENT_ENCODING, "gzip"); |
| 932 gzip = true; | 945 gzip = true; |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1036 } | 1049 } |
| 1037 }); | 1050 }); |
| 1038 } | 1051 } |
| 1039 | 1052 |
| 1040 Future close() { | 1053 Future close() { |
| 1041 // If we are already closed, return that future. | 1054 // If we are already closed, return that future. |
| 1042 if (_closeFuture != null) return _closeFuture; | 1055 if (_closeFuture != null) return _closeFuture; |
| 1043 // If we earlier saw an error, return immediate. The notification to | 1056 // If we earlier saw an error, return immediate. The notification to |
| 1044 // _Http*Connection is already done. | 1057 // _Http*Connection is already done. |
| 1045 if (_socketError) return new Future.value(outbound); | 1058 if (_socketError) return new Future.value(outbound); |
| 1059 if (outbound._isConnectionClosed) return new Future.value(outbound); |
| 1046 if (!headersWritten && !ignoreBody) { | 1060 if (!headersWritten && !ignoreBody) { |
| 1047 if (outbound.headers.contentLength == -1) { | 1061 if (outbound.headers.contentLength == -1) { |
| 1048 // If no body was written, ignoreBody is false (it's not a HEAD | 1062 // If no body was written, ignoreBody is false (it's not a HEAD |
| 1049 // request) and the content-length is unspecified, set contentLength to | 1063 // request) and the content-length is unspecified, set contentLength to |
| 1050 // 0. | 1064 // 0. |
| 1051 outbound.headers.chunkedTransferEncoding = false; | 1065 outbound.headers.chunkedTransferEncoding = false; |
| 1052 outbound.headers.contentLength = 0; | 1066 outbound.headers.contentLength = 0; |
| 1053 } else if (outbound.headers.contentLength > 0) { | 1067 } else if (outbound.headers.contentLength > 0) { |
| 1054 var error = new HttpException( | 1068 var error = new HttpException( |
| 1055 "No content even though contentLength was specified to be " | 1069 "No content even though contentLength was specified to be " |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1142 _addChunk(data, _gzipAdd); | 1156 _addChunk(data, _gzipAdd); |
| 1143 })); | 1157 })); |
| 1144 } | 1158 } |
| 1145 } | 1159 } |
| 1146 | 1160 |
| 1147 bool _ignoreError(error) | 1161 bool _ignoreError(error) |
| 1148 => (error is SocketException || error is TlsException) && | 1162 => (error is SocketException || error is TlsException) && |
| 1149 outbound is HttpResponse; | 1163 outbound is HttpResponse; |
| 1150 | 1164 |
| 1151 void _addGZipChunk(chunk, void add(List<int> data)) { | 1165 void _addGZipChunk(chunk, void add(List<int> data)) { |
| 1166 if (!outbound.bufferOutput) { |
| 1167 add(chunk); |
| 1168 return; |
| 1169 } |
| 1152 if (chunk.length > _gzipBuffer.length - _gzipBufferLength) { | 1170 if (chunk.length > _gzipBuffer.length - _gzipBufferLength) { |
| 1153 add(new Uint8List.view( | 1171 add(new Uint8List.view( |
| 1154 _gzipBuffer.buffer, 0, _gzipBufferLength)); | 1172 _gzipBuffer.buffer, 0, _gzipBufferLength)); |
| 1155 _gzipBuffer = new Uint8List(_OUTGOING_BUFFER_SIZE); | 1173 _gzipBuffer = new Uint8List(_OUTGOING_BUFFER_SIZE); |
| 1156 _gzipBufferLength = 0; | 1174 _gzipBufferLength = 0; |
| 1157 } | 1175 } |
| 1158 if (chunk.length > _OUTGOING_BUFFER_SIZE) { | 1176 if (chunk.length > _OUTGOING_BUFFER_SIZE) { |
| 1159 add(chunk); | 1177 add(chunk); |
| 1160 } else { | 1178 } else { |
| 1161 _gzipBuffer.setRange(_gzipBufferLength, | 1179 _gzipBuffer.setRange(_gzipBufferLength, |
| 1162 _gzipBufferLength + chunk.length, | 1180 _gzipBufferLength + chunk.length, |
| 1163 chunk); | 1181 chunk); |
| 1164 _gzipBufferLength += chunk.length; | 1182 _gzipBufferLength += chunk.length; |
| 1165 } | 1183 } |
| 1166 } | 1184 } |
| 1167 | 1185 |
| 1168 void _addChunk(chunk, void add(List<int> data)) { | 1186 void _addChunk(chunk, void add(List<int> data)) { |
| 1187 if (!outbound.bufferOutput) { |
| 1188 if (_buffer != null) { |
| 1189 // If _buffer is not null, we have not written the header yet. Write |
| 1190 // it now. |
| 1191 add(new Uint8List.view(_buffer.buffer, 0, _length)); |
| 1192 _buffer = null; |
| 1193 _length = 0; |
| 1194 } |
| 1195 add(chunk); |
| 1196 return; |
| 1197 } |
| 1169 if (chunk.length > _buffer.length - _length) { | 1198 if (chunk.length > _buffer.length - _length) { |
| 1170 add(new Uint8List.view(_buffer.buffer, 0, _length)); | 1199 add(new Uint8List.view(_buffer.buffer, 0, _length)); |
| 1171 _buffer = new Uint8List(_OUTGOING_BUFFER_SIZE); | 1200 _buffer = new Uint8List(_OUTGOING_BUFFER_SIZE); |
| 1172 _length = 0; | 1201 _length = 0; |
| 1173 } | 1202 } |
| 1174 if (chunk.length > _OUTGOING_BUFFER_SIZE) { | 1203 if (chunk.length > _OUTGOING_BUFFER_SIZE) { |
| 1175 add(chunk); | 1204 add(chunk); |
| 1176 } else { | 1205 } else { |
| 1177 _buffer.setRange(_length, _length + chunk.length, chunk); | 1206 _buffer.setRange(_length, _length + chunk.length, chunk); |
| 1178 _length += chunk.length; | 1207 _length += chunk.length; |
| (...skipping 1398 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2577 const _RedirectInfo(this.statusCode, this.method, this.location); | 2606 const _RedirectInfo(this.statusCode, this.method, this.location); |
| 2578 } | 2607 } |
| 2579 | 2608 |
| 2580 String _getHttpVersion() { | 2609 String _getHttpVersion() { |
| 2581 var version = Platform.version; | 2610 var version = Platform.version; |
| 2582 // Only include major and minor version numbers. | 2611 // Only include major and minor version numbers. |
| 2583 int index = version.indexOf('.', version.indexOf('.') + 1); | 2612 int index = version.indexOf('.', version.indexOf('.') + 1); |
| 2584 version = version.substring(0, index); | 2613 version = version.substring(0, index); |
| 2585 return 'Dart/$version (dart:io)'; | 2614 return 'Dart/$version (dart:io)'; |
| 2586 } | 2615 } |
| OLD | NEW |