| Index: runtime/bin/http_impl.dart
|
| diff --git a/runtime/bin/http_impl.dart b/runtime/bin/http_impl.dart
|
| index 05c0a8f3907ac8e08d5e94d19a022374a5f9430a..6c4db412700a266f8c7009da6a0a09628da3ede1 100644
|
| --- a/runtime/bin/http_impl.dart
|
| +++ b/runtime/bin/http_impl.dart
|
| @@ -32,6 +32,7 @@ class _HttpHeaders implements HttpHeaders {
|
| }
|
|
|
| void set(String name, Object value) {
|
| + name = name.toLowerCase();
|
| _checkMutable();
|
| removeAll(name);
|
| add(name, value);
|
| @@ -115,6 +116,20 @@ class _HttpHeaders implements HttpHeaders {
|
| _set("expires", formatted);
|
| }
|
|
|
| + ContentType get contentType() {
|
| + var values = _headers["content-type"];
|
| + if (values != null) {
|
| + return new ContentType.fromString(values[0]);
|
| + } else {
|
| + return new ContentType();
|
| + }
|
| + }
|
| +
|
| + void set contentType(ContentType contentType) {
|
| + _checkMutable();
|
| + _set("content-type", contentType.toString());
|
| + }
|
| +
|
| void _add(String name, Object value) {
|
| // TODO(sgjesse): Add immutable state throw HttpException is immutable.
|
| if (name.toLowerCase() == "date") {
|
| @@ -155,6 +170,8 @@ class _HttpHeaders implements HttpHeaders {
|
| }
|
| _set("host", value);
|
| }
|
| + } else if (name.toLowerCase() == "content-type") {
|
| + _set("content-type", value);
|
| } else {
|
| name = name.toLowerCase();
|
| List<String> values = _headers[name];
|
| @@ -229,6 +246,168 @@ class _HttpHeaders implements HttpHeaders {
|
| }
|
|
|
|
|
| +class _HeaderValue implements HeaderValue {
|
| + _HeaderValue([String this.value = ""]);
|
| +
|
| + _HeaderValue.fromString(String value) {
|
| + // Parse the string.
|
| + _parse(value);
|
| + }
|
| +
|
| + Map<String, String> get parameters() {
|
| + if (_parameters == null) _parameters = new Map<String, String>();
|
| + return _parameters;
|
| + }
|
| +
|
| + String toString() {
|
| + StringBuffer sb = new StringBuffer();
|
| + sb.add(value);
|
| + if (parameters != null && parameters.length > 0) {
|
| + _parameters.forEach((String name, String value) {
|
| + sb.add("; ");
|
| + sb.add(name);
|
| + sb.add("=");
|
| + sb.add(value);
|
| + });
|
| + }
|
| + return sb.toString();
|
| + }
|
| +
|
| + void _parse(String s) {
|
| + int index = 0;
|
| +
|
| + bool done() => index == s.length;
|
| +
|
| + void skipWS() {
|
| + while (!done()) {
|
| + if (s[index] != " " && s[index] != "\t") return;
|
| + index++;
|
| + }
|
| + }
|
| +
|
| + String parseValue() {
|
| + int start = index;
|
| + while (!done()) {
|
| + if (s[index] == " " || s[index] == "\t" || s[index] == ";") break;
|
| + index++;
|
| + }
|
| + return s.substring(start, index).toLowerCase();
|
| + }
|
| +
|
| + void expect(String expected) {
|
| + if (done()) throw new HttpException("Failed to parse header value [$s]");
|
| + if (s[index] != expected) {
|
| + throw new HttpException("Failed to parse header value [$s]");
|
| + }
|
| + index++;
|
| + }
|
| +
|
| + void parseParameters() {
|
| + _parameters = new Map<String, String>();
|
| +
|
| + String parseParameterName() {
|
| + int start = index;
|
| + while (!done()) {
|
| + if (s[index] == " " || s[index] == "\t" || s[index] == "=") break;
|
| + index++;
|
| + }
|
| + return s.substring(start, index).toLowerCase();
|
| + }
|
| +
|
| + String parseParameterValue() {
|
| + if (s[index] == "\"") {
|
| + // Parse quoted value.
|
| + StringBuffer sb = new StringBuffer();
|
| + index++;
|
| + while (!done()) {
|
| + if (s[index] == "\\") {
|
| + if (index + 1 == s.length) {
|
| + throw new HttpException("Failed to parse header value [$s]");
|
| + }
|
| + index++;
|
| + } else if (s[index] == "\"") {
|
| + index++;
|
| + break;
|
| + }
|
| + sb.add(s[index]);
|
| + index++;
|
| + }
|
| + return sb.toString();
|
| + } else {
|
| + // Parse non-quoted value.
|
| + return parseValue();
|
| + }
|
| + }
|
| +
|
| + while (!done()) {
|
| + skipWS();
|
| + if (done()) return;
|
| + String name = parseParameterName();
|
| + skipWS();
|
| + expect("=");
|
| + skipWS();
|
| + String value = parseParameterValue();
|
| + _parameters[name] = value;
|
| + skipWS();
|
| + if (done()) return;
|
| + expect(";");
|
| + }
|
| + }
|
| +
|
| + skipWS();
|
| + value = parseValue();
|
| + skipWS();
|
| + if (done()) return;
|
| + expect(";");
|
| + parseParameters();
|
| + }
|
| +
|
| + String value;
|
| + Map<String, String> _parameters;
|
| +}
|
| +
|
| +
|
| +class _ContentType extends _HeaderValue implements ContentType {
|
| + _ContentType([String this._primaryType = "", String this._subType = ""]);
|
| +
|
| + _ContentType.fromString(String value) : super.fromString(value);
|
| +
|
| + String get value() => "$_primaryType/$_subType";
|
| +
|
| + void set value(String s) {
|
| + int index = s.indexOf("/");
|
| + if (index == -1 || index == (s.length - 1)) {
|
| + primaryType = s.trim().toLowerCase();
|
| + subType = "";
|
| + } else {
|
| + primaryType = s.substring(0, index).trim().toLowerCase();
|
| + subType = s.substring(index + 1).trim().toLowerCase();
|
| + }
|
| + }
|
| +
|
| + String get primaryType() => _primaryType;
|
| +
|
| + void set primaryType(String s) {
|
| + _primaryType = s;
|
| + }
|
| +
|
| + String get subType() => _subType;
|
| +
|
| + void set subType(String s) {
|
| + _subType = s;
|
| + }
|
| +
|
| + String get charset() => parameters["charset"];
|
| +
|
| + void set charset(String s) {
|
| + parameters["charset"] = s;
|
| + }
|
| +
|
| + String _primaryType = "";
|
| + String _subType = "";
|
| +}
|
| +
|
| +
|
| class _HttpRequestResponseBase {
|
| final int START = 0;
|
| final int HEADER_SENT = 1;
|
|
|