| // Copyright (c) 2013, 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 dart._http; |
| |
| import 'dart:_internal' |
| show Since, valueOfNonNullableParamWithDefault, HttpStatus; |
| import 'dart:async'; |
| import 'dart:collection' |
| show |
| HashMap, |
| HashSet, |
| ListQueue, |
| LinkedList, |
| LinkedListEntry, |
| UnmodifiableMapView; |
| import 'dart:convert'; |
| import 'dart:developer' hide log; |
| import 'dart:io'; |
| import 'dart:isolate' show Isolate; |
| import 'dart:math'; |
| import 'dart:typed_data'; |
| |
| part 'crypto.dart'; |
| part 'embedder_config.dart'; |
| part 'http_date.dart'; |
| part 'http_headers.dart'; |
| part 'http_impl.dart'; |
| part 'http_parser.dart'; |
| part 'http_session.dart'; |
| part 'overrides.dart'; |
| part 'websocket.dart'; |
| part 'websocket_impl.dart'; |
| |
| /// A server that delivers content, such as web pages, using the HTTP protocol. |
| /// |
| /// Note: [HttpServer] provides low-level HTTP functionality. |
| /// We recommend users evaluate the high-level APIs discussed at |
| /// [Write HTTP servers](https://dart.dev/tutorials/server/httpserver) on |
| /// [dart.dev](https://dart.dev/). |
| /// |
| /// `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). |
| /// |
| /// ```dart |
| /// import 'dart:io'; |
| /// |
| /// void main() async { |
| /// var server = await HttpServer.bind(InternetAddress.anyIPv6, 80); |
| /// await server.forEach((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 is drained |
| /// when the server writes to the HttpResponse or closes it. |
| /// |
| /// ## Bind with a secure HTTPS connection |
| /// |
| /// Use [bindSecure] to create an HTTPS server. |
| /// |
| /// The server presents a certificate to the client. The certificate |
| /// chain and the private key are set in the [SecurityContext] |
| /// object that is passed to [bindSecure]. |
| /// |
| /// ```dart |
| /// import 'dart:io'; |
| /// |
| /// void main() async { |
| /// var chain = |
| /// Platform.script.resolve('certificates/server_chain.pem').toFilePath(); |
| /// var key = Platform.script.resolve('certificates/server_key.pem').toFilePath(); |
| /// var context = SecurityContext() |
| /// ..useCertificateChain(chain) |
| /// ..usePrivateKey(key, password: 'dartdart'); |
| /// var server = |
| /// await HttpServer.bindSecure(InternetAddress.anyIPv6, 443, context); |
| /// await server.forEach((HttpRequest request) { |
| /// request.response.write('Hello, world!'); |
| /// request.response.close(); |
| /// }); |
| /// } |
| /// ``` |
| /// |
| /// The certificates and keys are PEM files, which can be created and |
| /// managed with the tools in OpenSSL. |
| abstract class HttpServer implements Stream<HttpRequest> { |
| /// Gets and sets the default value of the `Server` header for all responses |
| /// generated by this [HttpServer]. |
| /// |
| /// If [serverHeader] is `null`, no `Server` header will be added to each |
| /// response. |
| /// |
| /// The default value is `null`. |
| String? serverHeader; |
| |
| /// Default set of headers added to all response objects. |
| /// |
| /// By default the following headers are in this set: |
| /// |
| /// Content-Type: text/plain; charset=utf-8 |
| /// X-Frame-Options: SAMEORIGIN |
| /// X-Content-Type-Options: nosniff |
| /// X-XSS-Protection: 1; mode=block |
| /// |
| /// If the `Server` header is added here and the `serverHeader` is set as |
| /// well then the value of `serverHeader` takes precedence. |
| HttpHeaders get defaultResponseHeaders; |
| |
| /// Whether the [HttpServer] should compress the content, if possible. |
| /// |
| /// The content can only be compressed when the response is using |
| /// chunked Transfer-Encoding and the incoming request has `gzip` |
| /// as an accepted encoding in the Accept-Encoding header. |
| /// |
| /// The default value is `false` (compression disabled). |
| /// To enable, set `autoCompress` to `true`. |
| bool autoCompress = false; |
| |
| /// Gets or sets the timeout used for idle keep-alive connections. If no |
| /// further request is seen within [idleTimeout] after the previous request was |
| /// completed, the connection is dropped. |
| /// |
| /// Default is 120 seconds. |
| /// |
| /// Note that it may take up to `2 * idleTimeout` before a idle connection is |
| /// aborted. |
| /// |
| /// To disable, set [idleTimeout] to `null`. |
| Duration? idleTimeout = const Duration(seconds: 120); |
| |
| /// Starts listening for HTTP requests on the specified [address] and |
| /// [port]. |
| /// |
| /// The [address] can either be a [String] or an |
| /// [InternetAddress]. If [address] is a [String], [bind] will |
| /// perform a [InternetAddress.lookup] and use the first value in the |
| /// list. To listen on the loopback adapter, which will allow only |
| /// incoming connections from the local host, use the value |
| /// [InternetAddress.loopbackIPv4] or |
| /// [InternetAddress.loopbackIPv6]. To allow for incoming |
| /// connection from the network use either one of the values |
| /// [InternetAddress.anyIPv4] or [InternetAddress.anyIPv6] to |
| /// bind to all interfaces or the IP address of a specific interface. |
| /// |
| /// If an IP version 6 (IPv6) address is used, both IP version 6 |
| /// (IPv6) and version 4 (IPv4) connections will be accepted. To |
| /// restrict this to version 6 (IPv6) only, use [v6Only] to set |
| /// version 6 only. However, if the address is |
| /// [InternetAddress.loopbackIPv6], only IP version 6 (IPv6) connections |
| /// will be accepted. |
| /// |
| /// If [port] has the value 0 an ephemeral port will be chosen by |
| /// the system. The actual port used can be retrieved using the |
| /// [port] getter. |
| /// |
| /// The optional argument [backlog] can be used to specify the listen |
| /// backlog for the underlying OS listen setup. If [backlog] has the |
| /// value of 0 (the default) a reasonable value will be chosen by |
| /// the system. |
| /// |
| /// The optional argument [shared] specifies whether additional `HttpServer` |
| /// objects can bind to the same combination of `address`, `port` and `v6Only`. |
| /// If `shared` is `true` and more `HttpServer`s from this isolate or other |
| /// isolates are bound to the port, then the incoming connections will be |
| /// distributed among all the bound `HttpServer`s. Connections can be |
| /// distributed over multiple isolates this way. |
| static Future<HttpServer> bind(address, int port, |
| {int backlog = 0, bool v6Only = false, bool shared = false}) => |
| _HttpServer.bind(address, port, backlog, v6Only, shared); |
| |
| /// The [address] can either be a [String] or an |
| /// [InternetAddress]. If [address] is a [String], [bind] will |
| /// perform a [InternetAddress.lookup] and use the first value in the |
| /// list. To listen on the loopback adapter, which will allow only |
| /// incoming connections from the local host, use the value |
| /// [InternetAddress.loopbackIPv4] or |
| /// [InternetAddress.loopbackIPv6]. To allow for incoming |
| /// connection from the network use either one of the values |
| /// [InternetAddress.anyIPv4] or [InternetAddress.anyIPv6] to |
| /// bind to all interfaces or the IP address of a specific interface. |
| /// |
| /// If an IP version 6 (IPv6) address is used, both IP version 6 |
| /// (IPv6) and version 4 (IPv4) connections will be accepted. To |
| /// restrict this to version 6 (IPv6) only, use [v6Only] to set |
| /// version 6 only. |
| /// |
| /// If [port] has the value 0 an ephemeral port will be chosen by |
| /// the system. The actual port used can be retrieved using the |
| /// [port] getter. |
| /// |
| /// The optional argument [backlog] can be used to specify the listen |
| /// backlog for the underlying OS listen setup. If [backlog] has the |
| /// value of 0 (the default) a reasonable value will be chosen by |
| /// the system. |
| /// |
| /// If [requestClientCertificate] is true, the server will |
| /// request clients to authenticate with a client certificate. |
| /// The server will advertise the names of trusted issuers of client |
| /// certificates, getting them from a [SecurityContext], where they have been |
| /// set using [SecurityContext.setClientAuthorities]. |
| /// |
| /// The optional argument [shared] specifies whether additional `HttpServer` |
| /// objects can bind to the same combination of `address`, `port` and `v6Only`. |
| /// If `shared` is `true` and more `HttpServer`s from this isolate or other |
| /// isolates are bound to the port, then the incoming connections will be |
| /// distributed among all the bound `HttpServer`s. Connections can be |
| /// distributed over multiple isolates this way. |
| |
| static Future<HttpServer> bindSecure( |
| address, int port, SecurityContext context, |
| {int backlog = 0, |
| bool v6Only = false, |
| bool requestClientCertificate = false, |
| bool shared = false}) => |
| _HttpServer.bindSecure(address, port, context, backlog, v6Only, |
| requestClientCertificate, shared); |
| |
| /// Attaches the HTTP server to an existing [ServerSocket]. When the |
| /// [HttpServer] is closed, the [HttpServer] will just detach itself, |
| /// closing current connections but not closing [serverSocket]. |
| factory HttpServer.listenOn(ServerSocket serverSocket) => |
| _HttpServer.listenOn(serverSocket); |
| |
| /// Permanently stops this [HttpServer] from listening for new |
| /// connections. This closes the [Stream] of [HttpRequest]s with a |
| /// done event. The returned future completes when the server is |
| /// stopped. For a server started using [bind] or [bindSecure] this |
| /// means that the port listened on no longer in use. |
| /// |
| /// If [force] is `true`, active connections will be closed immediately. |
| Future close({bool force = false}); |
| |
| /// The port that the server is listening on. |
| /// |
| /// This is the actual port used when a port of zero is |
| /// specified in the [bind] or [bindSecure] call. |
| int get port; |
| |
| /// The address that the server is listening on. |
| /// |
| /// This is the actual address used when the original address |
| /// was specified as a hostname. |
| InternetAddress get address; |
| |
| /// Sets the timeout, in seconds, for sessions of this [HttpServer]. |
| /// |
| /// The default timeout is 20 minutes. |
| set sessionTimeout(int timeout); |
| |
| /// A [HttpConnectionsInfo] object summarizing the number of |
| /// current connections handled by the server. |
| HttpConnectionsInfo connectionsInfo(); |
| } |
| |
| /// Summary statistics about an [HttpServer]s current socket connections. |
| class HttpConnectionsInfo { |
| /// Total number of socket connections. |
| int total = 0; |
| |
| /// Number of active connections where actual request/response |
| /// processing is active. |
| int active = 0; |
| |
| /// Number of idle connections held by clients as persistent connections. |
| int idle = 0; |
| |
| /// Number of connections which are preparing to close. |
| /// |
| /// Note: These connections are also part of the [active] count as they might |
| /// still be sending data to the client before finally closing. |
| int closing = 0; |
| } |
| |
| /// 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.cacheControlHeader, |
| /// 'max-age=3600, must-revalidate'); |
| /// |
| /// To retrieve the value of a header use the `value()` method: |
| /// |
| /// print(request.headers.value(HttpHeaders.userAgentHeader)); |
| /// |
| /// 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 acceptHeader = "accept"; |
| static const acceptCharsetHeader = "accept-charset"; |
| static const acceptEncodingHeader = "accept-encoding"; |
| static const acceptLanguageHeader = "accept-language"; |
| static const acceptRangesHeader = "accept-ranges"; |
| @Since("2.14") |
| static const accessControlAllowCredentialsHeader = |
| 'access-control-allow-credentials'; |
| @Since("2.14") |
| static const accessControlAllowHeadersHeader = 'access-control-allow-headers'; |
| @Since("2.14") |
| static const accessControlAllowMethodsHeader = 'access-control-allow-methods'; |
| @Since("2.14") |
| static const accessControlAllowOriginHeader = 'access-control-allow-origin'; |
| @Since("2.14") |
| static const accessControlExposeHeadersHeader = |
| 'access-control-expose-headers'; |
| @Since("2.14") |
| static const accessControlMaxAgeHeader = 'access-control-max-age'; |
| @Since("2.14") |
| static const accessControlRequestHeadersHeader = |
| 'access-control-request-headers'; |
| @Since("2.14") |
| static const accessControlRequestMethodHeader = |
| 'access-control-request-method'; |
| static const ageHeader = "age"; |
| static const allowHeader = "allow"; |
| static const authorizationHeader = "authorization"; |
| static const cacheControlHeader = "cache-control"; |
| static const connectionHeader = "connection"; |
| static const contentEncodingHeader = "content-encoding"; |
| static const contentLanguageHeader = "content-language"; |
| static const contentLengthHeader = "content-length"; |
| static const contentLocationHeader = "content-location"; |
| static const contentMD5Header = "content-md5"; |
| static const contentRangeHeader = "content-range"; |
| static const contentTypeHeader = "content-type"; |
| static const dateHeader = "date"; |
| static const etagHeader = "etag"; |
| static const expectHeader = "expect"; |
| static const expiresHeader = "expires"; |
| static const fromHeader = "from"; |
| static const hostHeader = "host"; |
| static const ifMatchHeader = "if-match"; |
| static const ifModifiedSinceHeader = "if-modified-since"; |
| static const ifNoneMatchHeader = "if-none-match"; |
| static const ifRangeHeader = "if-range"; |
| static const ifUnmodifiedSinceHeader = "if-unmodified-since"; |
| static const lastModifiedHeader = "last-modified"; |
| static const locationHeader = "location"; |
| static const maxForwardsHeader = "max-forwards"; |
| static const pragmaHeader = "pragma"; |
| static const proxyAuthenticateHeader = "proxy-authenticate"; |
| static const proxyAuthorizationHeader = "proxy-authorization"; |
| static const rangeHeader = "range"; |
| static const refererHeader = "referer"; |
| static const retryAfterHeader = "retry-after"; |
| static const serverHeader = "server"; |
| static const teHeader = "te"; |
| static const trailerHeader = "trailer"; |
| static const transferEncodingHeader = "transfer-encoding"; |
| static const upgradeHeader = "upgrade"; |
| static const userAgentHeader = "user-agent"; |
| static const varyHeader = "vary"; |
| static const viaHeader = "via"; |
| static const warningHeader = "warning"; |
| static const wwwAuthenticateHeader = "www-authenticate"; |
| |
| @Deprecated("Use acceptHeader instead") |
| static const ACCEPT = acceptHeader; |
| @Deprecated("Use acceptCharsetHeader instead") |
| static const ACCEPT_CHARSET = acceptCharsetHeader; |
| @Deprecated("Use acceptEncodingHeader instead") |
| static const ACCEPT_ENCODING = acceptEncodingHeader; |
| @Deprecated("Use acceptLanguageHeader instead") |
| static const ACCEPT_LANGUAGE = acceptLanguageHeader; |
| @Deprecated("Use acceptRangesHeader instead") |
| static const ACCEPT_RANGES = acceptRangesHeader; |
| @Deprecated("Use ageHeader instead") |
| static const AGE = ageHeader; |
| @Deprecated("Use allowHeader instead") |
| static const ALLOW = allowHeader; |
| @Deprecated("Use authorizationHeader instead") |
| static const AUTHORIZATION = authorizationHeader; |
| @Deprecated("Use cacheControlHeader instead") |
| static const CACHE_CONTROL = cacheControlHeader; |
| @Deprecated("Use connectionHeader instead") |
| static const CONNECTION = connectionHeader; |
| @Deprecated("Use contentEncodingHeader instead") |
| static const CONTENT_ENCODING = contentEncodingHeader; |
| @Deprecated("Use contentLanguageHeader instead") |
| static const CONTENT_LANGUAGE = contentLanguageHeader; |
| @Deprecated("Use contentLengthHeader instead") |
| static const CONTENT_LENGTH = contentLengthHeader; |
| @Deprecated("Use contentLocationHeader instead") |
| static const CONTENT_LOCATION = contentLocationHeader; |
| @Deprecated("Use contentMD5Header instead") |
| static const CONTENT_MD5 = contentMD5Header; |
| @Deprecated("Use contentRangeHeader instead") |
| static const CONTENT_RANGE = contentRangeHeader; |
| @Deprecated("Use contentTypeHeader instead") |
| static const CONTENT_TYPE = contentTypeHeader; |
| @Deprecated("Use dateHeader instead") |
| static const DATE = dateHeader; |
| @Deprecated("Use etagHeader instead") |
| static const ETAG = etagHeader; |
| @Deprecated("Use expectHeader instead") |
| static const EXPECT = expectHeader; |
| @Deprecated("Use expiresHeader instead") |
| static const EXPIRES = expiresHeader; |
| @Deprecated("Use fromHeader instead") |
| static const FROM = fromHeader; |
| @Deprecated("Use hostHeader instead") |
| static const HOST = hostHeader; |
| @Deprecated("Use ifMatchHeader instead") |
| static const IF_MATCH = ifMatchHeader; |
| @Deprecated("Use ifModifiedSinceHeader instead") |
| static const IF_MODIFIED_SINCE = ifModifiedSinceHeader; |
| @Deprecated("Use ifNoneMatchHeader instead") |
| static const IF_NONE_MATCH = ifNoneMatchHeader; |
| @Deprecated("Use ifRangeHeader instead") |
| static const IF_RANGE = ifRangeHeader; |
| @Deprecated("Use ifUnmodifiedSinceHeader instead") |
| static const IF_UNMODIFIED_SINCE = ifUnmodifiedSinceHeader; |
| @Deprecated("Use lastModifiedHeader instead") |
| static const LAST_MODIFIED = lastModifiedHeader; |
| @Deprecated("Use locationHeader instead") |
| static const LOCATION = locationHeader; |
| @Deprecated("Use maxForwardsHeader instead") |
| static const MAX_FORWARDS = maxForwardsHeader; |
| @Deprecated("Use pragmaHeader instead") |
| static const PRAGMA = pragmaHeader; |
| @Deprecated("Use proxyAuthenticateHeader instead") |
| static const PROXY_AUTHENTICATE = proxyAuthenticateHeader; |
| @Deprecated("Use proxyAuthorizationHeader instead") |
| static const PROXY_AUTHORIZATION = proxyAuthorizationHeader; |
| @Deprecated("Use rangeHeader instead") |
| static const RANGE = rangeHeader; |
| @Deprecated("Use refererHeader instead") |
| static const REFERER = refererHeader; |
| @Deprecated("Use retryAfterHeader instead") |
| static const RETRY_AFTER = retryAfterHeader; |
| @Deprecated("Use serverHeader instead") |
| static const SERVER = serverHeader; |
| @Deprecated("Use teHeader instead") |
| static const TE = teHeader; |
| @Deprecated("Use trailerHeader instead") |
| static const TRAILER = trailerHeader; |
| @Deprecated("Use transferEncodingHeader instead") |
| static const TRANSFER_ENCODING = transferEncodingHeader; |
| @Deprecated("Use upgradeHeader instead") |
| static const UPGRADE = upgradeHeader; |
| @Deprecated("Use userAgentHeader instead") |
| static const USER_AGENT = userAgentHeader; |
| @Deprecated("Use varyHeader instead") |
| static const VARY = varyHeader; |
| @Deprecated("Use viaHeader instead") |
| static const VIA = viaHeader; |
| @Deprecated("Use warningHeader instead") |
| static const WARNING = warningHeader; |
| @Deprecated("Use wwwAuthenticateHeader instead") |
| static const WWW_AUTHENTICATE = wwwAuthenticateHeader; |
| |
| // Cookie headers from RFC 6265. |
| static const cookieHeader = "cookie"; |
| static const setCookieHeader = "set-cookie"; |
| |
| @Deprecated("Use cookieHeader instead") |
| static const COOKIE = cookieHeader; |
| @Deprecated("Use setCookieHeader instead") |
| static const SET_COOKIE = setCookieHeader; |
| |
| // TODO(39783): Document this. |
| static const generalHeaders = [ |
| cacheControlHeader, |
| connectionHeader, |
| dateHeader, |
| pragmaHeader, |
| trailerHeader, |
| transferEncodingHeader, |
| upgradeHeader, |
| viaHeader, |
| warningHeader |
| ]; |
| |
| @Deprecated("Use generalHeaders instead") |
| static const GENERAL_HEADERS = generalHeaders; |
| |
| static const entityHeaders = [ |
| allowHeader, |
| contentEncodingHeader, |
| contentLanguageHeader, |
| contentLengthHeader, |
| contentLocationHeader, |
| contentMD5Header, |
| contentRangeHeader, |
| contentTypeHeader, |
| expiresHeader, |
| lastModifiedHeader |
| ]; |
| |
| @Deprecated("Use entityHeaders instead") |
| static const ENTITY_HEADERS = entityHeaders; |
| |
| static const responseHeaders = [ |
| acceptRangesHeader, |
| ageHeader, |
| etagHeader, |
| locationHeader, |
| proxyAuthenticateHeader, |
| retryAfterHeader, |
| serverHeader, |
| varyHeader, |
| wwwAuthenticateHeader |
| ]; |
| |
| @Deprecated("Use responseHeaders instead") |
| static const RESPONSE_HEADERS = responseHeaders; |
| |
| static const requestHeaders = [ |
| acceptHeader, |
| acceptCharsetHeader, |
| acceptEncodingHeader, |
| acceptLanguageHeader, |
| authorizationHeader, |
| expectHeader, |
| fromHeader, |
| hostHeader, |
| ifMatchHeader, |
| ifModifiedSinceHeader, |
| ifNoneMatchHeader, |
| ifRangeHeader, |
| ifUnmodifiedSinceHeader, |
| maxForwardsHeader, |
| proxyAuthorizationHeader, |
| rangeHeader, |
| refererHeader, |
| teHeader, |
| userAgentHeader |
| ]; |
| |
| @Deprecated("Use requestHeaders instead") |
| static const REQUEST_HEADERS = requestHeaders; |
| |
| /// The date specified by the [dateHeader] header, if any. |
| DateTime? date; |
| |
| /// The date and time specified by the [expiresHeader] header, if any. |
| DateTime? expires; |
| |
| /// The date and time specified by the [ifModifiedSinceHeader] header, if any. |
| DateTime? ifModifiedSince; |
| |
| /// The value of the [hostHeader] header, if any. |
| String? host; |
| |
| /// The value of the port part of the [hostHeader] header, if any. |
| int? port; |
| |
| /// The [ContentType] of the [contentTypeHeader] header, if any. |
| ContentType? contentType; |
| |
| /// The value of the [contentLengthHeader] header, if any. |
| /// |
| /// The value is negative if there is no content length set. |
| int contentLength = -1; |
| |
| /// Whether the connection is persistent (keep-alive). |
| late bool persistentConnection; |
| |
| /// Whether the connection uses chunked transfer encoding. |
| /// |
| /// Reflects and modifies the value of the [transferEncodingHeader] header. |
| late bool chunkedTransferEncoding; |
| |
| /// The values for the header named [name]. |
| /// |
| /// Returns null if there is no header with the provided name, |
| /// otherwise returns a new list containing the current values. |
| /// Not that modifying the list does not change the header. |
| List<String>? operator [](String name); |
| |
| /// Convenience method for the value for a single valued header. |
| /// |
| /// The value must not have more than one value. |
| /// |
| /// Returns `null` if there is no header with the provided name. |
| String? value(String name); |
| |
| /// Adds a header value. |
| /// |
| /// The header named [name] will have a string value derived from [value] |
| /// added to its list of values. |
| /// |
| /// Some headers are single valued, and for these, adding a value will |
| /// replace a previous value. If the [value] is a [DateTime], an |
| /// HTTP date format will be applied. If the value is an [Iterable], |
| /// each element will be added separately. For all other |
| /// types the default [Object.toString] method will be used. |
| /// |
| /// Header names are converted to lower-case unless |
| /// [preserveHeaderCase] is set to true. If two header names are |
| /// the same when converted to lower-case, they are considered to be |
| /// the same header, with one set of values. |
| /// |
| /// The current case of the a header name is that of the name used by |
| /// the last [set] or [add] call for that header. |
| void add(String name, Object value, |
| {@Since("2.8") bool preserveHeaderCase = false}); |
| |
| /// Sets the header [name] to [value]. |
| /// |
| /// Removes all existing values for the header named [name] and |
| /// then [add]s [value] to it. |
| void set(String name, Object value, |
| {@Since("2.8") bool preserveHeaderCase = false}); |
| |
| /// Removes a specific value for a header name. |
| /// |
| /// Some headers have system supplied values which cannot be removed. |
| /// For all other headers and values, the [value] is converted to a string |
| /// in the same way as for [add], then that string value is removed from the |
| /// current values of [name]. |
| /// If there are no remaining values for [name], the header is no longer |
| /// considered present. |
| void remove(String name, Object value); |
| |
| /// Removes all values for the specified header name. |
| /// |
| /// Some headers have system supplied values which cannot be removed. |
| /// All other values for [name] are removed. |
| /// If there are no remaining values for [name], the header is no longer |
| /// considered present. |
| void removeAll(String name); |
| |
| /// Performs the [action] on each header. |
| /// |
| /// The [action] function is called with each header's name and a list |
| /// of the header's values. The casing of the name string is determined by |
| /// the last [add] or [set] operation for that particular header, |
| /// which defaults to lower-casing the header name unless explicitly |
| /// set to preserve the case. |
| void forEach(void Function(String name, List<String> values) action); |
| |
| /// Disables folding for the header named [name] when sending the HTTP header. |
| /// |
| /// By default, multiple header values are folded into a |
| /// single header line by separating the values with commas. |
| /// |
| /// The 'set-cookie' header has folding disabled by default. |
| void noFolding(String name); |
| |
| /// Removes all headers. |
| /// |
| /// Some headers have system supplied values which cannot be removed. |
| /// All other header values are removed, and header names with not |
| /// remaining values are no longer considered present. |
| void clear(); |
| } |
| |
| /// Representation of a header value in the form: |
| /// ```plaintext |
| /// value; parameter1=value1; parameter2=value2 |
| /// ``` |
| /// |
| /// [HeaderValue] can be used to conveniently build and parse header |
| /// values on this form. |
| /// |
| /// Parameter values can be omitted, in which case the value is parsed as `null`. |
| /// Values can be doubled quoted to allow characters outside of the RFC 7230 |
| /// token characters and backslash sequences can be used to represent the double |
| /// quote and backslash characters themselves. |
| /// |
| /// To build an "accepts" header with the value |
| /// |
| /// text/plain; q=0.3, text/html |
| /// |
| /// use code like this: |
| /// |
| /// HttpClientRequest request = ...; |
| /// var v = HeaderValue("text/plain", {"q": "0.3"}); |
| /// request.headers.add(HttpHeaders.acceptHeader, v); |
| /// request.headers.add(HttpHeaders.acceptHeader, "text/html"); |
| /// |
| /// To parse the header values use the [parse] static method. |
| /// |
| /// HttpRequest request = ...; |
| /// List<String> values = request.headers[HttpHeaders.acceptHeader]; |
| /// values.forEach((value) { |
| /// HeaderValue v = HeaderValue.parse(value); |
| /// // Use v.value and v.parameters |
| /// }); |
| /// |
| /// An instance of [HeaderValue] is immutable. |
| abstract class HeaderValue { |
| /// Creates a new header value object setting the value and parameters. |
| factory HeaderValue( |
| [String value = "", Map<String, String?> parameters = const {}]) { |
| return _HeaderValue(value, parameters); |
| } |
| |
| /// Creates a new header value object from parsing a header value |
| /// string with both value and optional parameters. |
| static HeaderValue parse(String value, |
| {String parameterSeparator = ";", |
| String? valueSeparator, |
| bool preserveBackslash = false}) { |
| return _HeaderValue.parse(value, |
| parameterSeparator: parameterSeparator, |
| valueSeparator: valueSeparator, |
| preserveBackslash: preserveBackslash); |
| } |
| |
| /// The value of the header. |
| String get value; |
| |
| /// A map of parameters. |
| /// |
| /// This map cannot be modified. |
| Map<String, String?> get parameters; |
| |
| /// Returns the formatted string representation in the form: |
| /// ```plaintext |
| /// value; parameter1=value1; parameter2=value2 |
| /// ``` |
| String toString(); |
| } |
| |
| /// The [session][HttpRequest.session] of an [HttpRequest]. |
| abstract class HttpSession implements Map { |
| /// The id of the current session. |
| String get id; |
| |
| /// Destroys the session. |
| /// |
| /// This terminates the session and any further |
| /// connections with this id will be given a new id and session. |
| void destroy(); |
| |
| /// Sets a callback that will be called when the session is timed out. |
| /// |
| /// Calling this again will overwrite the previous value. |
| void set onTimeout(void Function() callback); |
| |
| /// Whether the session has not yet been sent to the client. |
| bool get isNew; |
| } |
| |
| /// A MIME/IANA media type used as the value of the |
| /// [HttpHeaders.contentTypeHeader] header. |
| /// |
| /// A [ContentType] is immutable. |
| abstract class ContentType implements HeaderValue { |
| /// Content type for plain text using UTF-8 encoding. |
| /// |
| /// text/plain; charset=utf-8 |
| static final text = ContentType("text", "plain", charset: "utf-8"); |
| @Deprecated("Use text instead") |
| static final TEXT = text; |
| |
| /// Content type for HTML using UTF-8 encoding. |
| /// |
| /// text/html; charset=utf-8 |
| static final html = ContentType("text", "html", charset: "utf-8"); |
| @Deprecated("Use html instead") |
| static final HTML = html; |
| |
| /// Content type for JSON using UTF-8 encoding. |
| /// |
| /// application/json; charset=utf-8 |
| static final json = ContentType("application", "json", charset: "utf-8"); |
| @Deprecated("Use json instead") |
| static final JSON = json; |
| |
| /// Content type for binary data. |
| /// |
| /// application/octet-stream |
| static final binary = ContentType("application", "octet-stream"); |
| @Deprecated("Use binary instead") |
| static final BINARY = binary; |
| |
| /// Creates a new content type object setting the primary type and |
| /// sub type. The charset and additional parameters can also be set |
| /// using [charset] and [parameters]. If charset is passed and |
| /// [parameters] contains charset as well the passed [charset] will |
| /// override the value in parameters. Keys passed in parameters will be |
| /// converted to lower case. The `charset` entry, whether passed as `charset` |
| /// or in `parameters`, will have its value converted to lower-case. |
| factory ContentType(String primaryType, String subType, |
| {String? charset, Map<String, String?> parameters = const {}}) { |
| return _ContentType(primaryType, subType, charset, parameters); |
| } |
| |
| /// Creates a new content type object from parsing a Content-Type |
| /// header value. As primary type, sub type and parameter names and |
| /// values are not case sensitive all these values will be converted |
| /// to lower case. Parsing this string |
| /// |
| /// text/html; charset=utf-8 |
| /// |
| /// will create a content type object with primary type "text", |
| /// subtype "html" and parameter "charset" with value "utf-8". |
| /// There may be more parameters supplied, but they are not recognized |
| /// by this class. |
| static ContentType parse(String value) { |
| return _ContentType.parse(value); |
| } |
| |
| /// Gets the MIME type and subtype, without any parameters. |
| /// |
| /// For the full content type `text/html;charset=utf-8`, |
| /// the [mimeType] value is the string `text/html`. |
| String get mimeType; |
| |
| /// Gets the primary type. |
| /// |
| /// For the full content type `text/html;charset=utf-8`, |
| /// the [primaryType] value is the string `text`. |
| String get primaryType; |
| |
| /// Gets the subtype. |
| /// |
| /// For the full content type `text/html;charset=utf-8`, |
| /// the [subType] value is the string `html`. |
| /// May be the empty string. |
| String get subType; |
| |
| /// Gets the character set, if any. |
| /// |
| /// For the full content type `text/html;charset=utf-8`, |
| /// the [charset] value is the string `utf-8`. |
| String? get charset; |
| } |
| |
| /// Representation of a cookie. For cookies received by the server as Cookie |
| /// header values only [name] and [value] properties will be set. When building a |
| /// cookie for the 'set-cookie' header in the server and when receiving cookies |
| /// in the client as 'set-cookie' headers all fields can be used. |
| abstract class Cookie { |
| /// The name of the cookie. |
| /// |
| /// Must be a `token` as specified in RFC 6265. |
| /// |
| /// The allowed characters in a `token` are the visible ASCII characters, |
| /// U+0021 (`!`) through U+007E (`~`), except the separator characters: |
| /// `(`, `)`, `<`, `>`, `@`, `,`, `;`, `:`, `\`, `"`, `/`, `[`, `]`, `?`, `=`, |
| /// `{`, and `}`. |
| late String name; |
| |
| /// The value of the cookie. |
| /// |
| /// Must be a `cookie-value` as specified in RFC 6265. |
| /// |
| /// The allowed characters in a cookie value are the visible ASCII characters, |
| /// U+0021 (`!`) through U+007E (`~`) except the characters: |
| /// `"`, `,`, `;` and `\`. |
| /// Cookie values may be wrapped in a single pair of double quotes |
| /// (U+0022, `"`). |
| late String value; |
| |
| /// The time at which the cookie expires. |
| DateTime? expires; |
| |
| /// The number of seconds until the cookie expires. A zero or negative value |
| /// means the cookie has expired. |
| int? maxAge; |
| |
| /// The domain that the cookie applies to. |
| String? domain; |
| |
| /// The path within the [domain] that the cookie applies to. |
| String? path; |
| |
| /// Whether to only send this cookie on secure connections. |
| bool secure = false; |
| |
| /// Whether the cookie is only sent in the HTTP request and is not made |
| /// available to client side scripts. |
| bool httpOnly = false; |
| |
| /// Creates a new cookie setting the name and value. |
| /// |
| /// [name] and [value] must be composed of valid characters according to RFC |
| /// 6265. |
| /// |
| /// By default the value of `httpOnly` will be set to `true`. |
| factory Cookie(String name, String value) => _Cookie(name, value); |
| |
| /// Creates a new cookie by parsing a header value from a 'set-cookie' |
| /// header. |
| factory Cookie.fromSetCookieValue(String value) { |
| return _Cookie.fromSetCookieValue(value); |
| } |
| |
| /// Returns the formatted string representation of the cookie. The |
| /// string representation can be used for setting the Cookie or |
| /// 'set-cookie' headers |
| String toString(); |
| } |
| |
| /// A server-side object |
| /// that contains the content of and information about an HTTP request. |
| /// |
| /// `HttpRequest` objects are generated by an [HttpServer], |
| /// which listens for HTTP requests on a specific host and port. |
| /// For each request received, the HttpServer, which is a [Stream], |
| /// generates an `HttpRequest` object and adds it to the stream. |
| /// |
| /// An `HttpRequest` object delivers the body content of the request |
| /// as a stream of byte lists. |
| /// The object also contains information about the request, |
| /// such as the method, URI, and headers. |
| /// |
| /// In the following code, an HttpServer listens |
| /// for HTTP requests. When the server receives a request, |
| /// it uses the HttpRequest object's `method` property to dispatch requests. |
| /// |
| /// final HOST = InternetAddress.loopbackIPv4; |
| /// final PORT = 80; |
| /// |
| /// HttpServer.bind(HOST, PORT).then((_server) { |
| /// _server.listen((HttpRequest request) { |
| /// switch (request.method) { |
| /// case 'GET': |
| /// handleGetRequest(request); |
| /// break; |
| /// case 'POST': |
| /// ... |
| /// } |
| /// }, |
| /// onError: handleError); // listen() failed. |
| /// }).catchError(handleError); |
| /// |
| /// 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; |
| /// res.write('Received request ${req.method}: ${req.uri.path}'); |
| /// res.close(); |
| /// } |
| abstract class HttpRequest implements Stream<Uint8List> { |
| /// The content length of the request body. |
| /// |
| /// If the size of the request body is not known in advance, |
| /// this value is -1. |
| int get contentLength; |
| |
| /// The method, such as 'GET' or 'POST', for the request. |
| String get method; |
| |
| /// The URI for the request. |
| /// |
| /// This provides access to the |
| /// path and query string for the request. |
| Uri get uri; |
| |
| /// The requested URI for the request. |
| /// |
| /// The returned URI is reconstructed by using http-header fields, to access |
| /// otherwise lost information, e.g. host and scheme. |
| /// |
| /// To reconstruct the scheme, first 'X-Forwarded-Proto' is checked, and then |
| /// falling back to server type. |
| /// |
| /// To reconstruct the host, first 'X-Forwarded-Host' is checked, then 'Host' |
| /// and finally calling back to server. |
| Uri get requestedUri; |
| |
| /// The request headers. |
| /// |
| /// The returned [HttpHeaders] are immutable. |
| HttpHeaders get headers; |
| |
| /// The cookies in the request, from the "Cookie" headers. |
| List<Cookie> get cookies; |
| |
| /// The persistent connection state signaled by the client. |
| bool get persistentConnection; |
| |
| /// The client certificate of the client making the request. |
| /// |
| /// This value is null if the connection is not a secure TLS or SSL connection, |
| /// or if the server does not request a client certificate, or if the client |
| /// does not provide one. |
| X509Certificate? get certificate; |
| |
| /// The session for the given request. |
| /// |
| /// If the session is being initialized by this call, |
| /// [HttpSession.isNew] is true for the returned session. |
| /// See [HttpServer.sessionTimeout] on how to change default timeout. |
| HttpSession get session; |
| |
| /// The HTTP protocol version used in the request, |
| /// either "1.0" or "1.1". |
| String get protocolVersion; |
| |
| /// Information about the client connection. |
| /// |
| /// Returns `null` if the socket is not available. |
| HttpConnectionInfo? get connectionInfo; |
| |
| /// The [HttpResponse] object, used for sending back the response to the |
| /// client. |
| /// |
| /// If the [contentLength] of the body isn't 0, and the body isn't being read, |
| /// any write calls on the [HttpResponse] automatically drain the request |
| /// body. |
| HttpResponse get response; |
| } |
| |
| /// 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 = ... |
| /// response.headers.contentType |
| /// = ContentType("application", "json", charset: "utf-8"); |
| /// response.write(...); // Strings written will be UTF-8 encoded. |
| /// |
| /// If no charset is provided the default of ISO-8859-1 (Latin 1) will |
| /// be used. |
| /// |
| /// HttpResponse response = ... |
| /// response.headers.add(HttpHeaders.contentTypeHeader, "text/plain"); |
| /// response.write(...); // Strings written will be ISO-8859-1 encoded. |
| /// |
| /// 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. |
| /// Gets and sets the content length of the response. If the size of |
| /// the response is not known in advance set the content length to |
| /// -1, which is also the default if not set. |
| int contentLength = -1; |
| |
| /// The status code of the response. |
| /// |
| /// Any integer value is accepted. For |
| /// the official HTTP status codes use the fields from |
| /// [HttpStatus]. If no status code is explicitly set the default |
| /// value [HttpStatus.ok] is used. |
| /// |
| /// The status code must be set before the body is written |
| /// to. Setting the status code after writing to the response body or |
| /// closing the response will throw a `StateError`. |
| int statusCode = HttpStatus.ok; |
| |
| /// The reason phrase for the response. |
| /// |
| /// If no reason phrase is explicitly set, a default reason phrase is provided. |
| /// |
| /// The reason phrase must be set before the body is written |
| /// to. Setting the reason phrase after writing to the response body |
| /// or closing the response will throw a [StateError]. |
| late String reasonPhrase; |
| |
| /// Gets and sets the persistent connection state. The initial value |
| /// of this property is the persistent connection state from the |
| /// request. |
| late bool persistentConnection; |
| |
| /// Set and get the [deadline] for the response. The deadline is timed from the |
| /// time it's set. Setting a new deadline will override any previous deadline. |
| /// When a deadline is exceeded, the response will be closed and any further |
| /// data ignored. |
| /// |
| /// To disable a deadline, set the [deadline] to `null`. |
| /// |
| /// The [deadline] is `null` by default. |
| Duration? deadline; |
| |
| /// Gets or sets if the [HttpResponse] should buffer output. |
| /// |
| /// Default value is `true`. |
| /// |
| /// __Note__: Disabling buffering of the output can result in very poor |
| /// performance, when writing many small chunks. |
| bool bufferOutput = true; |
| |
| /// Returns the response headers. |
| /// |
| /// The response headers can be modified until the response body is |
| /// written to or closed. After that they become immutable. |
| HttpHeaders get headers; |
| |
| /// Cookies to set in the client (in the 'set-cookie' header). |
| List<Cookie> get cookies; |
| |
| /// Respond with a redirect to [location]. |
| /// |
| /// The URI in [location] should be absolute, but there are no checks |
| /// to enforce that. |
| /// |
| /// By default the HTTP status code `HttpStatus.movedTemporarily` |
| /// (`302`) is used for the redirect, but an alternative one can be |
| /// specified using the [status] argument. |
| /// |
| /// This method will also call `close`, and the returned future is |
| /// the future returned by `close`. |
| Future redirect(Uri location, {int status = HttpStatus.movedTemporarily}); |
| |
| /// Detaches the underlying socket from the HTTP server. When the |
| /// socket is detached the HTTP server will no longer perform any |
| /// operations on it. |
| /// |
| /// This is normally used when a HTTP upgrade request is received |
| /// and the communication should continue with a different protocol. |
| /// |
| /// If [writeHeaders] is `true`, the status line and [headers] will be written |
| /// to the socket before it's detached. If `false`, the socket is detached |
| /// immediately, without any data written to the socket. Default is `true`. |
| Future<Socket> detachSocket({bool writeHeaders = true}); |
| |
| /// Gets information about the client connection. Returns `null` if the |
| /// socket is not available. |
| HttpConnectionInfo? get connectionInfo; |
| } |
| |
| /// An HTTP client for communicating with an HTTP server. |
| /// |
| /// Sends HTTP requests to an HTTP server and receives responses. |
| /// Maintains state, including session cookies and other cookies, |
| /// between multiple requests to the same server. |
| /// |
| /// Note: [HttpClient] provides low-level HTTP functionality. |
| /// We recommend users start with more developer-friendly and composable APIs |
| /// found in [`package:http`](https://pub.dev/packages/http). |
| /// |
| /// 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. |
| /// |
| /// ## Making a simple GET request: an example |
| /// |
| /// 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 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. |
| /// |
| /// ```dart import:convert |
| /// var client = HttpClient(); |
| /// try { |
| /// HttpClientRequest request = await client.get('localhost', 80, '/file.txt'); |
| /// // Optionally set up headers... |
| /// // Optionally write to the request object... |
| /// HttpClientResponse response = await request.close(); |
| /// // Process the response |
| /// final stringData = await response.transform(utf8.decoder).join(); |
| /// print(stringData); |
| /// } finally { |
| /// client.close(); |
| /// } |
| /// ``` |
| /// |
| /// The future for [HttpClientRequest] is created by methods such as |
| /// [getUrl] and [open]. |
| /// |
| /// ## HTTPS connections |
| /// |
| /// An `HttpClient` can make HTTPS requests, connecting to a server using |
| /// the TLS (SSL) secure networking protocol. Calling [getUrl] with an |
| /// https: scheme will work automatically, if the server's certificate is |
| /// signed by a root CA (certificate authority) on the default list of |
| /// well-known trusted CAs, compiled by Mozilla. |
| /// |
| /// To add a custom trusted certificate authority, or to send a client |
| /// certificate to servers that request one, pass a [SecurityContext] object |
| /// as the optional `context` argument to the `HttpClient` constructor. |
| /// The desired security options can be set on the [SecurityContext] object. |
| /// |
| /// ## 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. |
| /// To turn off gzip compression of the response, clear this header: |
| /// |
| /// request.headers.removeAll(HttpHeaders.acceptEncodingHeader) |
| /// |
| /// ## Closing the `HttpClient` |
| /// |
| /// `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 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 set the [findProxy] property to `null`. |
| /// |
| /// HttpClient client = HttpClient(); |
| /// client.findProxy = null; |
| abstract class HttpClient { |
| static const int defaultHttpPort = 80; |
| @Deprecated("Use defaultHttpPort instead") |
| static const int DEFAULT_HTTP_PORT = defaultHttpPort; |
| |
| static const int defaultHttpsPort = 443; |
| @Deprecated("Use defaultHttpsPort instead") |
| static const int DEFAULT_HTTPS_PORT = defaultHttpsPort; |
| |
| /// Enable logging of HTTP requests from all [HttpClient]s to the developer |
| /// timeline. |
| /// |
| /// Default is `false`. |
| static set enableTimelineLogging(bool value) { |
| final enabled = valueOfNonNullableParamWithDefault<bool>(value, false); |
| if (enabled != _enableTimelineLogging) { |
| postEvent('HttpTimelineLoggingStateChange', { |
| 'isolateId': Service.getIsolateID(Isolate.current), |
| 'enabled': enabled, |
| }); |
| } |
| _enableTimelineLogging = enabled; |
| } |
| |
| /// Current state of HTTP request logging from all [HttpClient]s to the |
| /// developer timeline. |
| /// |
| /// Default is `false`. |
| static bool get enableTimelineLogging => _enableTimelineLogging; |
| |
| static bool _enableTimelineLogging = false; |
| |
| /// Gets and sets the idle timeout of non-active persistent (keep-alive) |
| /// connections. |
| /// |
| /// The default value is 15 seconds. |
| Duration idleTimeout = const Duration(seconds: 15); |
| |
| /// Gets and sets the connection timeout. |
| /// |
| /// When connecting to a new host exceeds this timeout, a [SocketException] |
| /// is thrown. The timeout applies only to connections initiated after the |
| /// timeout is set. |
| /// |
| /// When this is `null`, the OS default timeout is used. The default is |
| /// `null`. |
| Duration? connectionTimeout; |
| |
| /// Gets and sets the maximum number of live connections, to a single host. |
| /// |
| /// Increasing this number may lower performance and take up unwanted |
| /// system resources. |
| /// |
| /// To disable, set to `null`. |
| /// |
| /// Default is `null`. |
| int? maxConnectionsPerHost; |
| |
| /// Gets and sets whether the body of a response will be automatically |
| /// uncompressed. |
| /// |
| /// The body of an HTTP response can be compressed. In most |
| /// situations providing the un-compressed body is most |
| /// convenient. Therefore the default behavior is to un-compress the |
| /// body. However in some situations (e.g. implementing a transparent |
| /// proxy) keeping the uncompressed stream is required. |
| /// |
| /// NOTE: Headers in the response are never modified. This means |
| /// that when automatic un-compression is turned on the value of the |
| /// header `Content-Length` will reflect the length of the original |
| /// compressed body. Likewise the header `Content-Encoding` will also |
| /// have the original value indicating compression. |
| /// |
| /// NOTE: Automatic un-compression is only performed if the |
| /// `Content-Encoding` header value is `gzip`. |
| /// |
| /// This value affects all responses produced by this client after the |
| /// value is changed. |
| /// |
| /// To disable, set to `false`. |
| /// |
| /// Default is `true`. |
| bool autoUncompress = true; |
| |
| /// Gets and sets the default value of the `User-Agent` header for all requests |
| /// generated by this [HttpClient]. |
| /// |
| /// The default value is `Dart/<version> (dart:io)`. |
| /// |
| /// If the userAgent is set to `null`, no default `User-Agent` header will be |
| /// added to each request. |
| String? userAgent; |
| |
| factory HttpClient({SecurityContext? context}) { |
| HttpOverrides? overrides = HttpOverrides.current; |
| if (overrides == null) { |
| return _HttpClient(context); |
| } |
| return overrides.createHttpClient(context); |
| } |
| |
| /// Opens a HTTP connection. |
| /// |
| /// The HTTP method to use is specified in [method], the server is |
| /// specified using [host] and [port], and the path (including |
| /// a possible query) is specified using [path]. |
| /// The path may also contain a URI fragment, which will be ignored. |
| /// |
| /// The `Host` header for the request will be set to the value [host]:[port] |
| /// (if [host] is an IP address, it will still be used in the `Host` header). |
| /// This can be overridden through the [HttpClientRequest] interface before |
| /// the request is sent. |
| /// |
| /// For additional information on the sequence of events during an |
| /// HTTP transaction, and the objects returned by the futures, see |
| /// the overall documentation for the class [HttpClient]. |
| Future<HttpClientRequest> open( |
| String method, String host, int port, String path); |
| |
| /// Opens a HTTP connection. |
| /// |
| /// The HTTP method is specified in [method] and the URL to use in |
| /// [url]. |
| /// |
| /// The `Host` header for the request will be set to the value |
| /// [Uri.host]:[Uri.port] from [url] (if `url.host` is an IP address, it will |
| /// still be used in the `Host` header). This can be overridden through the |
| /// [HttpClientRequest] interface before the request is sent. |
| /// |
| /// For additional information on the sequence of events during an |
| /// HTTP transaction, and the objects returned by the futures, see |
| /// the overall documentation for the class [HttpClient]. |
| Future<HttpClientRequest> openUrl(String method, Uri url); |
| |
| /// Opens a HTTP connection using the GET method. |
| /// |
| /// The server is specified using [host] and [port], and the path |
| /// (including a possible query) is specified using |
| /// [path]. |
| /// |
| /// See [open] for details. |
| Future<HttpClientRequest> get(String host, int port, String path); |
| |
| /// Opens a HTTP connection using the GET method. |
| /// |
| /// The URL to use is specified in [url]. |
| /// |
| /// See [openUrl] for details. |
| Future<HttpClientRequest> getUrl(Uri url); |
| |
| /// Opens a HTTP connection using the POST method. |
| /// |
| /// The server is specified using [host] and [port], and the path |
| /// (including a possible query) is specified using |
| /// [path]. |
| /// |
| /// See [open] for details. |
| Future<HttpClientRequest> post(String host, int port, String path); |
| |
| /// Opens a HTTP connection using the POST method. |
| /// |
| /// The URL to use is specified in [url]. |
| /// |
| /// See [openUrl] for details. |
| Future<HttpClientRequest> postUrl(Uri url); |
| |
| /// Opens a HTTP connection using the PUT method. |
| /// |
| /// The server is specified using [host] and [port], and the path |
| /// (including a possible query) is specified using [path]. |
| /// |
| /// See [open] for details. |
| Future<HttpClientRequest> put(String host, int port, String path); |
| |
| /// Opens a HTTP connection using the PUT method. |
| /// |
| /// The URL to use is specified in [url]. |
| /// |
| /// See [openUrl] for details. |
| Future<HttpClientRequest> putUrl(Uri url); |
| |
| /// Opens a HTTP connection using the DELETE method. |
| /// |
| /// The server is specified using [host] and [port], and the path |
| /// (including a possible query) is specified using [path]. |
| /// |
| /// See [open] for details. |
| Future<HttpClientRequest> delete(String host, int port, String path); |
| |
| /// Opens a HTTP connection using the DELETE method. |
| /// |
| /// The URL to use is specified in [url]. |
| /// |
| /// See [openUrl] for details. |
| Future<HttpClientRequest> deleteUrl(Uri url); |
| |
| /// Opens a HTTP connection using the PATCH method. |
| /// |
| /// The server is specified using [host] and [port], and the path |
| /// (including a possible query) is specified using [path]. |
| /// |
| /// See [open] for details. |
| Future<HttpClientRequest> patch(String host, int port, String path); |
| |
| /// Opens a HTTP connection using the PATCH method. |
| /// |
| /// The URL to use is specified in [url]. |
| /// |
| /// See [openUrl] for details. |
| Future<HttpClientRequest> patchUrl(Uri url); |
| |
| /// Opens a HTTP connection using the HEAD method. |
| /// |
| /// The server is specified using [host] and [port], and the path |
| /// (including a possible query) is specified using [path]. |
| /// |
| /// See [open] for details. |
| Future<HttpClientRequest> head(String host, int port, String path); |
| |
| /// Opens a HTTP connection using the HEAD method. |
| /// |
| /// The URL to use is specified in [url]. |
| /// |
| /// See [openUrl] for details. |
| Future<HttpClientRequest> headUrl(Uri url); |
| |
| /// Sets the function to be called when a site is requesting |
| /// authentication. |
| /// |
| /// The URL requested, the authentication scheme and the security realm |
| /// from the server are passed in the arguments [f.url], [f.scheme] and |
| /// [f.realm]. |
| /// |
| /// The function returns a [Future] which should complete when the |
| /// authentication has been resolved. If credentials cannot be |
| /// provided the [Future] should complete with `false`. If |
| /// credentials are available the function should add these using |
| /// [addCredentials] before completing the [Future] with the value |
| /// `true`. |
| /// |
| /// If the [Future] completes with `true` the request will be retried |
| /// using the updated credentials, however, the retried request will not |
| /// carry the original request payload. Otherwise response processing will |
| /// continue normally. |
| /// |
| /// If it is known that the remote server requires authentication for all |
| /// requests, it is advisable to use [addCredentials] directly, or manually |
| /// set the `'authorization'` header on the request to avoid the overhead |
| /// of a failed request, or issues due to missing request payload on retried |
| /// request. |
| void set authenticate( |
| Future<bool> Function(Uri url, String scheme, String? realm)? f); |
| |
| /// Add credentials to be used for authorizing HTTP requests. |
| void addCredentials(Uri url, String realm, HttpClientCredentials credentials); |
| |
| /// Sets the function used to create socket connections. |
| /// |
| /// The URL requested (e.g. through [getUrl]) and proxy configuration |
| /// ([f.proxyHost] and [f.proxyPort]) are passed as arguments. [f.proxyHost] |
| /// and [f.proxyPort] will be `null` if the connection is not made through |
| /// a proxy. |
| /// |
| /// Since connections may be reused based on host and port, it is important |
| /// that the function not ignore [f.proxyHost] and [f.proxyPort] if they are |
| /// not `null`. If proxies are not meaningful for the returned [Socket], you |
| /// can set [findProxy] to use a direct connection. |
| /// |
| /// For example: |
| /// |
| /// ```dart |
| /// import "dart:io"; |
| /// |
| /// void main() async { |
| /// HttpClient client = HttpClient() |
| /// ..connectionFactory = (Uri uri, String? proxyHost, int? proxyPort) { |
| /// assert(proxyHost == null); |
| /// assert(proxyPort == null); |
| /// var address = InternetAddress("/var/run/docker.sock", |
| /// type: InternetAddressType.unix); |
| /// return Socket.startConnect(address, 0); |
| /// } |
| /// ..findProxy = (Uri uri) => 'DIRECT'; |
| /// |
| /// final request = await client.getUrl(Uri.parse("http://ignored/v1.41/info")); |
| /// final response = await request.close(); |
| /// print(response.statusCode); |
| /// await response.drain(); |
| /// client.close(); |
| /// } |
| /// ``` |
| void set connectionFactory( |
| Future<ConnectionTask<Socket>> Function( |
| Uri url, String? proxyHost, int? proxyPort)? |
| f); |
| |
| /// Sets the function used to resolve the proxy server to be used for |
| /// opening a HTTP connection to the specified [url]. If this |
| /// function is not set, direct connections will always be used. |
| /// |
| /// The string returned by [f] must be in the format used by browser |
| /// PAC (proxy auto-config) scripts. That is either |
| /// |
| /// "DIRECT" |
| /// |
| /// for using a direct connection or |
| /// |
| /// "PROXY host:port" |
| /// |
| /// for using the proxy server `host` on port `port`. |
| /// |
| /// A configuration can contain several configuration elements |
| /// separated by semicolons, e.g. |
| /// |
| /// "PROXY host:port; PROXY host2:port2; DIRECT" |
| /// |
| /// The static function [findProxyFromEnvironment] on this class can |
| /// be used to implement proxy server resolving based on environment |
| /// variables. |
| void set findProxy(String Function(Uri url)? f); |
| |
| /// Function for resolving the proxy server to be used for a HTTP |
| /// connection from the proxy configuration specified through |
| /// environment variables. |
| /// |
| /// The following environment variables are taken into account: |
| /// |
| /// http_proxy |
| /// https_proxy |
| /// no_proxy |
| /// HTTP_PROXY |
| /// HTTPS_PROXY |
| /// NO_PROXY |
| /// |
| /// [:http_proxy:] and [:HTTP_PROXY:] specify the proxy server to use for |
| /// http:// urls. Use the format [:hostname:port:]. If no port is used a |
| /// default of 1080 will be used. If both are set the lower case one takes |
| /// precedence. |
| /// |
| /// [:https_proxy:] and [:HTTPS_PROXY:] specify the proxy server to use for |
| /// https:// urls. Use the format [:hostname:port:]. If no port is used a |
| /// default of 1080 will be used. If both are set the lower case one takes |
| /// precedence. |
| /// |
| /// [:no_proxy:] and [:NO_PROXY:] specify a comma separated list of |
| /// postfixes of hostnames for which not to use the proxy |
| /// server. E.g. the value "localhost,127.0.0.1" will make requests |
| /// to both "localhost" and "127.0.0.1" not use a proxy. If both are set |
| /// the lower case one takes precedence. |
| /// |
| /// To activate this way of resolving proxies assign this function to |
| /// the [findProxy] property on the [HttpClient]. |
| /// |
| /// HttpClient client = HttpClient(); |
| /// client.findProxy = HttpClient.findProxyFromEnvironment; |
| /// |
| /// If you don't want to use the system environment you can use a |
| /// different one by wrapping the function. |
| /// |
| /// HttpClient client = HttpClient(); |
| /// client.findProxy = (url) { |
| /// return HttpClient.findProxyFromEnvironment( |
| /// url, environment: {"http_proxy": ..., "no_proxy": ...}); |
| /// } |
| /// |
| /// If a proxy requires authentication it is possible to configure |
| /// the username and password as well. Use the format |
| /// [:username:password@hostname:port:] to include the username and |
| /// password. Alternatively the API [addProxyCredentials] can be used |
| /// to set credentials for proxies which require authentication. |
| static String findProxyFromEnvironment(Uri url, |
| {Map<String, String>? environment}) { |
| HttpOverrides? overrides = HttpOverrides.current; |
| if (overrides == null) { |
| return _HttpClient._findProxyFromEnvironment(url, environment); |
| } |
| return overrides.findProxyFromEnvironment(url, environment); |
| } |
| |
| /// Sets the function to be called when a proxy is requesting |
| /// authentication. |
| /// |
| /// Information on the proxy in use, the authentication scheme |
| /// and the security realm for the authentication |
| /// are passed in the arguments [f.host], [f.port], [f.scheme] and [f.realm]. |
| /// |
| /// The function returns a [Future] which should complete when the |
| /// authentication has been resolved. If credentials cannot be |
| /// provided the [Future] should complete with `false`. If |
| /// credentials are available the function should add these using |
| /// [addProxyCredentials] before completing the [Future] with the value |
| /// `true`. |
| /// |
| /// If the [Future] completes with `true` the request will be retried |
| /// using the updated credentials. Otherwise response processing will |
| /// continue normally. |
| void set authenticateProxy( |
| Future<bool> Function( |
| String host, int port, String scheme, String? realm)? |
| f); |
| |
| /// Add credentials to be used for authorizing HTTP proxies. |
| void addProxyCredentials( |
| String host, int port, String realm, HttpClientCredentials credentials); |
| |
| /// Sets a callback that will decide whether to accept a secure connection |
| /// with a server certificate that cannot be authenticated by any of our |
| /// trusted root certificates. |
| /// |
| /// When an secure HTTP request if made, using this HttpClient, and the |
| /// server returns a server certificate that cannot be authenticated, the |
| /// callback is called asynchronously with the [X509Certificate] object and |
| /// the server's hostname and port. If the value of [badCertificateCallback] |
| /// is `null`, the bad certificate is rejected, as if the callback |
| /// returned `false` |
| /// |
| /// If the callback returns true, the secure connection is accepted and the |
| /// `Future<HttpClientRequest>` that was returned from the call making the |
| /// request completes with a valid HttpRequest object. If the callback returns |
| /// false, the `Future<HttpClientRequest>` completes with an exception. |
| /// |
| /// If a bad certificate is received on a connection attempt, the library calls |
| /// the function that was the value of badCertificateCallback at the time |
| /// the request is made, even if the value of badCertificateCallback |
| /// has changed since then. |
| void set badCertificateCallback( |
| bool Function(X509Certificate cert, String host, int port)? callback); |
| |
| /// Sets a callback that will be called when new TLS keys are exchanged with |
| /// the server. It will receive one line of text in |
| /// [NSS Key Log Format](https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format) |
| /// for each call. Writing these lines to a file will allow tools (such as |
| /// [Wireshark](https://gitlab.com/wireshark/wireshark/-/wikis/TLS#tls-decryption)) |
| /// to decrypt communication between the this client and the server. This is |
| /// meant to allow network-level debugging of secure sockets and should not |
| /// be used in production code. For example: |
| /// |
| /// final log = File('keylog.txt'); |
| /// final client = HttpClient(); |
| /// client.keyLog = (line) => log.writeAsStringSync(line, |
| /// mode: FileMode.append); |
| void set keyLog(Function(String line)? callback); |
| |
| /// Shuts down the HTTP client. |
| /// |
| /// If [force] is `false` (the default) the [HttpClient] will be kept alive |
| /// until all active connections are done. If [force] is `true` any active |
| /// connections will be closed to immediately release all resources. These |
| /// closed connections will receive an error event to indicate that the client |
| /// was shut down. In both cases trying to establish a new connection after |
| /// calling [close] will throw an exception. |
| void close({bool force = false}); |
| } |
| |
| /// HTTP request for a client connection. |
| /// |
| /// 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 is determined from the "charset" parameter of |
| /// the "Content-Type" header. |
| /// |
| /// ```dart import:convert |
| /// var client = HttpClient(); |
| /// HttpClientRequest request = await client.get('localhost', 80, '/file.txt'); |
| /// request.headers.contentType = |
| /// ContentType('application', 'json', charset: 'utf-8'); |
| /// request.write('text content👍🎯'); // Strings written will be UTF-8 encoded. |
| /// ``` |
| /// |
| /// If no charset is provided the default of ISO-8859-1 (Latin 1) is used. |
| /// |
| /// ```dart |
| /// var client = HttpClient(); |
| /// HttpClientRequest request = await client.get('localhost', 80, '/file.txt'); |
| /// request.headers.add(HttpHeaders.contentTypeHeader, "text/plain"); |
| /// request.write('blåbærgrød'); // Strings written will be ISO-8859-1 encoded |
| /// ``` |
| /// |
| /// 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 { |
| /// The requested persistent connection state. |
| /// |
| /// The default value is `true`. |
| bool persistentConnection = true; |
| |
| /// Whether to follow redirects automatically. |
| /// |
| /// Set this property to `false` if this request should not |
| /// automatically follow redirects. The default is `true`. |
| /// |
| /// Automatic redirect will only happen for "GET" and "HEAD" requests |
| /// and only for the status codes [HttpStatus.movedPermanently] |
| /// (301), [HttpStatus.found] (302), |
| /// [HttpStatus.movedTemporarily] (302, alias for |
| /// [HttpStatus.found]), [HttpStatus.seeOther] (303), |
| /// [HttpStatus.temporaryRedirect] (307) and |
| /// [HttpStatus.permanentRedirect] (308). For |
| /// [HttpStatus.seeOther] (303) automatic redirect will also happen |
| /// for "POST" requests with the method changed to "GET" when |
| /// following the redirect. |
| /// |
| /// All headers added to the request will be added to the redirection |
| /// request(s) except when forwarding sensitive headers like |
| /// "Authorization", "WWW-Authenticate", and "Cookie". Those headers |
| /// will be skipped if following a redirect to a domain that is not a |
| /// subdomain match or exact match of the initial domain. |
| /// For example, a redirect from "foo.com" to either "foo.com" or |
| /// "sub.foo.com" will forward the sensitive headers, but a redirect to |
| /// "bar.com" will not. |
| /// |
| /// Any body send with the request will not be part of the redirection |
| /// request(s). |
| /// |
| /// For precise control of redirect handling, set this property to `false` |
| /// and make a separate HTTP request to process the redirect. For example: |
| /// |
| /// ```dart |
| /// final client = HttpClient(); |
| /// var uri = Uri.parse("http://localhost/"); |
| /// var request = await client.getUrl(uri); |
| /// request.followRedirects = false; |
| /// var response = await request.close(); |
| /// while (response.isRedirect) { |
| /// response.drain(); |
| /// final location = response.headers.value(HttpHeaders.locationHeader); |
| /// if (location != null) { |
| /// uri = uri.resolve(location); |
| /// request = await client.getUrl(uri); |
| /// // Set the body or headers as desired. |
| /// request.followRedirects = false; |
| /// response = await request.close(); |
| /// } |
| /// } |
| /// // Do something with the final response. |
| /// ``` |
| bool followRedirects = true; |
| |
| /// Set this property to the maximum number of redirects to follow |
| /// when [followRedirects] is `true`. If this number is exceeded |
| /// an error event will be added with a [RedirectException]. |
| /// |
| /// The default value is 5. |
| int maxRedirects = 5; |
| |
| /// The method of the request. |
| String get method; |
| |
| /// The uri of the request. |
| Uri get uri; |
| |
| /// Gets and sets the content length of the request. |
| /// |
| /// If the size of the request is not known in advance set content length to |
| /// -1, which is also the default. |
| int contentLength = -1; |
| |
| /// Gets or sets if the [HttpClientRequest] should buffer output. |
| /// |
| /// Default value is `true`. |
| /// |
| /// __Note__: Disabling buffering of the output can result in very poor |
| /// performance, when writing many small chunks. |
| bool bufferOutput = true; |
| |
| /// Returns the client request headers. |
| /// |
| /// The client request headers can be modified until the client |
| /// request body is written to or closed. After that they become |
| /// immutable. |
| HttpHeaders get headers; |
| |
| /// Cookies to present to the server (in the 'cookie' header). |
| List<Cookie> get cookies; |
| |
| /// A [HttpClientResponse] future that will complete once the response is |
| /// available. |
| /// |
| /// If an error occurs before the response is available, this future will |
| /// complete with an error. |
| Future<HttpClientResponse> get done; |
| |
| /// Close the request for input. Returns the value of [done]. |
| Future<HttpClientResponse> close(); |
| |
| /// Gets information about the client connection. |
| /// |
| /// Returns `null` if the socket is not available. |
| HttpConnectionInfo? get connectionInfo; |
| |
| /// Aborts the client connection. |
| /// |
| /// If the connection has not yet completed, the request is aborted and the |
| /// [done] future (also returned by [close]) is completed with the provided |
| /// [exception] and [stackTrace]. |
| /// If [exception] is omitted, it defaults to an [HttpException], and if |
| /// [stackTrace] is omitted, it defaults to [StackTrace.empty]. |
| /// |
| /// If the [done] future has already completed, aborting has no effect. |
| /// |
| /// Using the [IOSink] methods (e.g., [write] and [add]) has no effect after |
| /// the request has been aborted |
| /// |
| /// ```dart import:async |
| /// var client = HttpClient(); |
| /// HttpClientRequest request = await client.get('localhost', 80, '/file.txt'); |
| /// request.write('request content'); |
| /// Timer(Duration(seconds: 1), () { |
| /// request.abort(); |
| /// }); |
| /// request.close().then((response) { |
| /// // If response comes back before abort, this callback will be called. |
| /// }, onError: (e) { |
| /// // If abort() called before response is available, onError will fire. |
| /// }); |
| /// ``` |
| @Since("2.10") |
| void abort([Object? exception, StackTrace? stackTrace]); |
| } |
| |
| /// HTTP response for a client connection. |
| /// |
| /// The body of a [HttpClientResponse] object is a [Stream] of data from the |
| /// server. Use [Stream] methods like [`transform`][Stream.transform] and |
| /// [`join`][Stream.join] to access the data. |
| /// |
| /// ```dart import:convert |
| /// var client = HttpClient(); |
| /// try { |
| /// HttpClientRequest request = await client.get('localhost', 80, '/file.txt'); |
| /// HttpClientResponse response = await request.close(); |
| /// final stringData = await response.transform(utf8.decoder).join(); |
| /// print(stringData); |
| /// } finally { |
| /// client.close(); |
| /// } |
| /// ``` |
| abstract class HttpClientResponse implements Stream<List<int>> { |
| /// Returns the status code. |
| /// |
| /// The status code must be set before the body is written |
| /// to. Setting the status code after writing to the body will throw |
| /// a `StateError`. |
| int get statusCode; |
| |
| /// Returns the reason phrase associated with the status code. |
| /// |
| /// The reason phrase must be set before the body is written |
| /// to. Setting the reason phrase after writing to the body will throw |
| /// a `StateError`. |
| String get reasonPhrase; |
| |
| /// Returns the content length of the response body. Returns -1 if the size of |
| /// the response body is not known in advance. |
| /// |
| /// If the content length needs to be set, it must be set before the |
| /// body is written to. Setting the content length after writing to the body |
| /// will throw a `StateError`. |
| int get contentLength; |
| |
| /// The compression state of the response. |
| /// |
| /// This specifies whether the response bytes were compressed when they were |
| /// received across the wire and whether callers will receive compressed |
| /// or uncompressed bytes when they listed to this response's byte stream. |
| @Since("2.4") |
| HttpClientResponseCompressionState get compressionState; |
| |
| /// Gets the persistent connection state returned by the server. |
| /// |
| /// If the persistent connection state needs to be set, it must be |
| /// set before the body is written to. Setting the persistent connection state |
| /// after writing to the body will throw a `StateError`. |
| bool get persistentConnection; |
| |
| /// Returns whether the status code is one of the normal redirect |
| /// codes [HttpStatus.movedPermanently], [HttpStatus.found], |
| /// [HttpStatus.movedTemporarily], [HttpStatus.seeOther] and |
| /// [HttpStatus.temporaryRedirect]. |
| bool get isRedirect; |
| |
| /// Returns the series of redirects this connection has been through. The |
| /// list will be empty if no redirects were followed. [redirects] will be |
| /// updated both in the case of an automatic and a manual redirect. |
| List<RedirectInfo> get redirects; |
| |
| /// Redirects this connection to a new URL. The default value for |
| /// [method] is the method for the current request. The default value |
| /// for [url] is the value of the [HttpHeaders.locationHeader] header of |
| /// the current response. All body data must have been read from the |
| /// current response before calling [redirect]. |
| /// |
| /// All headers added to the request will be added to the redirection |
| /// request. However, any body sent with the request will not be |
| /// part of the redirection request. |
| /// |
| /// If [followLoops] is set to `true`, redirect will follow the redirect, |
| /// even if the URL was already visited. The default value is `false`. |
| /// |
| /// The method will ignore [HttpClientRequest.maxRedirects] |
| /// and will always perform the redirect. |
| Future<HttpClientResponse> redirect( |
| [String? method, Uri? url, bool? followLoops]); |
| |
| /// Returns the client response headers. |
| /// |
| /// The client response headers are immutable. |
| HttpHeaders get headers; |
| |
| /// Detach the underlying socket from the HTTP client. When the |
| /// socket is detached the HTTP client will no longer perform any |
| /// operations on it. |
| /// |
| /// This is normally used when a HTTP upgrade is negotiated and the |
| /// communication should continue with a different protocol. |
| Future<Socket> detachSocket(); |
| |
| /// Cookies set by the server (from the 'set-cookie' header). |
| List<Cookie> get cookies; |
| |
| /// Returns the certificate of the HTTPS server providing the response. |
| /// Returns null if the connection is not a secure TLS or SSL connection. |
| X509Certificate? get certificate; |
| |
| /// Gets information about the client connection. Returns `null` if the socket |
| /// is not available. |
| HttpConnectionInfo? get connectionInfo; |
| } |
| |
| /// Enum that specifies the compression state of the byte stream of an |
| /// [HttpClientResponse]. |
| /// |
| /// The values herein allow callers to answer the following questions as they |
| /// pertain to an [HttpClientResponse]: |
| /// |
| /// * Can the value of the response's `Content-Length` HTTP header be trusted? |
| /// * Does the caller need to manually decompress the response's byte stream? |
| /// |
| /// This enum is accessed via the [HttpClientResponse.compressionState] value. |
| @Since("2.4") |
| enum HttpClientResponseCompressionState { |
| /// The body of the HTTP response was received and remains in an uncompressed |
| /// state. |
| /// |
| /// In this state, the value of the `Content-Length` HTTP header, if |
| /// specified (non-negative), should match the number of bytes produced by |
| /// the response's byte stream. |
| notCompressed, |
| |
| /// The body of the HTTP response was originally compressed, but by virtue of |
| /// the [HttpClient.autoUncompress] configuration option, it has been |
| /// automatically uncompressed. |
| /// |
| /// HTTP headers are not modified, so when a response has been uncompressed |
| /// in this way, the value of the `Content-Length` HTTP header cannot be |
| /// trusted, as it will contain the compressed content length, whereas the |
| /// stream of bytes produced by the response will contain uncompressed bytes. |
| decompressed, |
| |
| /// The body of the HTTP response contains compressed bytes. |
| /// |
| /// In this state, the value of the `Content-Length` HTTP header, if |
| /// specified (non-negative), should match the number of bytes produced by |
| /// the response's byte stream. |
| /// |
| /// If the caller wishes to manually uncompress the body of the response, |
| /// it should consult the value of the `Content-Encoding` HTTP header to see |
| /// what type of compression has been applied. See |
| /// <https://tools.ietf.org/html/rfc2616#section-14.11> for more information. |
| compressed, |
| } |
| |
| abstract class HttpClientCredentials {} |
| |
| /// Represents credentials for basic authentication. |
| abstract class HttpClientBasicCredentials extends HttpClientCredentials { |
| factory HttpClientBasicCredentials(String username, String password) => |
| _HttpClientBasicCredentials(username, password); |
| } |
| |
| /// Represents credentials for digest authentication. Digest |
| /// authentication is only supported for servers using the MD5 |
| /// algorithm and quality of protection (qop) of either "none" or |
| /// "auth". |
| abstract class HttpClientDigestCredentials extends HttpClientCredentials { |
| factory HttpClientDigestCredentials(String username, String password) => |
| _HttpClientDigestCredentials(username, password); |
| } |
| |
| /// Information about an [HttpRequest], [HttpResponse], [HttpClientRequest], or |
| /// [HttpClientResponse] connection. |
| abstract class HttpConnectionInfo { |
| InternetAddress get remoteAddress; |
| int get remotePort; |
| int get localPort; |
| } |
| |
| /// Redirect information. |
| abstract class RedirectInfo { |
| /// Returns the status code used for the redirect. |
| int get statusCode; |
| |
| /// Returns the method used for the redirect. |
| String get method; |
| |
| /// Returns the location for the redirect. |
| Uri get location; |
| } |
| |
| class HttpException implements IOException { |
| final String message; |
| final Uri? uri; |
| |
| const HttpException(this.message, {this.uri}); |
| |
| String toString() { |
| var b = StringBuffer() |
| ..write('HttpException: ') |
| ..write(message); |
| var uri = this.uri; |
| if (uri != null) { |
| b.write(', uri = $uri'); |
| } |
| return b.toString(); |
| } |
| } |
| |
| class RedirectException implements HttpException { |
| final String message; |
| final List<RedirectInfo> redirects; |
| |
| const RedirectException(this.message, this.redirects); |
| |
| String toString() => "RedirectException: $message"; |
| |
| Uri get uri => redirects.last.location; |
| } |