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