| OLD | NEW | 
|---|
| 1 // Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file | 
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a | 
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. | 
| 4 | 4 | 
| 5 library shelf.message; | 5 library shelf.message; | 
| 6 | 6 | 
| 7 import 'dart:async'; | 7 import 'dart:async'; | 
| 8 import 'dart:convert'; | 8 import 'dart:convert'; | 
| 9 | 9 | 
| 10 import 'package:http_parser/http_parser.dart'; | 10 import 'package:http_parser/http_parser.dart'; | 
| 11 import 'package:stack_trace/stack_trace.dart'; | 11 import 'package:stack_trace/stack_trace.dart'; | 
| 12 | 12 | 
| 13 import 'shelf_unmodifiable_map.dart'; | 13 import 'shelf_unmodifiable_map.dart'; | 
|  | 14 import 'util.dart'; | 
| 14 | 15 | 
| 15 /// Represents logic shared between [Request] and [Response]. | 16 /// Represents logic shared between [Request] and [Response]. | 
| 16 abstract class Message { | 17 abstract class Message { | 
| 17   /// The HTTP headers. | 18   /// The HTTP headers. | 
| 18   /// | 19   /// | 
| 19   /// The value is immutable. | 20   /// The value is immutable. | 
| 20   final Map<String, String> headers; | 21   final Map<String, String> headers; | 
| 21 | 22 | 
| 22   /// Extra context that can be used by for middleware and handlers. | 23   /// Extra context that can be used by for middleware and handlers. | 
| 23   /// | 24   /// | 
| (...skipping 14 matching lines...) Expand all  Loading... | 
| 38   final Stream<List<int>> _body; | 39   final Stream<List<int>> _body; | 
| 39 | 40 | 
| 40   /// This boolean indicates whether [_body] has been read. | 41   /// This boolean indicates whether [_body] has been read. | 
| 41   /// | 42   /// | 
| 42   /// After calling [read], or [readAsString] (which internally calls [read]), | 43   /// After calling [read], or [readAsString] (which internally calls [read]), | 
| 43   /// this will be `true`. | 44   /// this will be `true`. | 
| 44   bool _bodyWasRead = false; | 45   bool _bodyWasRead = false; | 
| 45 | 46 | 
| 46   /// Creates a new [Message]. | 47   /// Creates a new [Message]. | 
| 47   /// | 48   /// | 
|  | 49   /// [body] is the response body. It may be either a [String], a | 
|  | 50   /// [Stream<List<int>>], or `null` to indicate no body. If it's a [String], | 
|  | 51   /// [encoding] is used to encode it to a [Stream<List<int>>]. It defaults to | 
|  | 52   /// UTF-8. | 
|  | 53   /// | 
| 48   /// If [headers] is `null`, it is treated as empty. | 54   /// If [headers] is `null`, it is treated as empty. | 
| 49   Message(this._body, | 55   /// | 
| 50       {Map<String, String> headers, Map<String, Object> context}) | 56   /// If [encoding] is passed, the "encoding" field of the Content-Type header | 
| 51       : this.headers = new ShelfUnmodifiableMap<String>(headers, | 57   /// in [headers] will be set appropriately. If there is no existing | 
| 52           ignoreKeyCase: true), | 58   /// Content-Type header, it will be set to "application/octet-stream". | 
|  | 59   Message(body, {Encoding encoding, Map<String, String> headers, | 
|  | 60       Map<String, Object> context}) | 
|  | 61       : this._body = _bodyToStream(body, encoding), | 
|  | 62         this.headers = new ShelfUnmodifiableMap<String>( | 
|  | 63             _adjustHeaders(headers, encoding), ignoreKeyCase: true), | 
| 53         this.context = new ShelfUnmodifiableMap<Object>(context, | 64         this.context = new ShelfUnmodifiableMap<Object>(context, | 
| 54             ignoreKeyCase: false); | 65             ignoreKeyCase: false); | 
| 55 | 66 | 
| 56   /// The contents of the content-length field in [headers]. | 67   /// The contents of the content-length field in [headers]. | 
| 57   /// | 68   /// | 
| 58   /// If not set, `null`. | 69   /// If not set, `null`. | 
| 59   int get contentLength { | 70   int get contentLength { | 
| 60     if (_contentLengthCache != null) return _contentLengthCache; | 71     if (_contentLengthCache != null) return _contentLengthCache; | 
| 61     if (!headers.containsKey('content-length')) return null; | 72     if (!headers.containsKey('content-length')) return null; | 
| 62     _contentLengthCache = int.parse(headers['content-length']); | 73     _contentLengthCache = int.parse(headers['content-length']); | 
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 123   Future<String> readAsString([Encoding encoding]) { | 134   Future<String> readAsString([Encoding encoding]) { | 
| 124     if (encoding == null) encoding = this.encoding; | 135     if (encoding == null) encoding = this.encoding; | 
| 125     if (encoding == null) encoding = UTF8; | 136     if (encoding == null) encoding = UTF8; | 
| 126     return Chain.track(encoding.decodeStream(read())); | 137     return Chain.track(encoding.decodeStream(read())); | 
| 127   } | 138   } | 
| 128 | 139 | 
| 129   /// Creates a new [Message] by copying existing values and applying specified | 140   /// Creates a new [Message] by copying existing values and applying specified | 
| 130   /// changes. | 141   /// changes. | 
| 131   Message change({Map<String, String> headers, Map<String, Object> context}); | 142   Message change({Map<String, String> headers, Map<String, Object> context}); | 
| 132 } | 143 } | 
|  | 144 | 
|  | 145 /// Converts [body] to a byte stream. | 
|  | 146 /// | 
|  | 147 /// [body] may be either a [String], a [Stream<List<int>>], or `null`. If it's a | 
|  | 148 /// [String], [encoding] will be used to convert it to a [Stream<List<int>>]. | 
|  | 149 Stream<List<int>> _bodyToStream(body, Encoding encoding) { | 
|  | 150   if (encoding == null) encoding = UTF8; | 
|  | 151   if (body == null) return new Stream.fromIterable([]); | 
|  | 152   if (body is String) return new Stream.fromIterable([encoding.encode(body)]); | 
|  | 153   if (body is Stream) return body; | 
|  | 154 | 
|  | 155   throw new ArgumentError('Response body "$body" must be a String or a ' | 
|  | 156       'Stream.'); | 
|  | 157 } | 
|  | 158 | 
|  | 159 /// Adds information about [encoding] to [headers]. | 
|  | 160 /// | 
|  | 161 /// Returns a new map without modifying [headers]. | 
|  | 162 Map<String, String> _adjustHeaders( | 
|  | 163     Map<String, String> headers, Encoding encoding) { | 
|  | 164   if (headers == null) headers = const {}; | 
|  | 165   if (encoding == null) return headers; | 
|  | 166   if (headers['content-type'] == null) { | 
|  | 167     return addHeader(headers, 'content-type', | 
|  | 168         'application/octet-stream; charset=${encoding.name}'); | 
|  | 169   } | 
|  | 170 | 
|  | 171   var contentType = new MediaType.parse(headers['content-type']).change( | 
|  | 172       parameters: {'charset': encoding.name}); | 
|  | 173   return addHeader(headers, 'content-type', contentType.toString()); | 
|  | 174 } | 
| OLD | NEW | 
|---|