| Index: sdk/lib/io/http.dart
|
| diff --git a/sdk/lib/io/http.dart b/sdk/lib/io/http.dart
|
| index 366fd8dec00a33ad1a7764e03f15a30954a72d9a..dee31ab2b26e0f13f1bf9429ea7b6d132aae80ed 100644
|
| --- a/sdk/lib/io/http.dart
|
| +++ b/sdk/lib/io/http.dart
|
| @@ -55,31 +55,101 @@ abstract class HttpStatus {
|
|
|
|
|
| /**
|
| - * A server that delivers content, such as web pages, using
|
| - * the HTTP protocol.
|
| + * A server that delivers content, such as web pages, using the HTTP protocol.
|
| *
|
| - * The [HttpServer] is a [Stream] of [HttpRequest]s. Each
|
| - * [HttpRequest] has an associated [HttpResponse] object as its
|
| - * [HttpRequest.response] member, and the server responds to a request by
|
| - * writing to that [HttpResponse] object.
|
| + * The HttpServer is a [Stream] that provides [HttpRequest] objects. Each
|
| + * HttpRequest has an associated [HttpResponse] object.
|
| + * The server responds to a request by writing to that HttpResponse object.
|
| + * The following example shows how to bind an HttpServer to an IPv6
|
| + * [InternetAddress] on port 80 (the standard port for HTTP servers)
|
| + * and how to listen for requests.
|
| + * Port 80 is the default HTTP port. However, on most systems accessing
|
| + * this requires super-user privileges. For local testing consider
|
| + * using a non-reserved port (1024 and above).
|
| *
|
| - * Incomplete requests where all or parts of the header is missing, are
|
| - * ignored and no exceptions or [HttpRequest] objects are generated for them.
|
| - * Likewise, when writing to a [HttpResponse], any [Socket] exceptions are
|
| + * import 'dart:io';
|
| + *
|
| + * main() {
|
| + * HttpServer
|
| + * .bind(InternetAddress.ANY_IP_V6, 80)
|
| + * .then((server) {
|
| + * server.listen((HttpRequest request) {
|
| + * request.response.write('Hello, world!');
|
| + * request.response.close();
|
| + * });
|
| + * });
|
| + * }
|
| + *
|
| + * Incomplete requests, in which all or part of the header is missing, are
|
| + * ignored, and no exceptions or HttpRequest objects are generated for them.
|
| + * Likewise, when writing to an HttpResponse, any [Socket] exceptions are
|
| * ignored and any future writes are ignored.
|
| *
|
| - * The [HttpRequest] exposes the request headers, and provides the request body,
|
| - * if it exists, as a stream of data. If the body is unread, it'll be drained
|
| - * when the [HttpResponse] is being written to or closed.
|
| + * The HttpRequest exposes the request headers and provides the request body,
|
| + * if it exists, as a Stream of data. If the body is unread, it is drained
|
| + * when the server writes to the HttpResponse or closes it.
|
| *
|
| - * The following example shows how to bind a [HttpServer] to a IPv6
|
| - * [InternetAddress] on port 80, and listening to requests.
|
| + * ## Bind with a secure HTTPS connection
|
| *
|
| - * HttpServer.bind(InternetAddress.ANY_IP_V6, 80).then((server) {
|
| - * server.listen((HttpRequest request) {
|
| - * // Handle requests.
|
| - * });
|
| - * });
|
| + * Use [bindSecure] to create an HTTPS server.
|
| + *
|
| + * The server presents a certificate to the client. In the following
|
| + * example, the certificate is named `localhost_cert` and comes from
|
| + * the database found in the `pkcert` directory.
|
| + *
|
| + * import 'dart:io';
|
| + * import "dart:isolate";
|
| + *
|
| + * main() {
|
| + * var testPkcertDatabase = Platform.script.resolve('pkcert')
|
| + * .toFilePath();
|
| + * SecureSocket.initialize(database: testPkcertDatabase,
|
| + * password: 'dartdart');
|
| + *
|
| + * HttpServer
|
| + * .bindSecure(InternetAddress.ANY_IP_V6,
|
| + * 443,
|
| + * certificateName: 'localhost_cert')
|
| + * .then((server) {
|
| + * server.listen((HttpRequest request) {
|
| + * request.response.write('Hello, world!');
|
| + * request.response.close();
|
| + * });
|
| + * });
|
| + * }
|
| + *
|
| + * The certificate database is managed using the Mozilla certutil tool (see
|
| + * [NSS Tools certutil](https://developer.mozilla.org/en-US/docs/NSS/tools/NSS_Tools_certutil)).
|
| + * Dart uses the NSS library to handle SSL, and the Mozilla certutil
|
| + * must be used to manipulate the certificate database.
|
| + *
|
| + * ## Connect to a server socket
|
| + *
|
| + * You can use the [listenOn] constructor to attach an HTTP server to
|
| + * a [ServerSocket].
|
| + *
|
| + * import 'dart:io';
|
| + *
|
| + * main() {
|
| + * ServerSocket.bind(InternetAddress.ANY_IP_V6, 80)
|
| + * .then((serverSocket) {
|
| + * HttpServer httpserver = new HttpServer.listenOn(serverSocket);
|
| + * serverSocket.listen((Socket socket) {
|
| + * socket.write('Hello, client.');
|
| + * });
|
| + * });
|
| + * }
|
| + *
|
| + * ## Other resources
|
| + *
|
| + * * HttpServer is a Stream. Refer to the [Stream] class for information
|
| + * about the streaming qualities of an HttpServer.
|
| + * Pausing the subscription of the stream, pauses at the OS level.
|
| + *
|
| + * * The [http_server](https://pub.dartlang.org/packages/http_server)
|
| + * package on pub.dartlang.org contains a set of high-level classes that,
|
| + * together with this class, makes it easy to provide content through HTTP
|
| + * servers.
|
| */
|
| abstract class HttpServer implements Stream<HttpRequest> {
|
| /**
|
| @@ -261,12 +331,33 @@ class HttpConnectionsInfo {
|
|
|
|
|
| /**
|
| - * Access to the HTTP headers for requests and responses. In some
|
| - * situations the headers will be immutable and the mutating methods
|
| - * will then throw exceptions.
|
| + * Headers for HTTP requests and responses.
|
| + *
|
| + * In some situations, headers are immutable:
|
| + *
|
| + * * HttpRequest and HttpClientResponse always have immutable headers.
|
| + *
|
| + * * HttpResponse and HttpClientRequest have immutable headers
|
| + * from the moment the body is written to.
|
| + *
|
| + * In these situations, the mutating methods throw exceptions.
|
| *
|
| * For all operations on HTTP headers the header name is
|
| * case-insensitive.
|
| + *
|
| + * To set the value of a header use the `set()` method:
|
| + *
|
| + * request.headers.set(HttpHeaders.CACHE_CONTROL,
|
| + 'max-age=3600, must-revalidate');
|
| + *
|
| + * To retrieve the value of a header use the `value()` method:
|
| + *
|
| + * print(request.headers.value(HttpHeaders.USER_AGENT));
|
| + *
|
| + * An HttpHeaders object holds a list of values for each name
|
| + * as the standard allows. In most cases a name holds only a single value,
|
| + * The most common mode of operation is to use `set()` for setting a value,
|
| + * and `value()` for retrieving a value.
|
| */
|
| abstract class HttpHeaders {
|
| static const ACCEPT = "accept";
|
| @@ -759,11 +850,11 @@ abstract class Cookie {
|
| * such as the method, URI, and headers.
|
| *
|
| * In the following code, an HttpServer listens
|
| - * for HTTP requests and, within the callback function,
|
| - * uses the `HttpRequest` object's `method` property to dispatch requests.
|
| + * for HTTP requests. When the server receives a request,
|
| + * it uses the HttpRequest object's `method` property to dispatch requests.
|
| *
|
| * final HOST = InternetAddress.LOOPBACK_IP_V4;
|
| - * final PORT = 4040;
|
| + * final PORT = 80;
|
| *
|
| * HttpServer.bind(HOST, PORT).then((_server) {
|
| * _server.listen((HttpRequest request) {
|
| @@ -778,12 +869,10 @@ abstract class Cookie {
|
| * onError: handleError); // listen() failed.
|
| * }).catchError(handleError);
|
| *
|
| - * Listen to the `HttpRequest` stream to handle the
|
| - * data and be notified once the entire body is received.
|
| - * An `HttpRequest` object contains an [HttpResponse] object,
|
| - * to which the server can write its response.
|
| - * For example, here's a skeletal callback function
|
| - * that responds to a request:
|
| + * An HttpRequest object provides access to the associated [HttpResponse]
|
| + * object through the response property.
|
| + * The server writes its response to the body of the HttpResponse object.
|
| + * For example, here's a function that responds to a request:
|
| *
|
| * void handleGetRequest(HttpRequest req) {
|
| * HttpResponse res = req.response;
|
| @@ -893,18 +982,37 @@ abstract class HttpRequest implements Stream<List<int>> {
|
|
|
|
|
| /**
|
| - * An [HttpResponse] represents the headers and data to be returned to
|
| - * a client in response to an HTTP request.
|
| - *
|
| - * This object has a number of properties for setting up the HTTP
|
| - * header of the response. When the header has been set up the methods
|
| - * from the [IOSink] can be used to write the actual body of the HTTP
|
| - * response. When one of the [IOSink] methods is used for the
|
| - * first time the request header is send. Calling any methods that
|
| - * will change the header after it is sent will throw an exception.
|
| - *
|
| - * When writing string data through the [IOSink] the encoding used
|
| - * will be determined from the "charset" parameter of the
|
| + * An HTTP response, which returns the headers and data
|
| + * from the server to the client in response to an HTTP request.
|
| + *
|
| + * Every HttpRequest object provides access to the associated [HttpResponse]
|
| + * object through the `response` property.
|
| + * The server sends its response to the client by writing to the
|
| + * HttpResponse object.
|
| + *
|
| + * ## Writing the response
|
| + *
|
| + * This class implements [IOSink].
|
| + * After the header has been set up, the methods
|
| + * from IOSink, such as `writeln()`, can be used to write
|
| + * the body of the HTTP response.
|
| + * Use the `close()` method to close the response and send it to the client.
|
| + *
|
| + * server.listen((HttpRequest request) {
|
| + * request.response.write('Hello, world!');
|
| + * request.response.close();
|
| + * });
|
| + *
|
| + * When one of the IOSink methods is used for the
|
| + * first time, the request header is sent. Calling any methods that
|
| + * change the header after it is sent throws an exception.
|
| + *
|
| + * ## Setting the headers
|
| + *
|
| + * The HttpResponse object has a number of properties for setting up
|
| + * the HTTP headers of the response.
|
| + * When writing string data through the IOSink, the encoding used
|
| + * is determined from the "charset" parameter of the
|
| * "Content-Type" header.
|
| *
|
| * HttpResponse response = ...
|
| @@ -919,8 +1027,8 @@ abstract class HttpRequest implements Stream<List<int>> {
|
| * response.headers.add(HttpHeaders.CONTENT_TYPE, "text/plain");
|
| * response.write(...); // Strings written will be ISO-8859-1 encoded.
|
| *
|
| - * If an unsupported encoding is used an exception will be thrown if
|
| - * using one of the write methods taking a string.
|
| + * An exception is thrown if you use the `write()` method
|
| + * while an unsupported content-type is set.
|
| */
|
| abstract class HttpResponse implements IOSink {
|
| // TODO(ajohnsen): Add documentation of how to pipe a file to the response.
|
| @@ -1011,57 +1119,72 @@ abstract class HttpResponse implements IOSink {
|
| * A client that receives content, such as web pages, from
|
| * a server using the HTTP protocol.
|
| *
|
| - * HttpClient contains a number of methods to send a HTTP request
|
| - * to a HTTP server and receive a HTTP response back.
|
| + * HttpClient contains a number of methods to send an [HttpClientRequest]
|
| + * to an Http server and receive an [HttpClientResponse] back.
|
| + * For example, you can use the [get], [getUrl], [post], and [postUrl] methods
|
| + * for GET and POST requests, respectively.
|
| *
|
| - * This is a two-step process, triggered by two futures. When the
|
| - * first future completes with a [HttpClientRequest] the underlying
|
| - * network connection has been established, but no data has yet been
|
| - * sent. The HTTP headers and body can be set on the request, and
|
| - * [:close:] is called to sent it to the server.
|
| + * ## Making a simple GET request: an example
|
| *
|
| - * The second future, which is returned by [:close:], completes with
|
| - * an [HttpClientResponse] object when the response is received from
|
| - * the server. This object contains the headers and body of the
|
| - * response.
|
| -
|
| - * The future for [HttpClientRequest] is created by methods such as
|
| - * [getUrl] and [open].
|
| + * A `getUrl` request is a two-step process, triggered by two [Future]s.
|
| + * When the first future completes with a [HttpClientRequest], the underlying
|
| + * network connection has been established, but no data has been sent.
|
| + * In the callback function for the first future, the HTTP headers and body
|
| + * can be set on the request. Either the first write to the request object
|
| + * or a call to [close] sends the request to the server.
|
| *
|
| - * When the HTTP response is ready a [HttpClientResponse] object is
|
| - * provided which provides access to the headers and body of the response. The
|
| - * body is available as a stream implemented by [HttpClientResponse].
|
| - * If a body is present, it must be read. Otherwise, it'll lead to a resource
|
| + * When the HTTP response is received from the server,
|
| + * the second future, which is returned by close,
|
| + * completes with an [HttpClientResponse] object.
|
| + * This object provides access to the headers and body of the response.
|
| + * The body is available as a stream implemented by HttpClientResponse.
|
| + * If a body is present, it must be read. Otherwise, it leads to resource
|
| * leaks. Consider using [HttpClientResponse.drain] if the body is unused.
|
| *
|
| * HttpClient client = new HttpClient();
|
| * client.getUrl(Uri.parse("http://www.example.com/"))
|
| * .then((HttpClientRequest request) {
|
| - * // Prepare the request then call close on it to send it.
|
| + * // Optionally set up headers...
|
| + * // Optionally write to the request object...
|
| + * // Then call close.
|
| + * ...
|
| * return request.close();
|
| * })
|
| * .then((HttpClientResponse response) {
|
| - * // Process the response.
|
| + * // Process the response.
|
| + * ...
|
| * });
|
| *
|
| - * All [HttpClient] requests set the following header by default:
|
| + * The future for [HttpClientRequest] is created by methods such as
|
| + * [getUrl] and [open].
|
| + *
|
| + * ## Headers
|
| + *
|
| + * All HttpClient requests set the following header by default:
|
| *
|
| * Accept-Encoding: gzip
|
| *
|
| * This allows the HTTP server to use gzip compression for the body if
|
| * possible. If this behavior is not desired set the
|
| - * "Accept-Encoding" header to something else.
|
| + * `Accept-Encoding` header to something else.
|
| + * To turn off gzip compression of the response, clear this header:
|
| + *
|
| + * request.headers.removeAll(HttpHeaders.ACCEPT_ENCODING)
|
| *
|
| - * The [HttpClient] supports persistent connections and caches network
|
| - * connections to reuse then for multiple requests whenever
|
| + * ## Closing the HttpClient
|
| + *
|
| + * The HttpClient supports persistent connections and caches network
|
| + * connections to reuse them for multiple requests whenever
|
| * possible. This means that network connections can be kept open for
|
| - * some time after a request have completed. Use [:HttpClient.close:]
|
| - * to force shut down the [HttpClient] object and close the idle
|
| + * some time after a request has completed. Use HttpClient.close
|
| + * to force the HttpClient object to shut down and to close the idle
|
| * network connections.
|
| *
|
| + * ## Turning proxies on and off
|
| + *
|
| * By default the HttpClient uses the proxy configuration available
|
| * from the environment, see [findProxyFromEnvironment]. To turn off
|
| - * the use of proxies all together set the [findProxy] property to
|
| + * the use of proxies set the [findProxy] property to
|
| * [:null:].
|
| *
|
| * HttpClient client = new HttpClient();
|
| @@ -1346,15 +1469,16 @@ abstract class HttpClient {
|
| /**
|
| * HTTP request for a client connection.
|
| *
|
| - * This object has a number of properties for setting up the HTTP
|
| - * header of the request. When the header has been set up the methods
|
| - * from the [IOSink] can be used to write the actual body of the HTTP
|
| - * request. When one of the [IOSink] methods is used for the first
|
| - * time the request header is send. Calling any methods that will
|
| - * change the header after it is sent will throw an exception.
|
| + * To set up a request, set the headers using the headers property
|
| + * provided in this class and write the data to the body of the request.
|
| + * HttpClientRequest is an [IOSink]. Use the methods from IOSink,
|
| + * such as writeCharCode(), to write the body of the HTTP
|
| + * request. When one of the IOSink methods is used for the first
|
| + * time, the request header is sent. Calling any methods that
|
| + * change the header after it is sent throws an exception.
|
| *
|
| * When writing string data through the [IOSink] the
|
| - * encoding used will be determined from the "charset" parameter of
|
| + * encoding used is determined from the "charset" parameter of
|
| * the "Content-Type" header.
|
| *
|
| * HttpClientRequest request = ...
|
| @@ -1362,15 +1486,15 @@ abstract class HttpClient {
|
| * = new ContentType("application", "json", charset: "utf-8");
|
| * request.write(...); // Strings written will be UTF-8 encoded.
|
| *
|
| - * If no charset is provided the default of ISO-8859-1 (Latin 1) will
|
| + * If no charset is provided the default of ISO-8859-1 (Latin 1) is
|
| * be used.
|
| *
|
| * HttpClientRequest request = ...
|
| * request.headers.add(HttpHeaders.CONTENT_TYPE, "text/plain");
|
| * request.write(...); // Strings written will be ISO-8859-1 encoded.
|
| *
|
| - * If an unsupported encoding is used an exception will be thrown if
|
| - * using one of the write methods taking a string.
|
| + * An exception is thrown if you use an unsupported encoding and the
|
| + * `write()` method being used takes a string parameter.
|
| */
|
| abstract class HttpClientRequest implements IOSink {
|
| /**
|
| @@ -1457,9 +1581,19 @@ abstract class HttpClientRequest implements IOSink {
|
|
|
|
|
| /**
|
| - * HTTP response for a client connection. The [HttpClientResponse] is a
|
| - * [Stream] of the body content of the response. Listen to the body to handle
|
| - * the data and be notified once the entire body is received.
|
| + * HTTP response for a client connection.
|
| +
|
| + * The body of a [HttpClientResponse] object is a
|
| + * [Stream] of data from the server. Listen to the body to handle
|
| + * the data and be notified when the entire body is received.
|
| + *
|
| + * new HttpClient().get('localhost', 80, '/file.txt')
|
| + * .then((HttpClientRequeset request) => request.close())
|
| + * .then((HttpClientResponse response) {
|
| + * response.transform(UTF8.decoder).listen((contents) {
|
| + * // handle data
|
| + * });
|
| + * });
|
| */
|
| abstract class HttpClientResponse implements Stream<List<int>> {
|
| /**
|
|
|