Index: sdk/lib/io/http_headers.dart |
diff --git a/sdk/lib/io/http_headers.dart b/sdk/lib/io/http_headers.dart |
index cb2935c1d6fc0eb7c1c40e063c9740747b730d18..b32748beda41dd683eea8cbd26dc28d6061cf705 100644 |
--- a/sdk/lib/io/http_headers.dart |
+++ b/sdk/lib/io/http_headers.dart |
@@ -5,8 +5,24 @@ |
part of dart.io; |
class _HttpHeaders implements HttpHeaders { |
+ final Map<String, List<String>> _headers; |
+ final String protocolVersion; |
+ |
+ bool _mutable = true; // Are the headers currently mutable? |
+ List<String> _noFoldingHeaders; |
+ |
+ int _contentLength = -1; |
+ bool _persistentConnection = true; |
+ bool _chunkedTransferEncoding = false; |
+ String _host; |
+ int _port; |
+ |
_HttpHeaders(String this.protocolVersion) |
- : _headers = new HashMap<String, List<String>>(); |
+ : _headers = new HashMap<String, List<String>>() { |
+ if (protocolVersion == "1.0") { |
+ _persistentConnection = false; |
+ } |
+ } |
List<String> operator[](String name) { |
name = name.toLowerCase(); |
@@ -70,35 +86,46 @@ class _HttpHeaders implements HttpHeaders { |
_noFoldingHeaders.add(name); |
} |
- bool get persistentConnection { |
- List<String> connection = _headers[HttpHeaders.CONNECTION]; |
- if (protocolVersion == "1.1") { |
- if (connection == null) return true; |
- return !connection.any((value) => value.toLowerCase() == "close"); |
- } else { |
- if (connection == null) return false; |
- return connection.any((value) => value.toLowerCase() == "keep-alive"); |
- } |
- } |
+ bool get persistentConnection => _persistentConnection; |
void set persistentConnection(bool persistentConnection) { |
_checkMutable(); |
- // Determine the value of the "Connection" header. |
- remove(HttpHeaders.CONNECTION, "close"); |
- remove(HttpHeaders.CONNECTION, "keep-alive"); |
- if (protocolVersion == "1.1" && !persistentConnection) { |
- add(HttpHeaders.CONNECTION, "close"); |
- } else if (protocolVersion == "1.0" && persistentConnection) { |
- add(HttpHeaders.CONNECTION, "keep-alive"); |
+ if (persistentConnection == _persistentConnection) return; |
+ if (persistentConnection) { |
+ if (protocolVersion == "1.1") { |
+ remove(HttpHeaders.CONNECTION, "close"); |
+ } else { |
+ if (_contentLength == -1) { |
+ throw new HttpException( |
+ "Trying to set 'Connection: Keep-Alive' on HTTP 1.0 headers with " |
+ "no ContentLength"); |
+ } |
+ add(HttpHeaders.CONNECTION, "keep-alive"); |
+ } |
+ } else { |
+ if (protocolVersion == "1.1") { |
+ add(HttpHeaders.CONNECTION, "close"); |
+ } else { |
+ remove(HttpHeaders.CONNECTION, "keep-alive"); |
+ } |
} |
+ _persistentConnection = persistentConnection; |
} |
int get contentLength => _contentLength; |
void set contentLength(int contentLength) { |
_checkMutable(); |
+ if (protocolVersion == "1.0" && |
+ persistentConnection && |
+ contentLength == -1) { |
+ throw new HttpException( |
+ "Trying to clear ContentLength on HTTP 1.0 headers with " |
+ "'Connection: Keep-Alive' set"); |
+ } |
_contentLength = contentLength; |
if (_contentLength >= 0) { |
+ if (chunkedTransferEncoding) chunkedTransferEncoding = false; |
_set(HttpHeaders.CONTENT_LENGTH, contentLength.toString()); |
} else { |
removeAll(HttpHeaders.CONTENT_LENGTH); |
@@ -109,16 +136,23 @@ class _HttpHeaders implements HttpHeaders { |
void set chunkedTransferEncoding(bool chunkedTransferEncoding) { |
_checkMutable(); |
- _chunkedTransferEncoding = chunkedTransferEncoding; |
- List<String> values = _headers[HttpHeaders.TRANSFER_ENCODING]; |
- if ((values == null || values[values.length - 1] != "chunked") && |
- chunkedTransferEncoding) { |
- // Headers does not specify chunked encoding - add it if set. |
+ if (chunkedTransferEncoding && protocolVersion == "1.0") { |
+ throw new HttpException( |
+ "Trying to set 'Transfer-Encoding: Chunked' on HTTP 1.0 headers"); |
+ } |
+ if (chunkedTransferEncoding == _chunkedTransferEncoding) return; |
+ if (chunkedTransferEncoding) { |
+ List<String> values = _headers[HttpHeaders.TRANSFER_ENCODING]; |
+ if ((values == null || values.last != "chunked")) { |
+ // Headers does not specify chunked encoding - add it if set. |
_addValue(HttpHeaders.TRANSFER_ENCODING, "chunked"); |
- } else if (!chunkedTransferEncoding) { |
+ } |
+ contentLength = -1; |
+ } else { |
// Headers does specify chunked encoding - remove it if not set. |
remove(HttpHeaders.TRANSFER_ENCODING, "chunked"); |
} |
+ _chunkedTransferEncoding = chunkedTransferEncoding; |
} |
String get host => _host; |
@@ -275,6 +309,14 @@ class _HttpHeaders implements HttpHeaders { |
} else { |
throw new HttpException("Unexpected type for header named $name"); |
} |
+ } else if (name == HttpHeaders.CONNECTION) { |
+ var lowerCaseValue = value.toLowerCase(); |
+ if (lowerCaseValue == 'close') { |
+ _persistentConnection = false; |
+ } else if (lowerCaseValue == 'keep-alive') { |
+ _persistentConnection = true; |
+ } |
+ _addValue(name, value); |
} else if (name == HttpHeaders.CONTENT_TYPE) { |
_set(HttpHeaders.CONTENT_TYPE, value); |
} else { |
@@ -321,27 +363,7 @@ class _HttpHeaders implements HttpHeaders { |
return true; |
} |
- void _synchronize() { |
- // If the content length is not known make sure chunked transfer |
- // encoding is used for HTTP 1.1. |
- if (contentLength < 0) { |
- if (protocolVersion == "1.0") { |
- persistentConnection = false; |
- } else { |
- chunkedTransferEncoding = true; |
- } |
- } |
- // If a Transfer-Encoding header field is present the |
- // Content-Length header MUST NOT be sent (RFC 2616 section 4.4). |
- if (chunkedTransferEncoding && |
- contentLength >= 0 && |
- protocolVersion == "1.1") { |
- contentLength = -1; |
- } |
- } |
- |
void _finalize() { |
- _synchronize(); |
_mutable = false; |
} |
@@ -463,17 +485,6 @@ class _HttpHeaders implements HttpHeaders { |
} |
return cookies; |
} |
- |
- |
- bool _mutable = true; // Are the headers currently mutable? |
- Map<String, List<String>> _headers; |
- List<String> _noFoldingHeaders; |
- |
- int _contentLength = -1; |
- bool _chunkedTransferEncoding = false; |
- final String protocolVersion; |
- String _host; |
- int _port; |
} |