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

Unified Diff: runtime/bin/http_impl.dart

Issue 10082003: Start refactoring of the HTTP header handling (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Addressed review comments Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/bin/http.dart ('k') | runtime/bin/http_parser.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/bin/http_impl.dart
diff --git a/runtime/bin/http_impl.dart b/runtime/bin/http_impl.dart
index 784ad824070f285038a447b988ce56804dd4596f..e74acb54769ae55776469eedec2f79717c16e431 100644
--- a/runtime/bin/http_impl.dart
+++ b/runtime/bin/http_impl.dart
@@ -2,17 +2,174 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+class _HttpHeaders implements HttpHeaders {
+ _HttpHeaders() : _headers = new Map<String, List<String>>();
+
+ List<String> operator[](String name) {
+ name = name.toLowerCase();
+ return _headers[name];
+ }
+
+ void add(String name, Object value) {
+ if (value is List) {
+ for (int i = 0; i < value.length; i++) {
+ _add(name, vlaie[i]);
+ }
+ } else {
+ _add(name, value);
+ }
+ }
+
+ void set(String name, Object value) {
+ removeAll(name);
+ add(name, value);
+ }
+
+ void remove(String name, Object value) {
+ name = name.toLowerCase();
+ List<String> values = _headers[name];
+ if (values != null) {
+ int index = values.indexOf(value);
+ if (index != -1) {
+ values.removeRange(index, 1);
+ }
+ }
+ }
+
+ void removeAll(String name) {
+ name = name.toLowerCase();
+ _headers.remove(name);
+ }
+
+ String get host() => _host;
+ void set host(String host) {
+ _host = host;
+ _updateHostHeader();
+ }
+
+ int get port() => _port;
+ void set port(int port) {
+ _port = port;
+ _updateHostHeader();
+ }
+
+ Date get expires() {
+ if (_expires == null) {
+ List<String> values = _headers["expires"];
+ if (values != null) {
+ _expires = _HttpUtils.parseDate(values[0]);
+ }
+ }
+ return _expires;
+ }
+
+ void set expires(Date expires) {
+ _expires = expires;
+ // Format "Expires" header with date in Greenwich Mean Time (GMT).
+ String formatted =
+ _HttpUtils.formatDate(_expires.changeTimeZone(new TimeZone.utc()));
+ _set("expires", formatted);
+ }
+
+ void _add(String name, Object value) {
+ // TODO(sgjesse): Add immutable state throw HttpException is immutable.
+ if (name.toLowerCase() == "expires") {
+ if (value is Date) {
+ expires = value;
+ } else if (value is String) {
+ expires = _HttpUtils.parseDate(value);
+ } else {
+ throw new HttpException("Unexpected type for header named $name");
+ }
+ } else if (name.toLowerCase() == "host") {
+ int pos = value.indexOf(":");
+ if (pos == -1) {
+ _host = value;
+ _port = HttpClient.DEFAULT_HTTP_PORT;
+ } else {
+ _host = value.substring(0, pos);
+ if (pos + 1 == value.length) {
+ _port = HttpClient.DEFAULT_HTTP_PORT;
+ } else {
+ _port = Math.parseInt(value.substring(pos + 1));
+ }
+ }
+ _updateHostHeader();
+ } else {
+ name = name.toLowerCase();
+ List<String> values = _headers[name];
+ if (values == null) {
+ values = new List<String>();
+ _headers[name] = values;
+ }
+ values.add(value.toString());
+ }
+ }
+
+ void _set(String name, String value) {
+ name = name.toLowerCase();
+ List<String> values = new List<String>();
+ _headers[name] = values;
+ values.add(value);
+ }
+
+ _updateHostHeader() {
+ String portPart = _port == HttpClient.DEFAULT_HTTP_PORT ? "" : ":$_port";
+ _set("host", "$host$portPart");
+ }
+
+ _write(_HttpConnectionBase connection) {
+ final COLONSP = const [_CharCode.COLON, _CharCode.SP];
+ final COMMASP = const [_CharCode.COMMA, _CharCode.SP];
+ final CRLF = const [_CharCode.CR, _CharCode.LF];
+
+ // Format headers.
+ _headers.forEach((String name, List<String> values) {
+ List<int> data;
+ data = name.charCodes();
+ connection._write(data);
+ connection._write(COLONSP);
+ for (int i = 0; i < values.length; i++) {
+ if (i > 0) {
+ connection._write(COMMASP);
+ }
+ data = values[i].charCodes();
+ connection._write(data);
+ }
+ connection._write(CRLF);
+ });
+ }
+
+ String toString() {
Anders Johnsen 2012/04/16 11:50:46 Looks good, and yes, let's use \n for line feed he
Søren Gjesse 2012/04/16 12:17:31 Good catch. Added return of sb.toString().
+ StringBuffer sb = new StringBuffer();
+ _headers.forEach((String name, List<String> values) {
+ sb.add(name);
+ sb.add(": ");
+ for (int i = 0; i < values.length; i++) {
+ if (i > 0) {
+ sb.add(": ");
+ }
+ sb.add(values[i]);
+ }
+ sb.add("\n");
+ });
+ }
+
+ Map<String, List<String>> _headers;
+
+ String _host;
+ int _port;
+ Date _expires;
+}
+
+
class _HttpRequestResponseBase {
_HttpRequestResponseBase(_HttpConnectionBase this._httpConnection)
: _contentLength = -1,
- _headers = new Map();
+ _headers = new _HttpHeaders();
int get contentLength() => _contentLength;
- Map get headers() => _headers;
-
- void _setHeader(String name, String value) {
- _headers[name.toLowerCase()] = value;
- }
+ HttpHeaders get headers() => _headers;
bool _write(List<int> data, bool copyBuffer) {
bool allWritten = true;
@@ -56,18 +213,7 @@ class _HttpRequestResponseBase {
}
bool _writeHeaders() {
- List<int> data;
-
- // Format headers.
- _headers.forEach((String name, String value) {
- data = name.charCodes();
- _httpConnection._write(data);
- data = ": ".charCodes();
- _httpConnection._write(data);
- data = value.charCodes();
- _httpConnection._write(data);
- _writeCRLF();
- });
+ _headers._write(_httpConnection);
// Terminate header.
return _writeCRLF();
}
@@ -97,7 +243,7 @@ class _HttpRequestResponseBase {
}
_HttpConnectionBase _httpConnection;
- Map<String, String> _headers;
+ _HttpHeaders _headers;
// Length of the content body. If this is set to -1 (default value)
// when starting to send data chunked transfer encoding will be
@@ -130,7 +276,7 @@ class _HttpRequest extends _HttpRequestResponseBase implements HttpRequest {
}
void _onHeaderReceived(String name, String value) {
- _setHeader(name, value);
+ _headers.add(name, value);
}
void _onHeadersComplete() {
@@ -219,27 +365,6 @@ class _HttpResponse extends _HttpRequestResponseBase implements HttpResponse {
_reasonPhrase = reasonPhrase;
}
- Date get expires() => _expires;
- void set expires(Date expires) {
- if (_outputStream != null) throw new HttpException("Header already sent");
- _expires = expires;
- // Format "Expires" header with date in Greenwich Mean Time (GMT).
- String formatted =
- _HttpUtils.formatDate(_expires.changeTimeZone(new TimeZone.utc()));
- _setHeader("Expires", formatted);
- }
-
- // Set a header on the response. NOTE: If the same header is set
- // more than once only the last one will be part of the response.
- void setHeader(String name, String value) {
- if (_outputStream != null) return new HttpException("Header already sent");
- if (name.toLowerCase() == "expires") {
- expires = _HttpUtils.parseDate(value);
- } else {
- _setHeader(name, value);
- }
- }
-
OutputStream get outputStream() {
if (_state == DONE) throw new HttpException("Response closed");
if (_outputStream == null) {
@@ -363,16 +488,16 @@ class _HttpResponse extends _HttpRequestResponseBase implements HttpResponse {
// Determine the value of the "Connection" header.
if (_protocolVersion == "1.1" && !_persistentConnection) {
- setHeader("Connection", "close");
+ _headers.set("Connection", "close");
} else if (_protocolVersion == "1.0" && _persistentConnection) {
- setHeader("Connection", "keep-alive");
+ _headers.set("Connection", "keep-alive");
}
// Determine the value of the "Transfer-Encoding" header based on
// whether the content length is known.
if (_contentLength >= 0) {
- setHeader("Content-Length", _contentLength.toString());
+ _headers.set("Content-Length", _contentLength.toString());
} else {
- setHeader("Transfer-Encoding", "chunked");
+ _headers.set("Transfer-Encoding", "chunked");
}
// Write headers.
@@ -385,7 +510,6 @@ class _HttpResponse extends _HttpRequestResponseBase implements HttpResponse {
int _statusCode;
String _reasonPhrase;
String _protocolVersion;
- Date _expires;
bool _persistentConnection;
_HttpOutputStream _outputStream;
int _state;
@@ -733,39 +857,6 @@ class _HttpClientRequest
void set contentLength(int contentLength) => _contentLength = contentLength;
- String get host() => _host;
- void set host(String host) {
- _host = host;
- _updateHostHeader();
- }
-
- int get port() => _port;
- void set port(int port) {
- _port = port;
- _updateHostHeader();
- }
-
- void setHeader(String name, String value) {
- if (_state != START) throw new HttpException("Header already sent");
- if (name.toLowerCase() == "host") {
- int pos = value.indexOf(":");
- if (pos == -1) {
- _host = value;
- _port = HttpClient.DEFAULT_HTTP_PORT;
- } else {
- _host = value.substring(0, pos);
- if (pos + 1 == value.length) {
- _port = HttpClient.DEFAULT_HTTP_PORT;
- } else {
- _port = Math.parseInt(value.substring(pos + 1));
- }
- }
- _updateHostHeader();
- return;
- }
- _setHeader(name, value);
- }
-
OutputStream get outputStream() {
if (_state == DONE) throw new HttpException("Request closed");
if (_outputStream == null) {
@@ -778,11 +869,6 @@ class _HttpClientRequest
return _outputStream;
}
- _updateHostHeader() {
- String portPart = _port == HttpClient.DEFAULT_HTTP_PORT ? "" : ":$_port";
- _setHeader("Host", "$host$portPart");
- }
-
// Delegate functions for the HttpOutputStream implementation.
bool _streamWrite(List<int> buffer, bool copyBuffer) {
return _write(buffer, copyBuffer);
@@ -830,9 +916,9 @@ class _HttpClientRequest
// Determine the value of the "Transfer-Encoding" header based on
// whether the content length is known.
if (_contentLength >= 0) {
- setHeader("Content-Length", _contentLength.toString());
+ _headers.set("Content-Length", _contentLength.toString());
} else {
- setHeader("Transfer-Encoding", "chunked");
+ _headers.set("Transfer-Encoding", "chunked");
}
// Write headers.
@@ -842,8 +928,6 @@ class _HttpClientRequest
String _method;
String _uri;
- String _host;
- int _port;
_HttpClientConnection _connection;
_HttpOutputStream _outputStream;
int _state;
@@ -861,14 +945,6 @@ class _HttpClientResponse
int get statusCode() => _statusCode;
String get reasonPhrase() => _reasonPhrase;
- Date get expires() {
- String str = _headers["expires"];
- if (str == null) return null;
- return _HttpUtils.parseDate(str);
- }
-
- Map get headers() => _headers;
-
InputStream get inputStream() {
if (_inputStream == null) {
_inputStream = new _HttpInputStream(this);
@@ -886,7 +962,7 @@ class _HttpClientResponse
}
void _onHeaderReceived(String name, String value) {
- _setHeader(name, value);
+ _headers.add(name, value);
}
void _onHeadersComplete() {
@@ -1149,8 +1225,8 @@ class _HttpClient implements HttpClient {
_HttpClientConnection connection) {
connection._connectionEstablished(socketConn);
HttpClientRequest request = connection.open(method, path);
- request.host = host;
- request.port = port;
+ request.headers.host = host;
+ request.headers.port = port;
if (connection._onRequest != null) {
connection._onRequest(request);
} else {
« no previous file with comments | « runtime/bin/http.dart ('k') | runtime/bin/http_parser.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698