| 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.response; | 5 library shelf.response; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:convert'; | 8 import 'dart:convert'; |
| 9 | 9 |
| 10 import 'package:collection/wrappers.dart'; | |
| 11 import 'package:http_parser/http_parser.dart'; | 10 import 'package:http_parser/http_parser.dart'; |
| 12 | 11 |
| 13 import 'message.dart'; | 12 import 'message.dart'; |
| 14 | 13 |
| 15 /// The response returned by a [Handler]. | 14 /// The response returned by a [Handler]. |
| 16 class Response extends Message { | 15 class Response extends Message { |
| 17 /// The HTTP status code of the response. | 16 /// The HTTP status code of the response. |
| 18 final int statusCode; | 17 final int statusCode; |
| 19 | 18 |
| 20 /// The date and time after which the response's data should be considered | 19 /// The date and time after which the response's data should be considered |
| (...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 189 /// [body] is the response body. It may be either a [String], a | 188 /// [body] is the response body. It may be either a [String], a |
| 190 /// [Stream<List<int>>], or `null` to indicate no body. If it's `null` or not | 189 /// [Stream<List<int>>], or `null` to indicate no body. If it's `null` or not |
| 191 /// passed, a default error message is used. If it's a [String], [encoding] is | 190 /// passed, a default error message is used. If it's a [String], [encoding] is |
| 192 /// used to encode it to a [Stream<List<int>>]. It defaults to UTF-8. | 191 /// used to encode it to a [Stream<List<int>>]. It defaults to UTF-8. |
| 193 /// | 192 /// |
| 194 /// If [encoding] is passed, the "encoding" field of the Content-Type header | 193 /// If [encoding] is passed, the "encoding" field of the Content-Type header |
| 195 /// in [headers] will be set appropriately. If there is no existing | 194 /// in [headers] will be set appropriately. If there is no existing |
| 196 /// Content-Type header, it will be set to "application/octet-stream". | 195 /// Content-Type header, it will be set to "application/octet-stream". |
| 197 Response(this.statusCode, {body, Map<String, String> headers, | 196 Response(this.statusCode, {body, Map<String, String> headers, |
| 198 Encoding encoding}) | 197 Encoding encoding}) |
| 199 : super(_adjustHeaders(headers, encoding), | 198 : super(_bodyToStream(body, encoding), |
| 200 _bodyToStream(body, encoding)) { | 199 headers: _adjustHeaders(headers, encoding)) { |
| 201 if (statusCode < 100) { | 200 if (statusCode < 100) { |
| 202 throw new ArgumentError("Invalid status code: $statusCode."); | 201 throw new ArgumentError("Invalid status code: $statusCode."); |
| 203 } | 202 } |
| 204 } | 203 } |
| 205 } | 204 } |
| 206 | 205 |
| 207 /// Converts [body] to a byte stream. | 206 /// Converts [body] to a byte stream. |
| 208 /// | 207 /// |
| 209 /// [body] may be either a [String], a [Stream<List<int>>], or `null`. If it's a | 208 /// [body] may be either a [String], a [Stream<List<int>>], or `null`. If it's a |
| 210 /// [String], [encoding] will be used to convert it to a [Stream<List<int>>]. | 209 /// [String], [encoding] will be used to convert it to a [Stream<List<int>>]. |
| 211 Stream<List<int>> _bodyToStream(body, Encoding encoding) { | 210 Stream<List<int>> _bodyToStream(body, Encoding encoding) { |
| 212 if (encoding == null) encoding = UTF8; | 211 if (encoding == null) encoding = UTF8; |
| 213 if (body == null) return new Stream.fromIterable([]); | 212 if (body == null) return new Stream.fromIterable([]); |
| 214 if (body is String) return new Stream.fromIterable([encoding.encode(body)]); | 213 if (body is String) return new Stream.fromIterable([encoding.encode(body)]); |
| 215 if (body is Stream) return body; | 214 if (body is Stream) return body; |
| 216 | 215 |
| 217 throw new ArgumentError('Response body "$body" must be a String or a ' | 216 throw new ArgumentError('Response body "$body" must be a String or a ' |
| 218 'Stream.'); | 217 'Stream.'); |
| 219 } | 218 } |
| 220 | 219 |
| 221 /// Adds information about [encoding] to [headers]. | 220 /// Adds information about [encoding] to [headers]. |
| 222 /// | 221 /// |
| 223 /// Returns a new map without modifying [headers]. | 222 /// Returns a new map without modifying [headers]. |
| 224 UnmodifiableMapView<String, String> _adjustHeaders( | 223 Map<String, String> _adjustHeaders( |
| 225 Map<String, String> headers, Encoding encoding) { | 224 Map<String, String> headers, Encoding encoding) { |
| 226 if (headers == null) headers = const {}; | 225 if (headers == null) headers = const {}; |
| 227 if (encoding == null) return new UnmodifiableMapView(headers); | 226 if (encoding == null) return headers; |
| 228 if (headers['content-type'] == null) { | 227 if (headers['content-type'] == null) { |
| 229 return new UnmodifiableMapView(_addHeader(headers, 'content-type', | 228 return _addHeader(headers, 'content-type', |
| 230 'application/octet-stream; charset=${encoding.name}')); | 229 'application/octet-stream; charset=${encoding.name}'); |
| 231 } | 230 } |
| 232 | 231 |
| 233 var contentType = new MediaType.parse(headers['content-type']) | 232 var contentType = new MediaType.parse(headers['content-type']) |
| 234 .change(parameters: {'charset': encoding.name}); | 233 .change(parameters: {'charset': encoding.name}); |
| 235 return new UnmodifiableMapView( | 234 return _addHeader(headers, 'content-type', contentType.toString()); |
| 236 _addHeader(headers, 'content-type', contentType.toString())); | |
| 237 } | 235 } |
| 238 | 236 |
| 239 /// Adds a header with [name] and [value] to [headers], which may be null. | 237 /// Adds a header with [name] and [value] to [headers], which may be null. |
| 240 /// | 238 /// |
| 241 /// Returns a new map without modifying [headers]. | 239 /// Returns a new map without modifying [headers]. |
| 242 Map<String, String> _addHeader(Map<String, String> headers, String name, | 240 Map<String, String> _addHeader(Map<String, String> headers, String name, |
| 243 String value) { | 241 String value) { |
| 244 headers = headers == null ? {} : new Map.from(headers); | 242 headers = headers == null ? {} : new Map.from(headers); |
| 245 headers[name] = value; | 243 headers[name] = value; |
| 246 return headers; | 244 return headers; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 263 /// Converts [location], which may be a [String] or a [Uri], to a [String]. | 261 /// Converts [location], which may be a [String] or a [Uri], to a [String]. |
| 264 /// | 262 /// |
| 265 /// Throws an [ArgumentError] if [location] isn't a [String] or a [Uri]. | 263 /// Throws an [ArgumentError] if [location] isn't a [String] or a [Uri]. |
| 266 String _locationToString(location) { | 264 String _locationToString(location) { |
| 267 if (location is String) return location; | 265 if (location is String) return location; |
| 268 if (location is Uri) return location.toString(); | 266 if (location is Uri) return location.toString(); |
| 269 | 267 |
| 270 throw new ArgumentError('Response location must be a String or Uri, was ' | 268 throw new ArgumentError('Response location must be a String or Uri, was ' |
| 271 '"$location".'); | 269 '"$location".'); |
| 272 } | 270 } |
| OLD | NEW |