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'"); |
- } |
- } |
- } |
-} |