| // 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 | 
 |         checkNotNullable, | 
 |         Since, | 
 |         valueOfNonNullableParamWithDefault, | 
 |         HttpStatus; | 
 | import 'dart:async'; | 
 | import 'dart:async' as dart_async show runZoned; | 
 | 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 'http_testing.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); | 
 |  | 
 |   /// An [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 interface 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"; | 
 |   static const contentDisposition = "content-disposition"; | 
 |  | 
 |   // Cookie headers from RFC 6265. | 
 |   static const cookieHeader = "cookie"; | 
 |   static const setCookieHeader = "set-cookie"; | 
 |  | 
 |   // TODO(39783): Document this. | 
 |   static const generalHeaders = [ | 
 |     cacheControlHeader, | 
 |     connectionHeader, | 
 |     dateHeader, | 
 |     pragmaHeader, | 
 |     trailerHeader, | 
 |     transferEncodingHeader, | 
 |     upgradeHeader, | 
 |     viaHeader, | 
 |     warningHeader, | 
 |   ]; | 
 |  | 
 |   static const entityHeaders = [ | 
 |     allowHeader, | 
 |     contentEncodingHeader, | 
 |     contentLanguageHeader, | 
 |     contentLengthHeader, | 
 |     contentLocationHeader, | 
 |     contentMD5Header, | 
 |     contentRangeHeader, | 
 |     contentTypeHeader, | 
 |     expiresHeader, | 
 |     lastModifiedHeader, | 
 |   ]; | 
 |  | 
 |   static const responseHeaders = [ | 
 |     acceptRangesHeader, | 
 |     ageHeader, | 
 |     etagHeader, | 
 |     locationHeader, | 
 |     proxyAuthenticateHeader, | 
 |     retryAfterHeader, | 
 |     serverHeader, | 
 |     varyHeader, | 
 |     wwwAuthenticateHeader, | 
 |     contentDisposition, | 
 |   ]; | 
 |  | 
 |   static const requestHeaders = [ | 
 |     acceptHeader, | 
 |     acceptCharsetHeader, | 
 |     acceptEncodingHeader, | 
 |     acceptLanguageHeader, | 
 |     authorizationHeader, | 
 |     expectHeader, | 
 |     fromHeader, | 
 |     hostHeader, | 
 |     ifMatchHeader, | 
 |     ifModifiedSinceHeader, | 
 |     ifNoneMatchHeader, | 
 |     ifRangeHeader, | 
 |     ifUnmodifiedSinceHeader, | 
 |     maxForwardsHeader, | 
 |     proxyAuthorizationHeader, | 
 |     rangeHeader, | 
 |     refererHeader, | 
 |     teHeader, | 
 |     userAgentHeader, | 
 |   ]; | 
 |  | 
 |   /// 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 interface 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]. | 
 | /// | 
 | /// Stores arbitrary information about a browser session on the server. This | 
 | /// information is stored in memory so it will be lost when the server exits. | 
 | /// | 
 | /// A cookie named "DARTSESSID" is stored on the browser to associate the | 
 | /// `HttpSession` with a particular client. | 
 | /// | 
 | /// ```dart | 
 | /// import 'dart:io'; | 
 | /// | 
 | /// void main() async { | 
 | ///   HttpServer.bind("localhost", 8080).then((server) { | 
 | ///     server.listen((request) { | 
 | ///       final session = request.session; | 
 | ///       if (session.isNew) { | 
 | ///         session["cart"] = []; | 
 | ///       } | 
 | ///       if (request.uri.queryParameters['buy'] != null) { | 
 | ///         final item = request.uri.queryParameters['buy']; | 
 | ///         session["cart"].add(item); | 
 | ///       } | 
 | ///       session["cart"].cast<String>().forEach(request.response.writeln); | 
 | ///       request.response.close(); | 
 | ///     }); | 
 | ///   }); | 
 | /// } | 
 | /// ``` | 
 | abstract interface 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 interface 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"); | 
 |  | 
 |   /// Content type for HTML using UTF-8 encoding. | 
 |   /// | 
 |   ///    text/html; charset=utf-8 | 
 |   static final html = ContentType("text", "html", charset: "utf-8"); | 
 |  | 
 |   /// Content type for JSON using UTF-8 encoding. | 
 |   /// | 
 |   ///    application/json; charset=utf-8 | 
 |   static final json = ContentType("application", "json", charset: "utf-8"); | 
 |  | 
 |   /// Content type for binary data. | 
 |   /// | 
 |   ///    application/octet-stream | 
 |   static final binary = ContentType("application", "octet-stream"); | 
 |  | 
 |   /// 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; | 
 | } | 
 |  | 
 | /// Cookie cross-site availability configuration. | 
 | /// | 
 | /// The value of [Cookie.sameSite], which defines whether an | 
 | /// HTTP cookie is available from other sites or not. | 
 | /// | 
 | /// Has three possible values: [lax], [strict] and [none]. | 
 | final class SameSite { | 
 |   /// Default value, cookie with this value will generally not be sent on | 
 |   /// cross-site requests, unless the user is navigated to the original site. | 
 |   static const lax = SameSite._("Lax"); | 
 |  | 
 |   /// Cookie with this value will never be sent on cross-site requests. | 
 |   static const strict = SameSite._("Strict"); | 
 |  | 
 |   /// Cookie with this value will be sent in all requests. | 
 |   /// | 
 |   /// [Cookie.secure] must also be set to true, otherwise the `none` value | 
 |   /// will have no effect. | 
 |   static const none = SameSite._("None"); | 
 |  | 
 |   static const List<SameSite> values = [lax, strict, none]; | 
 |  | 
 |   final String name; | 
 |  | 
 |   const SameSite._(this.name); | 
 |  | 
 |   @override | 
 |   String toString() => "SameSite=$name"; | 
 | } | 
 |  | 
 | /// 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 interface 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; | 
 |  | 
 |   /// Whether the cookie is available from other sites. | 
 |   /// | 
 |   /// This value is `null` if the SameSite attribute is not present. | 
 |   /// | 
 |   /// See [SameSite] for more information. | 
 |   SameSite? sameSite; | 
 |  | 
 |   /// 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 interface 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. | 
 |   /// | 
 |   /// If the request URI is absolute (e.g. 'https://www.example.com/foo') then | 
 |   /// it is returned as-is. Otherwise, the returned URI is reconstructed by | 
 |   /// using the request URI path (e.g. '/foo') and HTTP header fields. | 
 |   /// | 
 |   /// To reconstruct the scheme, the 'X-Forwarded-Proto' header is used. If it | 
 |   /// is not present then the socket type of the connection is used i.e. if | 
 |   /// the connection is made through a [SecureSocket] then the scheme is | 
 |   /// 'https', otherwise it is 'http'. | 
 |   /// | 
 |   /// To reconstruct the host, the 'X-Forwarded-Host' header is used. If it is | 
 |   /// not present then the 'Host' header is used. If neither is present then | 
 |   /// the host name of the server is used. | 
 |   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. | 
 | /// | 
 | /// If no "Content-Type" header is set then a default of | 
 | /// "text/plain; charset=utf-8" is used and string data written to the IOSink | 
 | /// will be encoded using UTF-8. | 
 | /// | 
 | /// ## 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. | 
 | /// | 
 | /// If a charset is provided but it is not recognized, then the "Content-Type" | 
 | /// header will include that charset but string data will be encoded using | 
 | /// ISO-8859-1 (Latin 1). | 
 | abstract interface 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. | 
 | /// | 
 | /// > **Note:** You should avoid directly using `HttpClient` to make HTTP | 
 | /// > requests. You can use `HttpClient` indirectly through the | 
 | /// > [`IOClient`](https://pub.dev/documentation/http/latest/io_client/IOClient-class.html) | 
 | /// > adapter in [`package:http`](https://pub.dev/packages/http). | 
 | /// > | 
 | /// > Using a higher-level library, | 
 | /// > like [`package:http`](https://pub.dev/packages/http), allows you to | 
 | /// > switch implementations with minimal changes to your code. For example, | 
 | /// > `package:http` | 
 | /// > [`Client`](https://pub.dev/documentation/http/latest/http/Client-class.html) | 
 | /// > has implementations for the browser and implementations that use | 
 | /// > platform native HTTP clients on Android and iOS. Unlike `HttpClient`, | 
 | /// > these native implementations work with the proxies, VPNs, etc. | 
 | /// | 
 | /// 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. | 
 | /// | 
 | /// 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 an [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 interface class HttpClient { | 
 |   static const int defaultHttpPort = 80; | 
 |  | 
 |   static const int defaultHttpsPort = 443; | 
 |  | 
 |   /// 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) { | 
 |       if (!const bool.fromEnvironment("dart.vm.product")) { | 
 |         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 interface 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; | 
 |  | 
 |   /// An [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 an [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 interface 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 interface class HttpClientCredentials {} | 
 |  | 
 | /// Represents credentials for basic authentication. | 
 | abstract final class HttpClientBasicCredentials | 
 |     implements 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 final class HttpClientDigestCredentials | 
 |     implements HttpClientCredentials { | 
 |   factory HttpClientDigestCredentials(String username, String password) => | 
 |       _HttpClientDigestCredentials(username, password); | 
 | } | 
 |  | 
 | /// Information about an [HttpRequest], [HttpResponse], [HttpClientRequest], or | 
 | /// [HttpClientResponse] connection. | 
 | abstract interface class HttpConnectionInfo { | 
 |   InternetAddress get remoteAddress; | 
 |   int get remotePort; | 
 |   int get localPort; | 
 | } | 
 |  | 
 | /// Redirect information. | 
 | abstract interface 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.isEmpty ? null : redirects.last.location; | 
 | } |