| 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:http_parser/http_parser.dart'; | 10 import 'package:http_parser/http_parser.dart'; |
| 11 | 11 |
| 12 import 'message.dart'; | 12 import 'message.dart'; |
| 13 import 'util.dart'; |
| 13 | 14 |
| 14 /// The response returned by a [Handler]. | 15 /// The response returned by a [Handler]. |
| 15 class Response extends Message { | 16 class Response extends Message { |
| 16 /// The HTTP status code of the response. | 17 /// The HTTP status code of the response. |
| 17 final int statusCode; | 18 final int statusCode; |
| 18 | 19 |
| 19 /// The date and time after which the response's data should be considered | 20 /// The date and time after which the response's data should be considered |
| 20 /// stale. | 21 /// stale. |
| 21 /// | 22 /// |
| 22 /// This is parsed from the Expires header in [headers]. If [headers] doesn't | 23 /// This is parsed from the Expires header in [headers]. If [headers] doesn't |
| (...skipping 23 matching lines...) Expand all Loading... |
| 46 /// This indicates that the request has succeeded. | 47 /// This indicates that the request has succeeded. |
| 47 /// | 48 /// |
| 48 /// [body] is the response body. It may be either a [String], a | 49 /// [body] is the response body. It may be either a [String], a |
| 49 /// [Stream<List<int>>], or `null` to indicate no body. If it's a [String], | 50 /// [Stream<List<int>>], or `null` to indicate no body. If it's a [String], |
| 50 /// [encoding] is used to encode it to a [Stream<List<int>>]. It defaults to | 51 /// [encoding] is used to encode it to a [Stream<List<int>>]. It defaults to |
| 51 /// UTF-8. | 52 /// UTF-8. |
| 52 /// | 53 /// |
| 53 /// If [encoding] is passed, the "encoding" field of the Content-Type header | 54 /// If [encoding] is passed, the "encoding" field of the Content-Type header |
| 54 /// in [headers] will be set appropriately. If there is no existing | 55 /// in [headers] will be set appropriately. If there is no existing |
| 55 /// Content-Type header, it will be set to "application/octet-stream". | 56 /// Content-Type header, it will be set to "application/octet-stream". |
| 56 Response.ok(body, {Map<String, String> headers, Encoding encoding, | 57 Response.ok(body, {Map<String, String> headers, Encoding encoding, |
| 57 Map<String, Object> context}) | 58 Map<String, Object> context}) |
| 58 : this(200, body: body, headers: headers, encoding: encoding, | 59 : this(200, body: body, headers: headers, encoding: encoding, |
| 59 context: context); | 60 context: context); |
| 60 | 61 |
| 61 /// Constructs a 301 Moved Permanently response. | 62 /// Constructs a 301 Moved Permanently response. |
| 62 /// | 63 /// |
| 63 /// This indicates that the requested resource has moved permanently to a new | 64 /// This indicates that the requested resource has moved permanently to a new |
| 64 /// URI. [location] is that URI; it can be either a [String] or a [Uri]. It's | 65 /// URI. [location] is that URI; it can be either a [String] or a [Uri]. It's |
| 65 /// automatically set as the Location header in [headers]. | 66 /// automatically set as the Location header in [headers]. |
| 66 /// | 67 /// |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 111 /// If [encoding] is passed, the "encoding" field of the Content-Type header | 112 /// If [encoding] is passed, the "encoding" field of the Content-Type header |
| 112 /// in [headers] will be set appropriately. If there is no existing | 113 /// in [headers] will be set appropriately. If there is no existing |
| 113 /// Content-Type header, it will be set to "application/octet-stream". | 114 /// Content-Type header, it will be set to "application/octet-stream". |
| 114 Response.seeOther(location, {body, Map<String, String> headers, | 115 Response.seeOther(location, {body, Map<String, String> headers, |
| 115 Encoding encoding, Map<String, Object> context}) | 116 Encoding encoding, Map<String, Object> context}) |
| 116 : this._redirect(303, location, body, headers, encoding, | 117 : this._redirect(303, location, body, headers, encoding, |
| 117 context: context); | 118 context: context); |
| 118 | 119 |
| 119 /// Constructs a helper constructor for redirect responses. | 120 /// Constructs a helper constructor for redirect responses. |
| 120 Response._redirect(int statusCode, location, body, | 121 Response._redirect(int statusCode, location, body, |
| 121 Map<String, String> headers, Encoding encoding, | 122 Map<String, String> headers, Encoding encoding, |
| 122 { Map<String, Object> context }) | 123 { Map<String, Object> context }) |
| 123 : this(statusCode, | 124 : this(statusCode, |
| 124 body: body, | 125 body: body, |
| 125 encoding: encoding, | 126 encoding: encoding, |
| 126 headers: _addHeader( | 127 headers: _addHeader( |
| 127 headers, 'location', _locationToString(location)), | 128 headers, 'location', _locationToString(location)), |
| 128 context: context); | 129 context: context); |
| 129 | 130 |
| 130 /// Constructs a 304 Not Modified response. | 131 /// Constructs a 304 Not Modified response. |
| 131 /// | 132 /// |
| 132 /// This is used to respond to a conditional GET request that provided | 133 /// This is used to respond to a conditional GET request that provided |
| 133 /// information used to determine whether the requested resource has changed | 134 /// information used to determine whether the requested resource has changed |
| 134 /// since the last request. It indicates that the resource has not changed and | 135 /// since the last request. It indicates that the resource has not changed and |
| 135 /// the old value should be used. | 136 /// the old value should be used. |
| 136 Response.notModified({Map<String, String> headers, | 137 Response.notModified({Map<String, String> headers, |
| 137 Map<String, Object> context}) | 138 Map<String, Object> context}) |
| 138 : this(304, headers: _addHeader( | 139 : this(304, headers: _addHeader( |
| 139 headers, 'date', formatHttpDate(new DateTime.now())), | 140 headers, 'date', formatHttpDate(new DateTime.now())), |
| 140 context: context); | 141 context: context); |
| 141 | 142 |
| 142 /// Constructs a 403 Forbidden response. | 143 /// Constructs a 403 Forbidden response. |
| 143 /// | 144 /// |
| 144 /// This indicates that the server is refusing to fulfill the request. | 145 /// This indicates that the server is refusing to fulfill the request. |
| 145 /// | 146 /// |
| 146 /// [body] is the response body. It may be either a [String], a | 147 /// [body] is the response body. It may be either a [String], a |
| (...skipping 15 matching lines...) Expand all Loading... |
| 162 /// requested URI. | 163 /// requested URI. |
| 163 /// | 164 /// |
| 164 /// [body] is the response body. It may be either a [String], a | 165 /// [body] is the response body. It may be either a [String], a |
| 165 /// [Stream<List<int>>], or `null` to indicate no body. If it's a [String], | 166 /// [Stream<List<int>>], or `null` to indicate no body. If it's a [String], |
| 166 /// [encoding] is used to encode it to a [Stream<List<int>>]. It defaults to | 167 /// [encoding] is used to encode it to a [Stream<List<int>>]. It defaults to |
| 167 /// UTF-8. | 168 /// UTF-8. |
| 168 /// | 169 /// |
| 169 /// If [encoding] is passed, the "encoding" field of the Content-Type header | 170 /// If [encoding] is passed, the "encoding" field of the Content-Type header |
| 170 /// in [headers] will be set appropriately. If there is no existing | 171 /// in [headers] will be set appropriately. If there is no existing |
| 171 /// Content-Type header, it will be set to "application/octet-stream". | 172 /// Content-Type header, it will be set to "application/octet-stream". |
| 172 Response.notFound(body, {Map<String, String> headers, Encoding encoding, | 173 Response.notFound(body, {Map<String, String> headers, Encoding encoding, |
| 173 Map<String, Object> context}) | 174 Map<String, Object> context}) |
| 174 : this(404, body: body, headers: headers, | 175 : this(404, body: body, headers: headers, |
| 175 context: context); | 176 context: context); |
| 176 | 177 |
| 177 /// Constructs a 500 Internal Server Error response. | 178 /// Constructs a 500 Internal Server Error response. |
| 178 /// | 179 /// |
| 179 /// This indicates that the server had an internal error that prevented it | 180 /// This indicates that the server had an internal error that prevented it |
| 180 /// from fulfilling the request. | 181 /// from fulfilling the request. |
| 181 /// | 182 /// |
| 182 /// [body] is the response body. It may be either a [String], a | 183 /// [body] is the response body. It may be either a [String], a |
| (...skipping 25 matching lines...) Expand all Loading... |
| 208 /// Content-Type header, it will be set to "application/octet-stream". | 209 /// Content-Type header, it will be set to "application/octet-stream". |
| 209 Response(this.statusCode, {body, Map<String, String> headers, | 210 Response(this.statusCode, {body, Map<String, String> headers, |
| 210 Encoding encoding, Map<String, Object> context}) | 211 Encoding encoding, Map<String, Object> context}) |
| 211 : super(_bodyToStream(body, encoding), | 212 : super(_bodyToStream(body, encoding), |
| 212 headers: _adjustHeaders(headers, encoding), | 213 headers: _adjustHeaders(headers, encoding), |
| 213 context: context) { | 214 context: context) { |
| 214 if (statusCode < 100) { | 215 if (statusCode < 100) { |
| 215 throw new ArgumentError("Invalid status code: $statusCode."); | 216 throw new ArgumentError("Invalid status code: $statusCode."); |
| 216 } | 217 } |
| 217 } | 218 } |
| 219 |
| 220 /// Creates a new [Response] by copying existing values and applying specified |
| 221 /// changes. |
| 222 /// |
| 223 /// New key-value pairs in [context] and [headers] will be added to the copied |
| 224 /// [Response]. |
| 225 /// |
| 226 /// If [context] or [headers] includes a key that already exists, the |
| 227 /// key-value pair will replace the corresponding entry in the copied |
| 228 /// [Response]. |
| 229 /// |
| 230 /// All other context and header values from the [Response] will be included |
| 231 /// in the copied [Response] unchanged. |
| 232 Response change({Map<String, String> headers, Map<String, Object> context}) { |
| 233 headers = updateMap(this.headers, headers); |
| 234 context = updateMap(this.context, context); |
| 235 |
| 236 return new Response(this.statusCode, body: this.read(), headers: headers, |
| 237 context: context); |
| 238 } |
| 218 } | 239 } |
| 219 | 240 |
| 220 /// Converts [body] to a byte stream. | 241 /// Converts [body] to a byte stream. |
| 221 /// | 242 /// |
| 222 /// [body] may be either a [String], a [Stream<List<int>>], or `null`. If it's a | 243 /// [body] may be either a [String], a [Stream<List<int>>], or `null`. If it's a |
| 223 /// [String], [encoding] will be used to convert it to a [Stream<List<int>>]. | 244 /// [String], [encoding] will be used to convert it to a [Stream<List<int>>]. |
| 224 Stream<List<int>> _bodyToStream(body, Encoding encoding) { | 245 Stream<List<int>> _bodyToStream(body, Encoding encoding) { |
| 225 if (encoding == null) encoding = UTF8; | 246 if (encoding == null) encoding = UTF8; |
| 226 if (body == null) return new Stream.fromIterable([]); | 247 if (body == null) return new Stream.fromIterable([]); |
| 227 if (body is String) return new Stream.fromIterable([encoding.encode(body)]); | 248 if (body is String) return new Stream.fromIterable([encoding.encode(body)]); |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 275 /// Converts [location], which may be a [String] or a [Uri], to a [String]. | 296 /// Converts [location], which may be a [String] or a [Uri], to a [String]. |
| 276 /// | 297 /// |
| 277 /// Throws an [ArgumentError] if [location] isn't a [String] or a [Uri]. | 298 /// Throws an [ArgumentError] if [location] isn't a [String] or a [Uri]. |
| 278 String _locationToString(location) { | 299 String _locationToString(location) { |
| 279 if (location is String) return location; | 300 if (location is String) return location; |
| 280 if (location is Uri) return location.toString(); | 301 if (location is Uri) return location.toString(); |
| 281 | 302 |
| 282 throw new ArgumentError('Response location must be a String or Uri, was ' | 303 throw new ArgumentError('Response location must be a String or Uri, was ' |
| 283 '"$location".'); | 304 '"$location".'); |
| 284 } | 305 } |
| OLD | NEW |