| Index: pkg/dev_compiler/tool/input_sdk/lib/io/http_headers.dart
|
| diff --git a/pkg/dev_compiler/tool/input_sdk/lib/io/http_headers.dart b/pkg/dev_compiler/tool/input_sdk/lib/io/http_headers.dart
|
| deleted file mode 100644
|
| index 6b14ae2d6c89208388f3ed676f8f12b537e3de49..0000000000000000000000000000000000000000
|
| --- a/pkg/dev_compiler/tool/input_sdk/lib/io/http_headers.dart
|
| +++ /dev/null
|
| @@ -1,999 +0,0 @@
|
| -// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
|
| -// 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.
|
| -
|
| -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;
|
| -
|
| - final int _defaultPortForScheme;
|
| -
|
| - _HttpHeaders(this.protocolVersion,
|
| - {int defaultPortForScheme: HttpClient.DEFAULT_HTTP_PORT,
|
| - _HttpHeaders initialHeaders})
|
| - : _headers = new HashMap<String, List<String>>(),
|
| - _defaultPortForScheme = defaultPortForScheme {
|
| - if (initialHeaders != null) {
|
| - initialHeaders._headers.forEach((name, value) => _headers[name] = value);
|
| - _contentLength = initialHeaders._contentLength;
|
| - _persistentConnection = initialHeaders._persistentConnection;
|
| - _chunkedTransferEncoding = initialHeaders._chunkedTransferEncoding;
|
| - _host = initialHeaders._host;
|
| - _port = initialHeaders._port;
|
| - }
|
| - if (protocolVersion == "1.0") {
|
| - _persistentConnection = false;
|
| - _chunkedTransferEncoding = false;
|
| - }
|
| - }
|
| -
|
| - List<String> operator[](String name) => _headers[name.toLowerCase()];
|
| -
|
| - String value(String name) {
|
| - name = name.toLowerCase();
|
| - List<String> values = _headers[name];
|
| - if (values == null) return null;
|
| - if (values.length > 1) {
|
| - throw new HttpException("More than one value for header $name");
|
| - }
|
| - return values[0];
|
| - }
|
| -
|
| - void add(String name, value) {
|
| - _checkMutable();
|
| - _addAll(_validateField(name), value);
|
| - }
|
| -
|
| - void _addAll(String name, value) {
|
| - assert(name == _validateField(name));
|
| - if (value is Iterable) {
|
| - for (var v in value) {
|
| - _add(name, _validateValue(v));
|
| - }
|
| - } else {
|
| - _add(name, _validateValue(value));
|
| - }
|
| - }
|
| -
|
| - void set(String name, Object value) {
|
| - _checkMutable();
|
| - name = _validateField(name);
|
| - _headers.remove(name);
|
| - if (name == HttpHeaders.TRANSFER_ENCODING) {
|
| - _chunkedTransferEncoding = false;
|
| - }
|
| - _addAll(name, value);
|
| - }
|
| -
|
| - void remove(String name, Object value) {
|
| - _checkMutable();
|
| - name = _validateField(name);
|
| - value = _validateValue(value);
|
| - List<String> values = _headers[name];
|
| - if (values != null) {
|
| - int index = values.indexOf(value);
|
| - if (index != -1) {
|
| - values.removeRange(index, index + 1);
|
| - }
|
| - if (values.length == 0) _headers.remove(name);
|
| - }
|
| - if (name == HttpHeaders.TRANSFER_ENCODING && value == "chunked") {
|
| - _chunkedTransferEncoding = false;
|
| - }
|
| - }
|
| -
|
| - void removeAll(String name) {
|
| - _checkMutable();
|
| - name = _validateField(name);
|
| - _headers.remove(name);
|
| - }
|
| -
|
| - void forEach(void f(String name, List<String> values)) {
|
| - _headers.forEach(f);
|
| - }
|
| -
|
| - void noFolding(String name) {
|
| - if (_noFoldingHeaders == null) _noFoldingHeaders = new List<String>();
|
| - _noFoldingHeaders.add(name);
|
| - }
|
| -
|
| - bool get persistentConnection => _persistentConnection;
|
| -
|
| - void set persistentConnection(bool persistentConnection) {
|
| - _checkMutable();
|
| - 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");
|
| - }
|
| - if (_contentLength == contentLength) return;
|
| - _contentLength = contentLength;
|
| - if (_contentLength >= 0) {
|
| - if (chunkedTransferEncoding) chunkedTransferEncoding = false;
|
| - _set(HttpHeaders.CONTENT_LENGTH, contentLength.toString());
|
| - } else {
|
| - removeAll(HttpHeaders.CONTENT_LENGTH);
|
| - if (protocolVersion == "1.1") {
|
| - chunkedTransferEncoding = true;
|
| - }
|
| - }
|
| - }
|
| -
|
| - bool get chunkedTransferEncoding => _chunkedTransferEncoding;
|
| -
|
| - void set chunkedTransferEncoding(bool chunkedTransferEncoding) {
|
| - _checkMutable();
|
| - 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");
|
| - }
|
| - contentLength = -1;
|
| - } else {
|
| - // Headers does specify chunked encoding - remove it if not set.
|
| - remove(HttpHeaders.TRANSFER_ENCODING, "chunked");
|
| - }
|
| - _chunkedTransferEncoding = chunkedTransferEncoding;
|
| - }
|
| -
|
| - String get host => _host;
|
| -
|
| - void set host(String host) {
|
| - _checkMutable();
|
| - _host = host;
|
| - _updateHostHeader();
|
| - }
|
| -
|
| - int get port => _port;
|
| -
|
| - void set port(int port) {
|
| - _checkMutable();
|
| - _port = port;
|
| - _updateHostHeader();
|
| - }
|
| -
|
| - DateTime get ifModifiedSince {
|
| - List<String> values = _headers[HttpHeaders.IF_MODIFIED_SINCE];
|
| - if (values != null) {
|
| - try {
|
| - return HttpDate.parse(values[0]);
|
| - } on Exception catch (e) {
|
| - return null;
|
| - }
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - void set ifModifiedSince(DateTime ifModifiedSince) {
|
| - _checkMutable();
|
| - // Format "ifModifiedSince" header with date in Greenwich Mean Time (GMT).
|
| - String formatted = HttpDate.format(ifModifiedSince.toUtc());
|
| - _set(HttpHeaders.IF_MODIFIED_SINCE, formatted);
|
| - }
|
| -
|
| - DateTime get date {
|
| - List<String> values = _headers[HttpHeaders.DATE];
|
| - if (values != null) {
|
| - try {
|
| - return HttpDate.parse(values[0]);
|
| - } on Exception catch (e) {
|
| - return null;
|
| - }
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - void set date(DateTime date) {
|
| - _checkMutable();
|
| - // Format "DateTime" header with date in Greenwich Mean Time (GMT).
|
| - String formatted = HttpDate.format(date.toUtc());
|
| - _set("date", formatted);
|
| - }
|
| -
|
| - DateTime get expires {
|
| - List<String> values = _headers[HttpHeaders.EXPIRES];
|
| - if (values != null) {
|
| - try {
|
| - return HttpDate.parse(values[0]);
|
| - } on Exception catch (e) {
|
| - return null;
|
| - }
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - void set expires(DateTime expires) {
|
| - _checkMutable();
|
| - // Format "Expires" header with date in Greenwich Mean Time (GMT).
|
| - String formatted = HttpDate.format(expires.toUtc());
|
| - _set(HttpHeaders.EXPIRES, formatted);
|
| - }
|
| -
|
| - ContentType get contentType {
|
| - var values = _headers["content-type"];
|
| - if (values != null) {
|
| - return ContentType.parse(values[0]);
|
| - } else {
|
| - return null;
|
| - }
|
| - }
|
| -
|
| - void set contentType(ContentType contentType) {
|
| - _checkMutable();
|
| - _set(HttpHeaders.CONTENT_TYPE, contentType.toString());
|
| - }
|
| -
|
| - void clear() {
|
| - _checkMutable();
|
| - _headers.clear();
|
| - _contentLength = -1;
|
| - _persistentConnection = true;
|
| - _chunkedTransferEncoding = false;
|
| - _host = null;
|
| - _port = null;
|
| - }
|
| -
|
| - // [name] must be a lower-case version of the name.
|
| - void _add(String name, value) {
|
| - assert(name == _validateField(name));
|
| - // Use the length as index on what method to call. This is notable
|
| - // faster than computing hash and looking up in a hash-map.
|
| - switch (name.length) {
|
| - case 4:
|
| - if (HttpHeaders.DATE == name) {
|
| - _addDate(name, value);
|
| - return;
|
| - }
|
| - if (HttpHeaders.HOST == name) {
|
| - _addHost(name, value);
|
| - return;
|
| - }
|
| - break;
|
| - case 7:
|
| - if (HttpHeaders.EXPIRES == name) {
|
| - _addExpires(name, value);
|
| - return;
|
| - }
|
| - break;
|
| - case 10:
|
| - if (HttpHeaders.CONNECTION == name) {
|
| - _addConnection(name, value);
|
| - return;
|
| - }
|
| - break;
|
| - case 12:
|
| - if (HttpHeaders.CONTENT_TYPE == name) {
|
| - _addContentType(name, value);
|
| - return;
|
| - }
|
| - break;
|
| - case 14:
|
| - if (HttpHeaders.CONTENT_LENGTH == name) {
|
| - _addContentLength(name, value);
|
| - return;
|
| - }
|
| - break;
|
| - case 17:
|
| - if (HttpHeaders.TRANSFER_ENCODING == name) {
|
| - _addTransferEncoding(name, value);
|
| - return;
|
| - }
|
| - if (HttpHeaders.IF_MODIFIED_SINCE == name) {
|
| - _addIfModifiedSince(name, value);
|
| - return;
|
| - }
|
| - }
|
| - _addValue(name, value);
|
| - }
|
| -
|
| - void _addContentLength(String name, value) {
|
| - if (value is int) {
|
| - contentLength = value;
|
| - } else if (value is String) {
|
| - contentLength = int.parse(value);
|
| - } else {
|
| - throw new HttpException("Unexpected type for header named $name");
|
| - }
|
| - }
|
| -
|
| - void _addTransferEncoding(String name, value) {
|
| - if (value == "chunked") {
|
| - chunkedTransferEncoding = true;
|
| - } else {
|
| - _addValue(HttpHeaders.TRANSFER_ENCODING, value);
|
| - }
|
| - }
|
| -
|
| - void _addDate(String name, value) {
|
| - if (value is DateTime) {
|
| - date = value;
|
| - } else if (value is String) {
|
| - _set(HttpHeaders.DATE, value);
|
| - } else {
|
| - throw new HttpException("Unexpected type for header named $name");
|
| - }
|
| - }
|
| -
|
| - void _addExpires(String name, value) {
|
| - if (value is DateTime) {
|
| - expires = value;
|
| - } else if (value is String) {
|
| - _set(HttpHeaders.EXPIRES, value);
|
| - } else {
|
| - throw new HttpException("Unexpected type for header named $name");
|
| - }
|
| - }
|
| -
|
| - void _addIfModifiedSince(String name, value) {
|
| - if (value is DateTime) {
|
| - ifModifiedSince = value;
|
| - } else if (value is String) {
|
| - _set(HttpHeaders.IF_MODIFIED_SINCE, value);
|
| - } else {
|
| - throw new HttpException("Unexpected type for header named $name");
|
| - }
|
| - }
|
| -
|
| - void _addHost(String name, value) {
|
| - if (value is String) {
|
| - int pos = value.indexOf(":");
|
| - if (pos == -1) {
|
| - _host = value;
|
| - _port = HttpClient.DEFAULT_HTTP_PORT;
|
| - } else {
|
| - if (pos > 0) {
|
| - _host = value.substring(0, pos);
|
| - } else {
|
| - _host = null;
|
| - }
|
| - if (pos + 1 == value.length) {
|
| - _port = HttpClient.DEFAULT_HTTP_PORT;
|
| - } else {
|
| - try {
|
| - _port = int.parse(value.substring(pos + 1));
|
| - } on FormatException catch (e) {
|
| - _port = null;
|
| - }
|
| - }
|
| - }
|
| - _set(HttpHeaders.HOST, value);
|
| - } else {
|
| - throw new HttpException("Unexpected type for header named $name");
|
| - }
|
| - }
|
| -
|
| - void _addConnection(String name, value) {
|
| - var lowerCaseValue = value.toLowerCase();
|
| - if (lowerCaseValue == 'close') {
|
| - _persistentConnection = false;
|
| - } else if (lowerCaseValue == 'keep-alive') {
|
| - _persistentConnection = true;
|
| - }
|
| - _addValue(name, value);
|
| - }
|
| -
|
| - void _addContentType(String name, value) {
|
| - _set(HttpHeaders.CONTENT_TYPE, value);
|
| - }
|
| -
|
| - void _addValue(String name, Object value) {
|
| - List<String> values = _headers[name];
|
| - if (values == null) {
|
| - values = new List<String>();
|
| - _headers[name] = values;
|
| - }
|
| - if (value is DateTime) {
|
| - values.add(HttpDate.format(value));
|
| - } else if (value is String) {
|
| - values.add(value);
|
| - } else {
|
| - values.add(_validateValue(value.toString()));
|
| - }
|
| - }
|
| -
|
| - void _set(String name, String value) {
|
| - assert(name == _validateField(name));
|
| - List<String> values = new List<String>();
|
| - _headers[name] = values;
|
| - values.add(value);
|
| - }
|
| -
|
| - _checkMutable() {
|
| - if (!_mutable) throw new HttpException("HTTP headers are not mutable");
|
| - }
|
| -
|
| - _updateHostHeader() {
|
| - bool defaultPort = _port == null || _port == _defaultPortForScheme;
|
| - _set("host", defaultPort ? host : "$host:$_port");
|
| - }
|
| -
|
| - _foldHeader(String name) {
|
| - if (name == HttpHeaders.SET_COOKIE ||
|
| - (_noFoldingHeaders != null &&
|
| - _noFoldingHeaders.indexOf(name) != -1)) {
|
| - return false;
|
| - }
|
| - return true;
|
| - }
|
| -
|
| - void _finalize() {
|
| - _mutable = false;
|
| - }
|
| -
|
| - int _write(Uint8List buffer, int offset) {
|
| - void write(List<int> bytes) {
|
| - int len = bytes.length;
|
| - for (int i = 0; i < len; i++) {
|
| - buffer[offset + i] = bytes[i];
|
| - }
|
| - offset += len;
|
| - }
|
| -
|
| - // Format headers.
|
| - for (String name in _headers.keys) {
|
| - List<String> values = _headers[name];
|
| - bool fold = _foldHeader(name);
|
| - var nameData = name.codeUnits;
|
| - write(nameData);
|
| - buffer[offset++] = _CharCode.COLON;
|
| - buffer[offset++] = _CharCode.SP;
|
| - for (int i = 0; i < values.length; i++) {
|
| - if (i > 0) {
|
| - if (fold) {
|
| - buffer[offset++] = _CharCode.COMMA;
|
| - buffer[offset++] = _CharCode.SP;
|
| - } else {
|
| - buffer[offset++] = _CharCode.CR;
|
| - buffer[offset++] = _CharCode.LF;
|
| - write(nameData);
|
| - buffer[offset++] = _CharCode.COLON;
|
| - buffer[offset++] = _CharCode.SP;
|
| - }
|
| - }
|
| - write(values[i].codeUnits);
|
| - }
|
| - buffer[offset++] = _CharCode.CR;
|
| - buffer[offset++] = _CharCode.LF;
|
| - }
|
| - return offset;
|
| - }
|
| -
|
| - String toString() {
|
| - StringBuffer sb = new StringBuffer();
|
| - _headers.forEach((String name, List<String> values) {
|
| - sb..write(name)..write(": ");
|
| - bool fold = _foldHeader(name);
|
| - for (int i = 0; i < values.length; i++) {
|
| - if (i > 0) {
|
| - if (fold) {
|
| - sb.write(", ");
|
| - } else {
|
| - sb..write("\n")..write(name)..write(": ");
|
| - }
|
| - }
|
| - sb.write(values[i]);
|
| - }
|
| - sb.write("\n");
|
| - });
|
| - return sb.toString();
|
| - }
|
| -
|
| - List<Cookie> _parseCookies() {
|
| - // Parse a Cookie header value according to the rules in RFC 6265.
|
| - var cookies = new List<Cookie>();
|
| - void parseCookieString(String s) {
|
| - int index = 0;
|
| -
|
| - bool done() => index == -1 || index == s.length;
|
| -
|
| - void skipWS() {
|
| - while (!done()) {
|
| - if (s[index] != " " && s[index] != "\t") return;
|
| - index++;
|
| - }
|
| - }
|
| -
|
| - String parseName() {
|
| - int start = index;
|
| - while (!done()) {
|
| - if (s[index] == " " || s[index] == "\t" || s[index] == "=") break;
|
| - index++;
|
| - }
|
| - return s.substring(start, index);
|
| - }
|
| -
|
| - String parseValue() {
|
| - int start = index;
|
| - while (!done()) {
|
| - if (s[index] == " " || s[index] == "\t" || s[index] == ";") break;
|
| - index++;
|
| - }
|
| - return s.substring(start, index);
|
| - }
|
| -
|
| - bool expect(String expected) {
|
| - if (done()) return false;
|
| - if (s[index] != expected) return false;
|
| - index++;
|
| - return true;
|
| - }
|
| -
|
| - while (!done()) {
|
| - skipWS();
|
| - if (done()) return;
|
| - String name = parseName();
|
| - skipWS();
|
| - if (!expect("=")) {
|
| - index = s.indexOf(';', index);
|
| - continue;
|
| - }
|
| - skipWS();
|
| - String value = parseValue();
|
| - try {
|
| - cookies.add(new _Cookie(name, value));
|
| - } catch (_) {
|
| - // Skip it, invalid cookie data.
|
| - }
|
| - skipWS();
|
| - if (done()) return;
|
| - if (!expect(";")) {
|
| - index = s.indexOf(';', index);
|
| - continue;
|
| - }
|
| - }
|
| - }
|
| - List<String> values = _headers[HttpHeaders.COOKIE];
|
| - if (values != null) {
|
| - values.forEach((headerValue) => parseCookieString(headerValue));
|
| - }
|
| - return cookies;
|
| - }
|
| -
|
| - static String _validateField(String field) {
|
| - for (var i = 0; i < field.length; i++) {
|
| - if (!_HttpParser._isTokenChar(field.codeUnitAt(i))) {
|
| - throw new FormatException(
|
| - "Invalid HTTP header field name: ${JSON.encode(field)}");
|
| - }
|
| - }
|
| - return field.toLowerCase();
|
| - }
|
| -
|
| - static _validateValue(value) {
|
| - if (value is! String) return value;
|
| - for (var i = 0; i < value.length; i++) {
|
| - if (!_HttpParser._isValueChar(value.codeUnitAt(i))) {
|
| - throw new FormatException(
|
| - "Invalid HTTP header field value: ${JSON.encode(value)}");
|
| - }
|
| - }
|
| - return value;
|
| - }
|
| -}
|
| -
|
| -
|
| -class _HeaderValue implements HeaderValue {
|
| - String _value;
|
| - Map<String, String> _parameters;
|
| - Map<String, String> _unmodifiableParameters;
|
| -
|
| - _HeaderValue([String this._value = "", Map<String, String> parameters]) {
|
| - if (parameters != null) {
|
| - _parameters = new HashMap<String, String>.from(parameters);
|
| - }
|
| - }
|
| -
|
| - static _HeaderValue parse(String value,
|
| - {parameterSeparator: ";",
|
| - valueSeparator: null,
|
| - preserveBackslash: false}) {
|
| - // Parse the string.
|
| - var result = new _HeaderValue();
|
| - result._parse(value, parameterSeparator, valueSeparator, preserveBackslash);
|
| - return result;
|
| - }
|
| -
|
| - String get value => _value;
|
| -
|
| - void _ensureParameters() {
|
| - if (_parameters == null) {
|
| - _parameters = new HashMap<String, String>();
|
| - }
|
| - }
|
| -
|
| - Map<String, String> get parameters {
|
| - _ensureParameters();
|
| - if (_unmodifiableParameters == null) {
|
| - _unmodifiableParameters = new UnmodifiableMapView(_parameters);
|
| - }
|
| - return _unmodifiableParameters;
|
| - }
|
| -
|
| - String toString() {
|
| - StringBuffer sb = new StringBuffer();
|
| - sb.write(_value);
|
| - if (parameters != null && parameters.length > 0) {
|
| - _parameters.forEach((String name, String value) {
|
| - sb..write("; ")..write(name)..write("=")..write(value);
|
| - });
|
| - }
|
| - return sb.toString();
|
| - }
|
| -
|
| - void _parse(String s,
|
| - String parameterSeparator,
|
| - String valueSeparator,
|
| - bool preserveBackslash) {
|
| - 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] == valueSeparator ||
|
| - s[index] == parameterSeparator) break;
|
| - index++;
|
| - }
|
| - return s.substring(start, index);
|
| - }
|
| -
|
| - void expect(String expected) {
|
| - if (done() || s[index] != expected) {
|
| - throw new HttpException("Failed to parse header value");
|
| - }
|
| - index++;
|
| - }
|
| -
|
| - void maybeExpect(String expected) {
|
| - if (s[index] == expected) index++;
|
| - }
|
| -
|
| - void parseParameters() {
|
| - var parameters = new HashMap<String, String>();
|
| - _parameters = new UnmodifiableMapView(parameters);
|
| -
|
| - String parseParameterName() {
|
| - int start = index;
|
| - while (!done()) {
|
| - if (s[index] == " " ||
|
| - s[index] == "\t" ||
|
| - s[index] == "=" ||
|
| - s[index] == parameterSeparator ||
|
| - s[index] == valueSeparator) break;
|
| - index++;
|
| - }
|
| - return s.substring(start, index).toLowerCase();
|
| - }
|
| -
|
| - String parseParameterValue() {
|
| - if (!done() && 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");
|
| - }
|
| - if (preserveBackslash && s[index + 1] != "\"") {
|
| - sb.write(s[index]);
|
| - }
|
| - index++;
|
| - } else if (s[index] == "\"") {
|
| - index++;
|
| - break;
|
| - }
|
| - sb.write(s[index]);
|
| - index++;
|
| - }
|
| - return sb.toString();
|
| - } else {
|
| - // Parse non-quoted value.
|
| - var val = parseValue();
|
| - return val == "" ? null : val;
|
| - }
|
| - }
|
| -
|
| - while (!done()) {
|
| - skipWS();
|
| - if (done()) return;
|
| - String name = parseParameterName();
|
| - skipWS();
|
| - if (done()) {
|
| - parameters[name] = null;
|
| - return;
|
| - }
|
| - maybeExpect("=");
|
| - skipWS();
|
| - if(done()) {
|
| - parameters[name] = null;
|
| - return;
|
| - }
|
| - String value = parseParameterValue();
|
| - if (name == 'charset' && this is _ContentType) {
|
| - // Charset parameter of ContentTypes are always lower-case.
|
| - value = value.toLowerCase();
|
| - }
|
| - parameters[name] = value;
|
| - skipWS();
|
| - if (done()) return;
|
| - // TODO: Implement support for multi-valued parameters.
|
| - if(s[index] == valueSeparator) return;
|
| - expect(parameterSeparator);
|
| - }
|
| - }
|
| -
|
| - skipWS();
|
| - _value = parseValue();
|
| - skipWS();
|
| - if (done()) return;
|
| - maybeExpect(parameterSeparator);
|
| - parseParameters();
|
| - }
|
| -}
|
| -
|
| -
|
| -class _ContentType extends _HeaderValue implements ContentType {
|
| - String _primaryType = "";
|
| - String _subType = "";
|
| -
|
| - _ContentType(String primaryType,
|
| - String subType,
|
| - String charset,
|
| - Map<String, String> parameters)
|
| - : _primaryType = primaryType, _subType = subType, super("") {
|
| - if (_primaryType == null) _primaryType = "";
|
| - if (_subType == null) _subType = "";
|
| - _value = "$_primaryType/$_subType";
|
| - if (parameters != null) {
|
| - _ensureParameters();
|
| - parameters.forEach((String key, String value) {
|
| - String lowerCaseKey = key.toLowerCase();
|
| - if (lowerCaseKey == "charset") {
|
| - value = value.toLowerCase();
|
| - }
|
| - this._parameters[lowerCaseKey] = value;
|
| - });
|
| - }
|
| - if (charset != null) {
|
| - _ensureParameters();
|
| - this._parameters["charset"] = charset.toLowerCase();
|
| - }
|
| - }
|
| -
|
| - _ContentType._();
|
| -
|
| - static _ContentType parse(String value) {
|
| - var result = new _ContentType._();
|
| - result._parse(value, ";", null, false);
|
| - int index = result._value.indexOf("/");
|
| - if (index == -1 || index == (result._value.length - 1)) {
|
| - result._primaryType = result._value.trim().toLowerCase();
|
| - result._subType = "";
|
| - } else {
|
| - result._primaryType =
|
| - result._value.substring(0, index).trim().toLowerCase();
|
| - result._subType = result._value.substring(index + 1).trim().toLowerCase();
|
| - }
|
| - return result;
|
| - }
|
| -
|
| - String get mimeType => '$primaryType/$subType';
|
| -
|
| - String get primaryType => _primaryType;
|
| -
|
| - String get subType => _subType;
|
| -
|
| - String get charset => parameters["charset"];
|
| -}
|
| -
|
| -
|
| -class _Cookie implements Cookie {
|
| - String name;
|
| - String value;
|
| - DateTime expires;
|
| - int maxAge;
|
| - String domain;
|
| - String path;
|
| - bool httpOnly = false;
|
| - bool secure = false;
|
| -
|
| - _Cookie([this.name, this.value]) {
|
| - // Default value of httponly is true.
|
| - httpOnly = true;
|
| - _validate();
|
| - }
|
| -
|
| - _Cookie.fromSetCookieValue(String value) {
|
| - // Parse the 'set-cookie' header value.
|
| - _parseSetCookieValue(value);
|
| - }
|
| -
|
| - // Parse a 'set-cookie' header value according to the rules in RFC 6265.
|
| - void _parseSetCookieValue(String s) {
|
| - int index = 0;
|
| -
|
| - bool done() => index == s.length;
|
| -
|
| - String parseName() {
|
| - int start = index;
|
| - while (!done()) {
|
| - if (s[index] == "=") break;
|
| - index++;
|
| - }
|
| - return s.substring(start, index).trim();
|
| - }
|
| -
|
| - String parseValue() {
|
| - int start = index;
|
| - while (!done()) {
|
| - if (s[index] == ";") break;
|
| - index++;
|
| - }
|
| - return s.substring(start, index).trim();
|
| - }
|
| -
|
| - 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 parseAttributes() {
|
| - String parseAttributeName() {
|
| - int start = index;
|
| - while (!done()) {
|
| - if (s[index] == "=" || s[index] == ";") break;
|
| - index++;
|
| - }
|
| - return s.substring(start, index).trim().toLowerCase();
|
| - }
|
| -
|
| - String parseAttributeValue() {
|
| - int start = index;
|
| - while (!done()) {
|
| - if (s[index] == ";") break;
|
| - index++;
|
| - }
|
| - return s.substring(start, index).trim().toLowerCase();
|
| - }
|
| -
|
| - while (!done()) {
|
| - String name = parseAttributeName();
|
| - String value = "";
|
| - if (!done() && s[index] == "=") {
|
| - index++; // Skip the = character.
|
| - value = parseAttributeValue();
|
| - }
|
| - if (name == "expires") {
|
| - expires = HttpDate._parseCookieDate(value);
|
| - } else if (name == "max-age") {
|
| - maxAge = int.parse(value);
|
| - } else if (name == "domain") {
|
| - domain = value;
|
| - } else if (name == "path") {
|
| - path = value;
|
| - } else if (name == "httponly") {
|
| - httpOnly = true;
|
| - } else if (name == "secure") {
|
| - secure = true;
|
| - }
|
| - if (!done()) index++; // Skip the ; character
|
| - }
|
| - }
|
| -
|
| - name = parseName();
|
| - if (done() || name.length == 0) {
|
| - throw new HttpException("Failed to parse header value [$s]");
|
| - }
|
| - index++; // Skip the = character.
|
| - value = parseValue();
|
| - _validate();
|
| - if (done()) return;
|
| - index++; // Skip the ; character.
|
| - parseAttributes();
|
| - }
|
| -
|
| - String toString() {
|
| - StringBuffer sb = new StringBuffer();
|
| - sb..write(name)..write("=")..write(value);
|
| - if (expires != null) {
|
| - sb..write("; Expires=")..write(HttpDate.format(expires));
|
| - }
|
| - if (maxAge != null) {
|
| - sb..write("; Max-Age=")..write(maxAge);
|
| - }
|
| - if (domain != null) {
|
| - sb..write("; Domain=")..write(domain);
|
| - }
|
| - if (path != null) {
|
| - sb..write("; Path=")..write(path);
|
| - }
|
| - if (secure) sb.write("; Secure");
|
| - if (httpOnly) sb.write("; HttpOnly");
|
| - return sb.toString();
|
| - }
|
| -
|
| - void _validate() {
|
| - const SEPERATORS = const [
|
| - "(", ")", "<", ">", "@", ",", ";", ":", "\\",
|
| - '"', "/", "[", "]", "?", "=", "{", "}"];
|
| - for (int i = 0; i < name.length; i++) {
|
| - int codeUnit = name.codeUnits[i];
|
| - if (codeUnit <= 32 ||
|
| - codeUnit >= 127 ||
|
| - SEPERATORS.indexOf(name[i]) >= 0) {
|
| - throw new FormatException(
|
| - "Invalid character in cookie name, code unit: '$codeUnit'");
|
| - }
|
| - }
|
| - for (int i = 0; i < value.length; i++) {
|
| - int codeUnit = value.codeUnits[i];
|
| - if (!(codeUnit == 0x21 ||
|
| - (codeUnit >= 0x23 && codeUnit <= 0x2B) ||
|
| - (codeUnit >= 0x2D && codeUnit <= 0x3A) ||
|
| - (codeUnit >= 0x3C && codeUnit <= 0x5B) ||
|
| - (codeUnit >= 0x5D && codeUnit <= 0x7E))) {
|
| - throw new FormatException(
|
| - "Invalid character in cookie value, code unit: '$codeUnit'");
|
| - }
|
| - }
|
| - }
|
| -}
|
|
|