Chromium Code Reviews| Index: pkg/http/lib/src/request.dart |
| diff --git a/pkg/http/lib/src/request.dart b/pkg/http/lib/src/request.dart |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..129c2fc90d696f0f85de0f39dc7cf3cd4ca9dfe8 |
| --- /dev/null |
| +++ b/pkg/http/lib/src/request.dart |
| @@ -0,0 +1,162 @@ |
| +// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| +// for details. All rights reserved. Use of this source code is governed by a |
| +// BSD-style license that can be found in the LICENSE file. |
| + |
| +library request; |
| + |
| +import 'dart:io'; |
| +import 'dart:scalarlist'; |
| +import 'dart:uri'; |
| + |
| +import 'base_request.dart'; |
| +import 'utils.dart'; |
| + |
| +/// An HTTP request where the entire request body is known in advance. |
| +class Request extends BaseRequest { |
| + /// The size of the request body, in bytes. This is calculated from |
| + /// [bodyBytes]. |
| + /// |
| + /// The content length cannot be set for [Request], since it's automatically |
| + /// calculated from [bodyBytes]. |
| + int get contentLength => bodyBytes.length; |
| + |
| + set contentLength(int value) { |
| + throw new UnsupportedError("Cannot set the contentLength property of " |
| + "non-streaming Request objects."); |
| + } |
| + |
| + /// The default encoding to use when converting between [bodyBytes] and |
| + /// [body]. This is only used if [encoding] hasn't been manually set and if |
| + /// the content-type header has no encoding information. |
| + Encoding _defaultEncoding; |
| + |
| + /// The encoding used for the request. This encoding is used when converting |
| + /// between [bodyBytes] and [body]. |
| + /// |
| + /// If the request has a `Content-Type` header and that header has a `charset` |
| + /// parameter, that parameter's value is used as the encoding. Otherwise, if |
| + /// [encoding] has been set manually, that encoding is used. If that hasn't |
| + /// been set either, this defaults to [Encoding.UTF_8]. |
| + /// |
| + /// If the `charset` parameter's value is not a known [Encoding], reading this |
| + /// will throw an [ArgumentError]. |
|
Bob Nystrom
2012/11/01 19:53:59
ArgumentError is wrong here since getters don't ha
nweiz
2012/11/02 19:29:12
Changed to FormatError.
|
| + /// |
| + /// If the request has a `Content-Type` header, setting this will set the |
| + /// charset parameter on that header. |
| + Encoding get encoding { |
| + if (_contentType == null || _contentType.charset == null) { |
| + return _defaultEncoding; |
| + } |
| + return requiredEncodingForCharset(_contentType.charset); |
| + } |
| + |
| + set encoding(Encoding value) { |
| + _checkFinalized(); |
| + _defaultEncoding = value; |
| + var contentType = _contentType; |
| + if (contentType != null) { |
| + contentType.charset = value.name; |
| + _contentType = contentType; |
| + } |
| + } |
| + |
| + // TODO(nweiz): make this return a read-only view |
| + /// The bytes comprising the body of the request. This is converted to and |
| + /// from [body] using [encoding]. |
| + /// |
| + /// This list should only be set, not be modified in place. |
| + Uint8List get bodyBytes => _bodyBytes; |
| + Uint8List _bodyBytes; |
| + |
| + set bodyBytes(List<int> value) { |
| + _checkFinalized(); |
| + _bodyBytes = toUint8List(value); |
| + } |
| + |
| + /// The body of the request as a string. This is converted to and from |
| + /// [bodyBytes] using [encoding]. |
| + /// |
| + /// When this is set, if the request does not yet have a `Content-Type` |
| + /// header, one will be added with the type `text/plain`. Then the `charset` |
| + /// parameter of the `Content-Type` header (whether new or pre-existing) will |
| + /// be set to [encoding] if it wasn't already set. |
| + String get body => decodeString(bodyBytes, encoding); |
| + |
| + set body(String value) { |
| + bodyBytes = encodeString(value, encoding); |
| + var contentType = _contentType; |
| + if (contentType == null) contentType = new ContentType("text", "plain"); |
| + if (contentType.charset == null) contentType.charset = encoding.name; |
| + _contentType = contentType; |
| + } |
| + |
| + /// The form-encoded fields in the body of the request as a map from field |
| + /// names to values. The form-encoded body is converted to and from |
| + /// [bodyBytes] using [encoding] (in the same way as [body]). |
| + /// |
| + /// If the request doesn't have a `Content-Type` header of |
| + /// `application/x-www-form-urlencoded`, reading this will throw a |
| + /// [StateError]. |
| + /// |
| + /// If the request has a `Content-Type` header with a type other than |
| + /// `application/x-www-form-urlencoded`, setting this will throw a |
| + /// [StateError]. Otherwise, the content type will be set to |
| + /// `application/x-www-form-urlencoded`. |
| + /// |
| + /// This map should only be set, not modified in place. |
| + Map<String, String> get bodyFields { |
| + if (_contentType == null || |
| + _contentType.value != "application/x-www-form-urlencoded") { |
| + throw new StateError('Cannot access the body fields of a Request without ' |
| + 'content-type "application/x-www-form-urlencoded".'); |
| + } |
| + |
| + return queryToMap(body); |
| + } |
| + |
| + set bodyFields(Map<String, String> fields) { |
| + if (_contentType == null) { |
| + _contentType = new ContentType("application", "x-www-form-urlencoded"); |
| + } else if (_contentType.value != "application/x-www-form-urlencoded") { |
| + throw new StateError('Cannot set the body fields of a Request with ' |
| + 'content-type "${_contentType.value}".'); |
| + } |
| + |
| + this.body = mapToQuery(fields); |
| + } |
| + |
| + /// Creates a new HTTP request. |
| + Request(String method, Uri url) |
| + : super(method, url), |
| + _defaultEncoding = Encoding.UTF_8, |
| + _bodyBytes = new Uint8List(0); |
| + |
| + /// Freeze all mutable fields and return an [InputStream] containing the |
| + /// request body. |
| + InputStream finalize() { |
| + super.finalize(); |
| + |
| + var stream = new ListInputStream(); |
| + stream.write(bodyBytes); |
| + stream.markEndOfStream(); |
| + return stream; |
| + } |
| + |
| + /// The `Content-Type` header of the request (if it exists) as a |
| + /// [ContentType]. |
| + ContentType get _contentType { |
| + var contentType = headers[HttpHeaders.CONTENT_TYPE]; |
| + if (contentType == null) return null; |
| + return new ContentType.fromString(contentType); |
| + } |
| + |
| + set _contentType(ContentType value) { |
| + headers[HttpHeaders.CONTENT_TYPE] = value.toString(); |
| + } |
| + |
| + /// Throw an error if this request has been finalized. |
| + void _checkFinalized() { |
| + if (!finalized) return; |
| + throw new StateError("Can't modify a finalized Request."); |
| + } |
| +} |