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>> { |
/** |