| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 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. |
| 4 |
| 5 library request; |
| 6 |
| 7 import 'dart:io'; |
| 8 import 'dart:scalarlist'; |
| 9 import 'dart:uri'; |
| 10 |
| 11 import 'base_request.dart'; |
| 12 import 'utils.dart'; |
| 13 |
| 14 /// An HTTP request where the entire request body is known in advance. |
| 15 class Request extends BaseRequest { |
| 16 /// The size of the request body, in bytes. This is calculated from |
| 17 /// [bodyBytes]. |
| 18 /// |
| 19 /// The content length cannot be set for [Request], since it's automatically |
| 20 /// calculated from [bodyBytes]. |
| 21 int get contentLength => bodyBytes.length; |
| 22 |
| 23 set contentLength(int value) { |
| 24 throw new UnsupportedError("Cannot set the contentLength property of " |
| 25 "non-streaming Request objects."); |
| 26 } |
| 27 |
| 28 /// The default encoding to use when converting between [bodyBytes] and |
| 29 /// [body]. This is only used if [encoding] hasn't been manually set and if |
| 30 /// the content-type header has no encoding information. |
| 31 Encoding _defaultEncoding; |
| 32 |
| 33 /// The encoding used for the request. This encoding is used when converting |
| 34 /// between [bodyBytes] and [body]. |
| 35 /// |
| 36 /// If the request has a `Content-Type` header and that header has a `charset` |
| 37 /// parameter, that parameter's value is used as the encoding. Otherwise, if |
| 38 /// [encoding] has been set manually, that encoding is used. If that hasn't |
| 39 /// been set either, this defaults to [Encoding.UTF_8]. |
| 40 /// |
| 41 /// If the `charset` parameter's value is not a known [Encoding], reading this |
| 42 /// will throw a [FormatException]. |
| 43 /// |
| 44 /// If the request has a `Content-Type` header, setting this will set the |
| 45 /// charset parameter on that header. |
| 46 Encoding get encoding { |
| 47 if (_contentType == null || _contentType.charset == null) { |
| 48 return _defaultEncoding; |
| 49 } |
| 50 return requiredEncodingForCharset(_contentType.charset); |
| 51 } |
| 52 |
| 53 set encoding(Encoding value) { |
| 54 _checkFinalized(); |
| 55 _defaultEncoding = value; |
| 56 var contentType = _contentType; |
| 57 if (contentType != null) { |
| 58 contentType.charset = value.name; |
| 59 _contentType = contentType; |
| 60 } |
| 61 } |
| 62 |
| 63 // TODO(nweiz): make this return a read-only view |
| 64 /// The bytes comprising the body of the request. This is converted to and |
| 65 /// from [body] using [encoding]. |
| 66 /// |
| 67 /// This list should only be set, not be modified in place. |
| 68 Uint8List get bodyBytes => _bodyBytes; |
| 69 Uint8List _bodyBytes; |
| 70 |
| 71 set bodyBytes(List<int> value) { |
| 72 _checkFinalized(); |
| 73 _bodyBytes = toUint8List(value); |
| 74 } |
| 75 |
| 76 /// The body of the request as a string. This is converted to and from |
| 77 /// [bodyBytes] using [encoding]. |
| 78 /// |
| 79 /// When this is set, if the request does not yet have a `Content-Type` |
| 80 /// header, one will be added with the type `text/plain`. Then the `charset` |
| 81 /// parameter of the `Content-Type` header (whether new or pre-existing) will |
| 82 /// be set to [encoding] if it wasn't already set. |
| 83 String get body => decodeString(bodyBytes, encoding); |
| 84 |
| 85 set body(String value) { |
| 86 bodyBytes = encodeString(value, encoding); |
| 87 var contentType = _contentType; |
| 88 if (contentType == null) contentType = new ContentType("text", "plain"); |
| 89 if (contentType.charset == null) contentType.charset = encoding.name; |
| 90 _contentType = contentType; |
| 91 } |
| 92 |
| 93 /// The form-encoded fields in the body of the request as a map from field |
| 94 /// names to values. The form-encoded body is converted to and from |
| 95 /// [bodyBytes] using [encoding] (in the same way as [body]). |
| 96 /// |
| 97 /// If the request doesn't have a `Content-Type` header of |
| 98 /// `application/x-www-form-urlencoded`, reading this will throw a |
| 99 /// [StateError]. |
| 100 /// |
| 101 /// If the request has a `Content-Type` header with a type other than |
| 102 /// `application/x-www-form-urlencoded`, setting this will throw a |
| 103 /// [StateError]. Otherwise, the content type will be set to |
| 104 /// `application/x-www-form-urlencoded`. |
| 105 /// |
| 106 /// This map should only be set, not modified in place. |
| 107 Map<String, String> get bodyFields { |
| 108 if (_contentType == null || |
| 109 _contentType.value != "application/x-www-form-urlencoded") { |
| 110 throw new StateError('Cannot access the body fields of a Request without ' |
| 111 'content-type "application/x-www-form-urlencoded".'); |
| 112 } |
| 113 |
| 114 return queryToMap(body); |
| 115 } |
| 116 |
| 117 set bodyFields(Map<String, String> fields) { |
| 118 if (_contentType == null) { |
| 119 _contentType = new ContentType("application", "x-www-form-urlencoded"); |
| 120 } else if (_contentType.value != "application/x-www-form-urlencoded") { |
| 121 throw new StateError('Cannot set the body fields of a Request with ' |
| 122 'content-type "${_contentType.value}".'); |
| 123 } |
| 124 |
| 125 this.body = mapToQuery(fields); |
| 126 } |
| 127 |
| 128 /// Creates a new HTTP request. |
| 129 Request(String method, Uri url) |
| 130 : super(method, url), |
| 131 _defaultEncoding = Encoding.UTF_8, |
| 132 _bodyBytes = new Uint8List(0); |
| 133 |
| 134 /// Freeze all mutable fields and return an [InputStream] containing the |
| 135 /// request body. |
| 136 InputStream finalize() { |
| 137 super.finalize(); |
| 138 |
| 139 var stream = new ListInputStream(); |
| 140 stream.write(bodyBytes); |
| 141 stream.markEndOfStream(); |
| 142 return stream; |
| 143 } |
| 144 |
| 145 /// The `Content-Type` header of the request (if it exists) as a |
| 146 /// [ContentType]. |
| 147 ContentType get _contentType { |
| 148 var contentType = headers[HttpHeaders.CONTENT_TYPE]; |
| 149 if (contentType == null) return null; |
| 150 return new ContentType.fromString(contentType); |
| 151 } |
| 152 |
| 153 set _contentType(ContentType value) { |
| 154 headers[HttpHeaders.CONTENT_TYPE] = value.toString(); |
| 155 } |
| 156 |
| 157 /// Throw an error if this request has been finalized. |
| 158 void _checkFinalized() { |
| 159 if (!finalized) return; |
| 160 throw new StateError("Can't modify a finalized Request."); |
| 161 } |
| 162 } |
| OLD | NEW |