5285b80b8a
locking down MultipartRequest a bit Removed superfluous import of dart:io and dart:isolate R=nweiz@google.com Review URL: https://codereview.chromium.org//19866007 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@25376 260f80e4-7a28-3924-810f-c04153c831b5
133 lines
4.4 KiB
Dart
133 lines
4.4 KiB
Dart
// 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 base_request;
|
|
|
|
import 'dart:async';
|
|
|
|
import 'byte_stream.dart';
|
|
import 'client.dart';
|
|
import 'streamed_response.dart';
|
|
import 'utils.dart';
|
|
|
|
/// The base class for HTTP requests.
|
|
///
|
|
/// Subclasses of [BaseRequest] can be constructed manually and passed to
|
|
/// [BaseClient.send], which allows the user to provide fine-grained control
|
|
/// over the request properties. However, usually it's easier to use convenience
|
|
/// methods like [get] or [BaseClient.get].
|
|
abstract class BaseRequest {
|
|
/// The HTTP method of the request. Most commonly "GET" or "POST", less
|
|
/// commonly "HEAD", "PUT", or "DELETE". Non-standard method names are also
|
|
/// supported.
|
|
final String method;
|
|
|
|
/// The URL to which the request will be sent.
|
|
final Uri url;
|
|
|
|
/// The size of the request body, in bytes. This defaults to -1, which
|
|
/// indicates that the size of the request is not known in advance.
|
|
int get contentLength => _contentLength;
|
|
int _contentLength = -1;
|
|
|
|
set contentLength(int value) {
|
|
_checkFinalized();
|
|
_contentLength = value;
|
|
}
|
|
|
|
/// Whether a persistent connection should be maintained with the server.
|
|
/// Defaults to true.
|
|
bool get persistentConnection => _persistentConnection;
|
|
bool _persistentConnection = true;
|
|
|
|
set persistentConnection(bool value) {
|
|
_checkFinalized();
|
|
_persistentConnection = value;
|
|
}
|
|
|
|
/// Whether the client should follow redirects while resolving this request.
|
|
/// Defaults to true.
|
|
bool get followRedirects => _followRedirects;
|
|
bool _followRedirects = true;
|
|
|
|
set followRedirects(bool value) {
|
|
_checkFinalized();
|
|
_followRedirects = value;
|
|
}
|
|
|
|
/// The maximum number of redirects to follow when [followRedirects] is true.
|
|
/// If this number is exceeded the [BaseResponse] future will signal a
|
|
/// [RedirectException]. Defaults to 5.
|
|
int get maxRedirects => _maxRedirects;
|
|
int _maxRedirects = 5;
|
|
|
|
set maxRedirects(int value) {
|
|
_checkFinalized();
|
|
_maxRedirects = value;
|
|
}
|
|
|
|
// TODO(nweiz): automatically parse cookies from headers
|
|
|
|
// TODO(nweiz): make this a HttpHeaders object
|
|
/// The headers for this request.
|
|
final Map<String, String> headers;
|
|
|
|
/// Whether the request has been finalized.
|
|
bool get finalized => _finalized;
|
|
bool _finalized = false;
|
|
|
|
/// Creates a new HTTP request.
|
|
BaseRequest(this.method, this.url)
|
|
: headers = <String, String>{};
|
|
|
|
/// Finalizes the HTTP request in preparation for it being sent. This freezes
|
|
/// all mutable fields and returns a single-subscription [ByteStream] that
|
|
/// emits the body of the request.
|
|
///
|
|
/// The base implementation of this returns null rather than a [ByteStream];
|
|
/// subclasses are responsible for creating the return value, which should be
|
|
/// single-subscription to ensure that no data is dropped. They should also
|
|
/// freeze any additional mutable fields they add that don't make sense to
|
|
/// change after the request headers are sent.
|
|
ByteStream finalize() {
|
|
// TODO(nweiz): freeze headers
|
|
if (finalized) throw new StateError("Can't finalize a finalized Request.");
|
|
_finalized = true;
|
|
return null;
|
|
}
|
|
|
|
/// Sends this request.
|
|
///
|
|
/// This automatically initializes a new [Client] and closes that client once
|
|
/// the request is complete. If you're planning on making multiple requests to
|
|
/// the same server, you should use a single [Client] for all of those
|
|
/// requests.
|
|
Future<StreamedResponse> send() {
|
|
var client = new Client();
|
|
return client.send(this).then((response) {
|
|
var stream = onDone(response.stream, client.close);
|
|
return new StreamedResponse(
|
|
new ByteStream(stream),
|
|
response.statusCode,
|
|
response.contentLength,
|
|
request: response.request,
|
|
headers: response.headers,
|
|
isRedirect: response.isRedirect,
|
|
persistentConnection: response.persistentConnection,
|
|
reasonPhrase: response.reasonPhrase);
|
|
}).catchError((e) {
|
|
client.close();
|
|
throw e;
|
|
});
|
|
}
|
|
|
|
/// Throws an error if this request has been finalized.
|
|
void _checkFinalized() {
|
|
if (!finalized) return;
|
|
throw new StateError("Can't modify a finalized Request.");
|
|
}
|
|
|
|
String toString() => "$method $url";
|
|
}
|