diff CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/include/kj/compat/http.h @ 69:33d812a61356

planemo upload commit 2e9511a184a1ca667c7be0c6321a36dc4e3d116d
author jpayne
date Tue, 18 Mar 2025 17:55:14 -0400
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/include/kj/compat/http.h	Tue Mar 18 17:55:14 2025 -0400
@@ -0,0 +1,1504 @@
+// Copyright (c) 2017 Sandstorm Development Group, Inc. and contributors
+// Licensed under the MIT License:
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#pragma once
+// The KJ HTTP client/server library.
+//
+// This is a simple library which can be used to implement an HTTP client or server. Properties
+// of this library include:
+// - Uses KJ async framework.
+// - Agnostic to transport layer -- you can provide your own.
+// - Header parsing is zero-copy -- it results in strings that point directly into the buffer
+//   received off the wire.
+// - Application code which reads and writes headers refers to headers by symbolic names, not by
+//   string literals, with lookups being array-index-based, not map-based. To make this possible,
+//   the application announces what headers it cares about in advance, in order to assign numeric
+//   values to them.
+// - Methods are identified by an enum.
+
+#include <kj/string.h>
+#include <kj/vector.h>
+#include <kj/memory.h>
+#include <kj/one-of.h>
+#include <kj/async-io.h>
+#include <kj/debug.h>
+
+KJ_BEGIN_HEADER
+
+namespace kj {
+
+#define KJ_HTTP_FOR_EACH_METHOD(MACRO) \
+  MACRO(GET) \
+  MACRO(HEAD) \
+  MACRO(POST) \
+  MACRO(PUT) \
+  MACRO(DELETE) \
+  MACRO(PATCH) \
+  MACRO(PURGE) \
+  MACRO(OPTIONS) \
+  MACRO(TRACE) \
+  /* standard methods */ \
+  /* */ \
+  /* (CONNECT is intentionally omitted since it should be handled specially in HttpServer) */ \
+  \
+  MACRO(COPY) \
+  MACRO(LOCK) \
+  MACRO(MKCOL) \
+  MACRO(MOVE) \
+  MACRO(PROPFIND) \
+  MACRO(PROPPATCH) \
+  MACRO(SEARCH) \
+  MACRO(UNLOCK) \
+  MACRO(ACL) \
+  /* WebDAV */ \
+  \
+  MACRO(REPORT) \
+  MACRO(MKACTIVITY) \
+  MACRO(CHECKOUT) \
+  MACRO(MERGE) \
+  /* Subversion */ \
+  \
+  MACRO(MSEARCH) \
+  MACRO(NOTIFY) \
+  MACRO(SUBSCRIBE) \
+  MACRO(UNSUBSCRIBE)
+  /* UPnP */
+
+enum class HttpMethod {
+  // Enum of known HTTP methods.
+  //
+  // We use an enum rather than a string to allow for faster parsing and switching and to reduce
+  // ambiguity.
+
+#define DECLARE_METHOD(id) id,
+KJ_HTTP_FOR_EACH_METHOD(DECLARE_METHOD)
+#undef DECLARE_METHOD
+};
+
+struct HttpConnectMethod {};
+// CONNECT is handled specially and separately from the other HttpMethods.
+
+kj::StringPtr KJ_STRINGIFY(HttpMethod method);
+kj::StringPtr KJ_STRINGIFY(HttpConnectMethod method);
+kj::Maybe<HttpMethod> tryParseHttpMethod(kj::StringPtr name);
+kj::Maybe<kj::OneOf<HttpMethod, HttpConnectMethod>> tryParseHttpMethodAllowingConnect(
+    kj::StringPtr name);
+// Like tryParseHttpMethod but, as the name suggests, explicitly allows for the CONNECT
+// method. Added as a separate function instead of modifying tryParseHttpMethod to avoid
+// breaking API changes in existing uses of tryParseHttpMethod.
+
+class HttpHeaderTable;
+
+class HttpHeaderId {
+  // Identifies an HTTP header by numeric ID that indexes into an HttpHeaderTable.
+  //
+  // The KJ HTTP API prefers that headers be identified by these IDs for a few reasons:
+  // - Integer lookups are much more efficient than string lookups.
+  // - Case-insensitivity is awkward to deal with when const strings are being passed to the lookup
+  //   method.
+  // - Writing out strings less often means fewer typos.
+  //
+  // See HttpHeaderTable for usage hints.
+
+public:
+  HttpHeaderId() = default;
+
+  inline bool operator==(const HttpHeaderId& other) const { return id == other.id; }
+  inline bool operator!=(const HttpHeaderId& other) const { return id != other.id; }
+  inline bool operator< (const HttpHeaderId& other) const { return id <  other.id; }
+  inline bool operator> (const HttpHeaderId& other) const { return id >  other.id; }
+  inline bool operator<=(const HttpHeaderId& other) const { return id <= other.id; }
+  inline bool operator>=(const HttpHeaderId& other) const { return id >= other.id; }
+
+  inline size_t hashCode() const { return id; }
+  // Returned value is guaranteed to be small and never collide with other headers on the same
+  // table.
+
+  kj::StringPtr toString() const;
+
+  void requireFrom(const HttpHeaderTable& table) const;
+  // In debug mode, throws an exception if the HttpHeaderId is not from the given table.
+  //
+  // In opt mode, no-op.
+
+#define KJ_HTTP_FOR_EACH_BUILTIN_HEADER(MACRO) \
+  /* Headers that are always read-only. */ \
+  MACRO(CONNECTION, "Connection") \
+  MACRO(KEEP_ALIVE, "Keep-Alive") \
+  MACRO(TE, "TE") \
+  MACRO(TRAILER, "Trailer") \
+  MACRO(UPGRADE, "Upgrade") \
+  \
+  /* Headers that are read-only except in the case of a response to a HEAD request. */ \
+  MACRO(CONTENT_LENGTH, "Content-Length") \
+  MACRO(TRANSFER_ENCODING, "Transfer-Encoding") \
+  \
+  /* Headers that are read-only for WebSocket handshakes. */ \
+  MACRO(SEC_WEBSOCKET_KEY, "Sec-WebSocket-Key") \
+  MACRO(SEC_WEBSOCKET_VERSION, "Sec-WebSocket-Version") \
+  MACRO(SEC_WEBSOCKET_ACCEPT, "Sec-WebSocket-Accept") \
+  MACRO(SEC_WEBSOCKET_EXTENSIONS, "Sec-WebSocket-Extensions") \
+  \
+  /* Headers that you can write. */ \
+  MACRO(HOST, "Host") \
+  MACRO(DATE, "Date") \
+  MACRO(LOCATION, "Location") \
+  MACRO(CONTENT_TYPE, "Content-Type")
+  // For convenience, these headers are valid for all HttpHeaderTables. You can refer to them like:
+  //
+  //     HttpHeaderId::HOST
+  //
+  // TODO(someday): Fill this out with more common headers.
+
+#define DECLARE_HEADER(id, name) \
+  static const HttpHeaderId id;
+  // Declare a constant for each builtin header, e.g.: HttpHeaderId::CONNECTION
+
+  KJ_HTTP_FOR_EACH_BUILTIN_HEADER(DECLARE_HEADER);
+#undef DECLARE_HEADER
+
+private:
+  const HttpHeaderTable* table;
+  uint id;
+
+  inline explicit constexpr HttpHeaderId(const HttpHeaderTable* table, uint id)
+      : table(table), id(id) {}
+  friend class HttpHeaderTable;
+  friend class HttpHeaders;
+};
+
+class HttpHeaderTable {
+  // Construct an HttpHeaderTable to declare which headers you'll be interested in later on, and
+  // to manufacture IDs for them.
+  //
+  // Example:
+  //
+  //     // Build a header table with the headers we are interested in.
+  //     kj::HttpHeaderTable::Builder builder;
+  //     const HttpHeaderId accept = builder.add("Accept");
+  //     const HttpHeaderId contentType = builder.add("Content-Type");
+  //     kj::HttpHeaderTable table(kj::mv(builder));
+  //
+  //     // Create an HTTP client.
+  //     auto client = kj::newHttpClient(table, network);
+  //
+  //     // Get http://example.com.
+  //     HttpHeaders headers(table);
+  //     headers.set(accept, "text/html");
+  //     auto response = client->send(kj::HttpMethod::GET, "http://example.com", headers)
+  //         .wait(waitScope);
+  //     auto msg = kj::str("Response content type: ", response.headers.get(contentType));
+
+  struct IdsByNameMap;
+
+public:
+  HttpHeaderTable();
+  // Constructs a table that only contains the builtin headers.
+
+  class Builder {
+  public:
+    Builder();
+    HttpHeaderId add(kj::StringPtr name);
+    Own<HttpHeaderTable> build();
+
+    HttpHeaderTable& getFutureTable();
+    // Get the still-unbuilt header table. You cannot actually use it until build() has been
+    // called.
+    //
+    // This method exists to help when building a shared header table -- the Builder may be passed
+    // to several components, each of which will register the headers they need and get a reference
+    // to the future table.
+
+  private:
+    kj::Own<HttpHeaderTable> table;
+  };
+
+  KJ_DISALLOW_COPY_AND_MOVE(HttpHeaderTable);  // Can't copy because HttpHeaderId points to the table.
+  ~HttpHeaderTable() noexcept(false);
+
+  uint idCount() const;
+  // Return the number of IDs in the table.
+
+  kj::Maybe<HttpHeaderId> stringToId(kj::StringPtr name) const;
+  // Try to find an ID for the given name. The matching is case-insensitive, per the HTTP spec.
+  //
+  // Note: if `name` contains characters that aren't allowed in HTTP header names, this may return
+  //   a bogus value rather than null, due to optimizations used in case-insensitive matching.
+
+  kj::StringPtr idToString(HttpHeaderId id) const;
+  // Get the canonical string name for the given ID.
+
+  bool isReady() const;
+  // Returns true if this HttpHeaderTable either was default constructed or its Builder has
+  // invoked `build()` and released it.
+
+private:
+  kj::Vector<kj::StringPtr> namesById;
+  kj::Own<IdsByNameMap> idsByName;
+
+  enum class BuildStatus {
+    UNSTARTED = 0,
+    BUILDING = 1,
+    FINISHED = 2,
+  };
+  BuildStatus buildStatus = BuildStatus::UNSTARTED;
+};
+
+class HttpHeaders {
+  // Represents a set of HTTP headers.
+  //
+  // This class guards against basic HTTP header injection attacks: Trying to set a header name or
+  // value containing a newline, carriage return, or other invalid character will throw an
+  // exception.
+
+public:
+  explicit HttpHeaders(const HttpHeaderTable& table);
+
+  static bool isValidHeaderValue(kj::StringPtr value);
+  // This returns whether the value is a valid parameter to the set call. While the HTTP spec
+  // suggests that only printable ASCII characters are allowed in header values, in practice that
+  // turns out to not be the case. We follow the browser's lead in disallowing \r and \n.
+  // https://github.com/httpwg/http11bis/issues/19
+  // Use this if you want to validate the value before supplying it to set() if you want to avoid
+  // an exception being thrown (e.g. you have custom error reporting). NOTE that set will still
+  // validate the value. If performance is a problem this API needs to be adjusted to a
+  // `validateHeaderValue` function that returns a special type that set can be confident has
+  // already passed through the validation routine.
+
+  KJ_DISALLOW_COPY(HttpHeaders);
+  HttpHeaders(HttpHeaders&&) = default;
+  HttpHeaders& operator=(HttpHeaders&&) = default;
+
+  size_t size() const;
+  // Returns the number of headers that forEach() would iterate over.
+
+  void clear();
+  // Clears all contents, as if the object was freshly-allocated. However, calling this rather
+  // than actually re-allocating the object may avoid re-allocation of internal objects.
+
+  HttpHeaders clone() const;
+  // Creates a deep clone of the HttpHeaders. The returned object owns all strings it references.
+
+  HttpHeaders cloneShallow() const;
+  // Creates a shallow clone of the HttpHeaders. The returned object references the same strings
+  // as the original, owning none of them.
+
+  bool isWebSocket() const;
+  // Convenience method that checks for the presence of the header `Upgrade: websocket`.
+  //
+  // Note that this does not actually validate that the request is a complete WebSocket handshake
+  // with the correct version number -- such validation will occur if and when you call
+  // acceptWebSocket().
+
+  kj::Maybe<kj::StringPtr> get(HttpHeaderId id) const;
+  // Read a header.
+  //
+  // Note that there is intentionally no method to look up a header by string name rather than
+  // header ID. The intent is that you should always allocate a header ID for any header that you
+  // care about, so that you can get() it by ID. Headers with registered IDs are stored in an array
+  // indexed by ID, making lookup fast. Headers without registered IDs are stored in a separate list
+  // that is optimized for re-transmission of the whole list, but not for lookup.
+
+  template <typename Func>
+  void forEach(Func&& func) const;
+  // Calls `func(name, value)` for each header in the set -- including headers that aren't mapped
+  // to IDs in the header table. Both inputs are of type kj::StringPtr.
+
+  template <typename Func1, typename Func2>
+  void forEach(Func1&& func1, Func2&& func2) const;
+  // Calls `func1(id, value)` for each header in the set that has a registered HttpHeaderId, and
+  // `func2(name, value)` for each header that does not. All calls to func1() precede all calls to
+  // func2().
+
+  void set(HttpHeaderId id, kj::StringPtr value);
+  void set(HttpHeaderId id, kj::String&& value);
+  // Sets a header value, overwriting the existing value.
+  //
+  // The String&& version is equivalent to calling the other version followed by takeOwnership().
+  //
+  // WARNING: It is the caller's responsibility to ensure that `value` remains valid until the
+  //   HttpHeaders object is destroyed. This allows string literals to be passed without making a
+  //   copy, but complicates the use of dynamic values. Hint: Consider using `takeOwnership()`.
+
+  void add(kj::StringPtr name, kj::StringPtr value);
+  void add(kj::StringPtr name, kj::String&& value);
+  void add(kj::String&& name, kj::String&& value);
+  // Append a header. `name` will be looked up in the header table, but if it's not mapped, the
+  // header will be added to the list of unmapped headers.
+  //
+  // The String&& versions are equivalent to calling the other version followed by takeOwnership().
+  //
+  // WARNING: It is the caller's responsibility to ensure that `name` and `value` remain valid
+  //   until the HttpHeaders object is destroyed. This allows string literals to be passed without
+  //   making a copy, but complicates the use of dynamic values. Hint: Consider using
+  //   `takeOwnership()`.
+
+  void unset(HttpHeaderId id);
+  // Removes a header.
+  //
+  // It's not possible to remove a header by string name because non-indexed headers would take
+  // O(n) time to remove. Instead, construct a new HttpHeaders object and copy contents.
+
+  void takeOwnership(kj::String&& string);
+  void takeOwnership(kj::Array<char>&& chars);
+  void takeOwnership(HttpHeaders&& otherHeaders);
+  // Takes ownership of a string so that it lives until the HttpHeaders object is destroyed. Useful
+  // when you've passed a dynamic value to set() or add() or parse*().
+
+  struct Request {
+    HttpMethod method;
+    kj::StringPtr url;
+  };
+  struct ConnectRequest {
+    kj::StringPtr authority;
+  };
+  struct Response {
+    uint statusCode;
+    kj::StringPtr statusText;
+  };
+
+  struct ProtocolError {
+    // Represents a protocol error, such as a bad request method or invalid headers. Debugging such
+    // errors is difficult without a copy of the data which we tried to parse, but this data is
+    // sensitive, so we can't just lump it into the error description directly. ProtocolError
+    // provides this sensitive data separate from the error description.
+    //
+    // TODO(cleanup): Should maybe not live in HttpHeaders? HttpServerErrorHandler::ProtocolError?
+    //   Or HttpProtocolError? Or maybe we need a more general way of attaching sensitive context to
+    //   kj::Exceptions?
+
+    uint statusCode;
+    // Suggested HTTP status code that should be used when returning an error to the client.
+    //
+    // Most errors are 400. An unrecognized method will be 501.
+
+    kj::StringPtr statusMessage;
+    // HTTP status message to go with `statusCode`, e.g. "Bad Request".
+
+    kj::StringPtr description;
+    // An error description safe for all the world to see.
+
+    kj::ArrayPtr<char> rawContent;
+    // Unredacted data which led to the error condition. This may contain anything transported over
+    // HTTP, to include sensitive PII, so you must take care to sanitize this before using it in any
+    // error report that may leak to unprivileged eyes.
+    //
+    // This ArrayPtr is merely a copy of the `content` parameter passed to `tryParseRequest()` /
+    // `tryParseResponse()`, thus it remains valid for as long as a successfully-parsed HttpHeaders
+    // object would remain valid.
+  };
+
+  using RequestOrProtocolError = kj::OneOf<Request, ProtocolError>;
+  using ResponseOrProtocolError = kj::OneOf<Response, ProtocolError>;
+  using RequestConnectOrProtocolError = kj::OneOf<Request, ConnectRequest, ProtocolError>;
+
+  RequestOrProtocolError tryParseRequest(kj::ArrayPtr<char> content);
+  RequestConnectOrProtocolError tryParseRequestOrConnect(kj::ArrayPtr<char> content);
+  ResponseOrProtocolError tryParseResponse(kj::ArrayPtr<char> content);
+
+  // Parse an HTTP header blob and add all the headers to this object.
+  //
+  // `content` should be all text from the start of the request to the first occurrence of two
+  // newlines in a row -- including the first of these two newlines, but excluding the second.
+  //
+  // The parse is performed with zero copies: The callee clobbers `content` with '\0' characters
+  // to split it into a bunch of shorter strings. The caller must keep `content` valid until the
+  // `HttpHeaders` is destroyed, or pass it to `takeOwnership()`.
+
+  bool tryParse(kj::ArrayPtr<char> content);
+  // Like tryParseRequest()/tryParseResponse(), but don't expect any request/response line.
+
+  kj::String serializeRequest(HttpMethod method, kj::StringPtr url,
+                              kj::ArrayPtr<const kj::StringPtr> connectionHeaders = nullptr) const;
+  kj::String serializeConnectRequest(kj::StringPtr authority,
+                              kj::ArrayPtr<const kj::StringPtr> connectionHeaders = nullptr) const;
+  kj::String serializeResponse(uint statusCode, kj::StringPtr statusText,
+                               kj::ArrayPtr<const kj::StringPtr> connectionHeaders = nullptr) const;
+  // **Most applications will not use these methods; they are called by the HTTP client and server
+  // implementations.**
+  //
+  // Serialize the headers as a complete request or response blob. The blob uses '\r\n' newlines
+  // and includes the double-newline to indicate the end of the headers.
+  //
+  // `connectionHeaders`, if provided, contains connection-level headers supplied by the HTTP
+  // implementation, in the order specified by the KJ_HTTP_FOR_EACH_BUILTIN_HEADER macro. These
+  // headers values override any corresponding header value in the HttpHeaders object. The
+  // CONNECTION_HEADERS_COUNT constants below can help you construct this `connectionHeaders` array.
+
+  enum class BuiltinIndicesEnum {
+  #define HEADER_ID(id, name) id,
+    KJ_HTTP_FOR_EACH_BUILTIN_HEADER(HEADER_ID)
+  #undef HEADER_ID
+  };
+
+  struct BuiltinIndices {
+  #define HEADER_ID(id, name) static constexpr uint id = static_cast<uint>(BuiltinIndicesEnum::id);
+    KJ_HTTP_FOR_EACH_BUILTIN_HEADER(HEADER_ID)
+  #undef HEADER_ID
+  };
+
+  static constexpr uint HEAD_RESPONSE_CONNECTION_HEADERS_COUNT = BuiltinIndices::CONTENT_LENGTH;
+  static constexpr uint CONNECTION_HEADERS_COUNT = BuiltinIndices::SEC_WEBSOCKET_KEY;
+  static constexpr uint WEBSOCKET_CONNECTION_HEADERS_COUNT = BuiltinIndices::HOST;
+  // Constants for use with HttpHeaders::serialize*().
+
+  kj::String toString() const;
+
+private:
+  const HttpHeaderTable* table;
+
+  kj::Array<kj::StringPtr> indexedHeaders;
+  // Size is always table->idCount().
+
+  struct Header {
+    kj::StringPtr name;
+    kj::StringPtr value;
+  };
+  kj::Vector<Header> unindexedHeaders;
+
+  kj::Vector<kj::Array<char>> ownedStrings;
+
+  void addNoCheck(kj::StringPtr name, kj::StringPtr value);
+
+  kj::StringPtr cloneToOwn(kj::StringPtr str);
+
+  kj::String serialize(kj::ArrayPtr<const char> word1,
+                       kj::ArrayPtr<const char> word2,
+                       kj::ArrayPtr<const char> word3,
+                       kj::ArrayPtr<const kj::StringPtr> connectionHeaders) const;
+
+  bool parseHeaders(char* ptr, char* end);
+
+  // TODO(perf): Arguably we should store a map, but header sets are never very long
+  // TODO(perf): We could optimize for common headers by storing them directly as fields. We could
+  //   also add direct accessors for those headers.
+};
+
+class HttpInputStream {
+  // Low-level interface to receive HTTP-formatted messages (headers followed by body) from an
+  // input stream, without a paired output stream.
+  //
+  // Most applications will not use this. Regular HTTP clients and servers don't need this. This
+  // is mainly useful for apps implementing various protocols that look like HTTP but aren't
+  // really.
+
+public:
+  struct Request {
+    HttpMethod method;
+    kj::StringPtr url;
+    const HttpHeaders& headers;
+    kj::Own<kj::AsyncInputStream> body;
+  };
+  virtual kj::Promise<Request> readRequest() = 0;
+  // Reads one HTTP request from the input stream.
+  //
+  // The returned struct contains pointers directly into a buffer that is invalidated on the next
+  // message read.
+
+  struct Connect {
+    kj::StringPtr authority;
+    const HttpHeaders& headers;
+    kj::Own<kj::AsyncInputStream> body;
+  };
+  virtual kj::Promise<kj::OneOf<Request, Connect>> readRequestAllowingConnect() = 0;
+  // Reads one HTTP request from the input stream.
+  //
+  // The returned struct contains pointers directly into a buffer that is invalidated on the next
+  // message read.
+
+  struct Response {
+    uint statusCode;
+    kj::StringPtr statusText;
+    const HttpHeaders& headers;
+    kj::Own<kj::AsyncInputStream> body;
+  };
+  virtual kj::Promise<Response> readResponse(HttpMethod requestMethod) = 0;
+  // Reads one HTTP response from the input stream.
+  //
+  // You must provide the request method because responses to HEAD requests require special
+  // treatment.
+  //
+  // The returned struct contains pointers directly into a buffer that is invalidated on the next
+  // message read.
+
+  struct Message {
+    const HttpHeaders& headers;
+    kj::Own<kj::AsyncInputStream> body;
+  };
+  virtual kj::Promise<Message> readMessage() = 0;
+  // Reads an HTTP header set followed by a body, with no request or response line. This is not
+  // useful for HTTP but may be useful for other protocols that make the unfortunate choice to
+  // mimic HTTP message format, such as Visual Studio Code's JSON-RPC transport.
+  //
+  // The returned struct contains pointers directly into a buffer that is invalidated on the next
+  // message read.
+
+  virtual kj::Promise<bool> awaitNextMessage() = 0;
+  // Waits until more data is available, but doesn't consume it. Returns false on EOF.
+};
+
+class EntropySource {
+  // Interface for an object that generates entropy. Typically, cryptographically-random entropy
+  // is expected.
+  //
+  // TODO(cleanup): Put this somewhere more general.
+
+public:
+  virtual void generate(kj::ArrayPtr<byte> buffer) = 0;
+};
+
+struct CompressionParameters {
+  // These are the parameters for `Sec-WebSocket-Extensions` permessage-deflate extension.
+  // Since we cannot distinguish the client/server in `upgradeToWebSocket`, we use the prefixes
+  // `inbound` and `outbound` instead.
+  bool outboundNoContextTakeover = false;
+  bool inboundNoContextTakeover = false;
+  kj::Maybe<size_t> outboundMaxWindowBits = nullptr;
+  kj::Maybe<size_t> inboundMaxWindowBits = nullptr;
+};
+
+class WebSocket {
+  // Interface representincg an open WebSocket session.
+  //
+  // Each side can send and receive data and "close" messages.
+  //
+  // Ping/Pong and message fragmentation are not exposed through this interface. These features of
+  // the underlying WebSocket protocol are not exposed by the browser-level JavaScript API either,
+  // and thus applications typically need to implement these features at the application protocol
+  // level instead. The implementation is, however, expected to reply to Ping messages it receives.
+
+public:
+  virtual kj::Promise<void> send(kj::ArrayPtr<const byte> message) = 0;
+  virtual kj::Promise<void> send(kj::ArrayPtr<const char> message) = 0;
+  // Send a message (binary or text). The underlying buffer must remain valid, and you must not
+  // call send() again, until the returned promise resolves.
+
+  virtual kj::Promise<void> close(uint16_t code, kj::StringPtr reason) = 0;
+  // Send a Close message.
+  //
+  // Note that the returned Promise resolves once the message has been sent -- it does NOT wait
+  // for the other end to send a Close reply. The application should await a reply before dropping
+  // the WebSocket object.
+
+  virtual kj::Promise<void> disconnect() = 0;
+  // Sends EOF on the underlying connection without sending a "close" message. This is NOT a clean
+  // shutdown, but is sometimes useful when you want the other end to trigger whatever behavior
+  // it normally triggers when a connection is dropped.
+
+  virtual void abort() = 0;
+  // Forcefully close this WebSocket, such that the remote end should get a DISCONNECTED error if
+  // it continues to write. This differs from disconnect(), which only closes the sending
+  // direction, but still allows receives.
+
+  virtual kj::Promise<void> whenAborted() = 0;
+  // Resolves when the remote side aborts the connection such that send() would throw DISCONNECTED,
+  // if this can be detected without actually writing a message. (If not, this promise never
+  // resolves, but send() or receive() will throw DISCONNECTED when appropriate. See also
+  // kj::AsyncOutputStream::whenWriteDisconnected().)
+
+  struct ProtocolError {
+    // Represents a protocol error, such as a bad opcode or oversize message.
+
+    uint statusCode;
+    // Suggested WebSocket status code that should be used when returning an error to the client.
+    //
+    // Most errors are 1002; an oversize message will be 1009.
+
+    kj::StringPtr description;
+    // An error description safe for all the world to see. This should be at most 123 bytes so that
+    // it can be used as the body of a Close frame (RFC 6455 sections 5.5 and 5.5.1).
+  };
+
+  struct Close {
+    uint16_t code;
+    kj::String reason;
+  };
+
+  typedef kj::OneOf<kj::String, kj::Array<byte>, Close> Message;
+
+  static constexpr size_t SUGGESTED_MAX_MESSAGE_SIZE = 1u << 20;  // 1MB
+
+  virtual kj::Promise<Message> receive(size_t maxSize = SUGGESTED_MAX_MESSAGE_SIZE) = 0;
+  // Read one message from the WebSocket and return it. Can only call once at a time. Do not call
+  // again after Close is received.
+
+  virtual kj::Promise<void> pumpTo(WebSocket& other);
+  // Continuously receives messages from this WebSocket and send them to `other`.
+  //
+  // On EOF, calls other.disconnect(), then resolves.
+  //
+  // On other read errors, calls other.close() with the error, then resolves.
+  //
+  // On write error, rejects with the error.
+
+  virtual kj::Maybe<kj::Promise<void>> tryPumpFrom(WebSocket& other);
+  // Either returns null, or performs the equivalent of other.pumpTo(*this). Only returns non-null
+  // if this WebSocket implementation is able to perform the pump in an optimized way, better than
+  // the default implementation of pumpTo(). The default implementation of pumpTo() always tries
+  // calling this first, and the default implementation of tryPumpFrom() always returns null.
+
+  virtual uint64_t sentByteCount() = 0;
+  virtual uint64_t receivedByteCount() = 0;
+
+  enum ExtensionsContext {
+    // Indicate whether a Sec-WebSocket-Extension header should be rendered for use in request
+    // headers or response headers.
+    REQUEST,
+    RESPONSE
+  };
+  virtual kj::Maybe<kj::String> getPreferredExtensions(ExtensionsContext ctx) { return nullptr; }
+  // If pumpTo() / tryPumpFrom() is able to be optimized only if the other WebSocket is using
+  // certain extensions (e.g. compression settings), then this method returns what those extensions
+  // are. For example, matching extensions between standard WebSockets allows pumping to be
+  // implemented by pumping raw bytes between network connections, without reading individual frames.
+  //
+  // A null return value indicates that there is no preference. A non-null return value containing
+  // an empty string indicates a preference for no extensions to be applied.
+};
+
+using TlsStarterCallback = kj::Maybe<kj::Function<kj::Promise<void>(kj::StringPtr)>>;
+struct HttpConnectSettings {
+  bool useTls = false;
+  // Requests to automatically establish a TLS session over the connection. The remote party
+  // will be expected to present a valid certificate matching the requested hostname.
+  kj::Maybe<TlsStarterCallback&> tlsStarter;
+  // This is an output parameter. It doesn't need to be set. But if it is set, then it may get
+  // filled with a callback function. It will get filled with `nullptr` if any of the following
+  // are true:
+  //
+  // * kj is not built with TLS support
+  // * the underlying HttpClient does not support the startTls mechanism
+  // * `useTls` has been set to `true` and so TLS has already been started
+  //
+  // The callback function itself can be called to initiate a TLS handshake on the connection in
+  // between write() operations. It is not allowed to initiate a TLS handshake while a write
+  // operation or a pump operation to the connection exists. Read operations are not subject to
+  // the same constraint, however: implementations are required to be able to handle TLS
+  // initiation while a read operation or pump operation from the connection exists. Once the
+  // promise returned from the callback is fulfilled, the connection has become a secure stream,
+  // and write operations are once again permitted. The StringPtr parameter to the callback,
+  // expectedServerHostname may be dropped after the function synchronously returns.
+  //
+  // The PausableReadAsyncIoStream class defined below can be used to ensure that read operations
+  // are not pending when the tlsStarter is invoked.
+  //
+  // This mechanism is required for certain protocols, more info can be found on
+  // https://en.wikipedia.org/wiki/Opportunistic_TLS.
+};
+
+
+class PausableReadAsyncIoStream final: public kj::AsyncIoStream {
+  // A custom AsyncIoStream which can pause pending reads. This is used by startTls to pause a
+  // a read before TLS is initiated.
+  //
+  // TODO(cleanup): this class should be rewritten to use a CRTP mixin approach so that pumps
+  // can be optimised once startTls is invoked.
+  class PausableRead;
+public:
+  PausableReadAsyncIoStream(kj::Own<kj::AsyncIoStream> stream)
+      : inner(kj::mv(stream)), currentlyWriting(false), currentlyReading(false) {}
+
+  _::Deferred<kj::Function<void()>> trackRead();
+
+  _::Deferred<kj::Function<void()>> trackWrite();
+
+  kj::Promise<size_t> tryRead(void* buffer, size_t minBytes, size_t maxBytes) override;
+
+  kj::Promise<size_t> tryReadImpl(void* buffer, size_t minBytes, size_t maxBytes);
+
+  kj::Maybe<uint64_t> tryGetLength() override;
+
+  kj::Promise<uint64_t> pumpTo(kj::AsyncOutputStream& output, uint64_t amount) override;
+
+  kj::Promise<void> write(const void* buffer, size_t size) override;
+
+  kj::Promise<void> write(kj::ArrayPtr<const kj::ArrayPtr<const byte>> pieces) override;
+
+  kj::Maybe<kj::Promise<uint64_t>> tryPumpFrom(
+      kj::AsyncInputStream& input, uint64_t amount = kj::maxValue) override;
+
+  kj::Promise<void> whenWriteDisconnected() override;
+
+  void shutdownWrite() override;
+
+  void abortRead() override;
+
+  kj::Maybe<int> getFd() const override;
+
+  void pause();
+
+  void unpause();
+
+  bool getCurrentlyReading();
+
+  bool getCurrentlyWriting();
+
+  kj::Own<kj::AsyncIoStream> takeStream();
+
+  void replaceStream(kj::Own<kj::AsyncIoStream> stream);
+
+  void reject(kj::Exception&& exc);
+
+private:
+  kj::Own<kj::AsyncIoStream> inner;
+  kj::Maybe<PausableRead&> maybePausableRead;
+  bool currentlyWriting;
+  bool currentlyReading;
+};
+
+class HttpClient {
+  // Interface to the client end of an HTTP connection.
+  //
+  // There are two kinds of clients:
+  // * Host clients are used when talking to a specific host. The `url` specified in a request
+  //   is actually just a path. (A `Host` header is still required in all requests.)
+  // * Proxy clients are used when the target could be any arbitrary host on the internet.
+  //   The `url` specified in a request is a full URL including protocol and hostname.
+
+public:
+  struct Response {
+    uint statusCode;
+    kj::StringPtr statusText;
+    const HttpHeaders* headers;
+    kj::Own<kj::AsyncInputStream> body;
+    // `statusText` and `headers` remain valid until `body` is dropped or read from.
+  };
+
+  struct Request {
+    kj::Own<kj::AsyncOutputStream> body;
+    // Write the request entity body to this stream, then drop it when done.
+    //
+    // May be null for GET and HEAD requests (which have no body) and requests that have
+    // Content-Length: 0.
+
+    kj::Promise<Response> response;
+    // Promise for the eventual response.
+  };
+
+  virtual Request request(HttpMethod method, kj::StringPtr url, const HttpHeaders& headers,
+                          kj::Maybe<uint64_t> expectedBodySize = nullptr) = 0;
+  // Perform an HTTP request.
+  //
+  // `url` may be a full URL (with protocol and host) or it may be only the path part of the URL,
+  // depending on whether the client is a proxy client or a host client.
+  //
+  // `url` and `headers` need only remain valid until `request()` returns (they can be
+  // stack-allocated).
+  //
+  // `expectedBodySize`, if provided, must be exactly the number of bytes that will be written to
+  // the body. This will trigger use of the `Content-Length` connection header. Otherwise,
+  // `Transfer-Encoding: chunked` will be used.
+
+  struct WebSocketResponse {
+    uint statusCode;
+    kj::StringPtr statusText;
+    const HttpHeaders* headers;
+    kj::OneOf<kj::Own<kj::AsyncInputStream>, kj::Own<WebSocket>> webSocketOrBody;
+    // `statusText` and `headers` remain valid until `webSocketOrBody` is dropped or read from.
+  };
+  virtual kj::Promise<WebSocketResponse> openWebSocket(
+      kj::StringPtr url, const HttpHeaders& headers);
+  // Tries to open a WebSocket. Default implementation calls send() and never returns a WebSocket.
+  //
+  // `url` and `headers` need only remain valid until `openWebSocket()` returns (they can be
+  // stack-allocated).
+
+  struct ConnectRequest {
+    struct Status {
+      uint statusCode;
+      kj::String statusText;
+      kj::Own<HttpHeaders> headers;
+      kj::Maybe<kj::Own<kj::AsyncInputStream>> errorBody;
+      // If the connect request is rejected, the statusCode can be any HTTP status code
+      // outside the 200-299 range and errorBody *may* be specified if there is a rejection
+      // payload.
+
+      // TODO(perf): Having Status own the statusText and headers is a bit unfortunate.
+      // Ideally we could have these be non-owned so that the headers object could just
+      // point directly into HttpOutputStream's buffer and not be copied. That's a bit
+      // more difficult to with CONNECT since the lifetimes of the buffers are a little
+      // different than with regular HTTP requests. It should still be possible but for
+      // now copying and owning the status text and headers is easier.
+
+      Status(uint statusCode,
+             kj::String statusText,
+             kj::Own<HttpHeaders> headers,
+             kj::Maybe<kj::Own<kj::AsyncInputStream>> errorBody = nullptr)
+          : statusCode(statusCode),
+            statusText(kj::mv(statusText)),
+            headers(kj::mv(headers)),
+            errorBody(kj::mv(errorBody)) {}
+    };
+
+    kj::Promise<Status> status;
+    kj::Own<kj::AsyncIoStream> connection;
+  };
+
+  virtual ConnectRequest connect(
+      kj::StringPtr host, const HttpHeaders& headers, HttpConnectSettings settings);
+  // Handles CONNECT requests.
+  //
+  // `host` must specify both the host and port (e.g. "example.org:1234").
+  //
+  // The `host` and `headers` need only remain valid until `connect()` returns (it can be
+  // stack-allocated).
+};
+
+class HttpService {
+  // Interface which HTTP services should implement.
+  //
+  // This interface is functionally equivalent to HttpClient, but is intended for applications to
+  // implement rather than call. The ergonomics and performance of the method signatures are
+  // optimized for the serving end.
+  //
+  // As with clients, there are two kinds of services:
+  // * Host services are used when talking to a specific host. The `url` specified in a request
+  //   is actually just a path. (A `Host` header is still required in all requests, and the service
+  //   may in fact serve multiple origins via this header.)
+  // * Proxy services are used when the target could be any arbitrary host on the internet, i.e. to
+  //   implement an HTTP proxy. The `url` specified in a request is a full URL including protocol
+  //   and hostname.
+
+public:
+  class Response {
+  public:
+    virtual kj::Own<kj::AsyncOutputStream> send(
+        uint statusCode, kj::StringPtr statusText, const HttpHeaders& headers,
+        kj::Maybe<uint64_t> expectedBodySize = nullptr) = 0;
+    // Begin the response.
+    //
+    // `statusText` and `headers` need only remain valid until send() returns (they can be
+    // stack-allocated).
+    //
+    // `send()` may only be called a single time. Calling it a second time will cause an exception
+    // to be thrown.
+
+    virtual kj::Own<WebSocket> acceptWebSocket(const HttpHeaders& headers) = 0;
+    // If headers.isWebSocket() is true then you can call acceptWebSocket() instead of send().
+    //
+    // If the request is an invalid WebSocket request (e.g., it has an Upgrade: websocket header,
+    // but other WebSocket-related headers are invalid), `acceptWebSocket()` will throw an
+    // exception, and the HttpServer will return a 400 Bad Request response and close the
+    // connection. In this circumstance, the HttpServer will ignore any exceptions which propagate
+    // from the `HttpService::request()` promise. `HttpServerErrorHandler::handleApplicationError()`
+    // will not be invoked, and the HttpServer's listen task will be fulfilled normally.
+    //
+    // `acceptWebSocket()` may only be called a single time. Calling it a second time will cause an
+    // exception to be thrown.
+
+    kj::Promise<void> sendError(uint statusCode, kj::StringPtr statusText,
+                                const HttpHeaders& headers);
+    kj::Promise<void> sendError(uint statusCode, kj::StringPtr statusText,
+                                const HttpHeaderTable& headerTable);
+    // Convenience wrapper around send() which sends a basic error. A generic error page specifying
+    // the error code is sent as the body.
+    //
+    // You must provide headers or a header table because downstream service wrappers may be
+    // expecting response headers built with a particular table so that they can insert additional
+    // headers.
+  };
+
+  virtual kj::Promise<void> request(
+      HttpMethod method, kj::StringPtr url, const HttpHeaders& headers,
+      kj::AsyncInputStream& requestBody, Response& response) = 0;
+  // Perform an HTTP request.
+  //
+  // `url` may be a full URL (with protocol and host) or it may be only the path part of the URL,
+  // depending on whether the service is a proxy service or a host service.
+  //
+  // `url` and `headers` are invalidated on the first read from `requestBody` or when the returned
+  // promise resolves, whichever comes first.
+  //
+  // Request processing can be canceled by dropping the returned promise. HttpServer may do so if
+  // the client disconnects prematurely.
+  //
+  // The implementation of `request()` should usually not try to use `response` in any way in
+  // exception-handling code, because it is often not possible to tell whether `Response::send()` or
+  // `Response::acceptWebSocket()` has already been called. Instead, to generate error HTTP
+  // responses for the client, implement an HttpServerErrorHandler and pass it to the HttpServer via
+  // HttpServerSettings. If the `HttpService::request()` promise rejects and no response has yet
+  // been sent, `HttpServerErrorHandler::handleApplicationError()` will be passed a non-null
+  // `Maybe<Response&>` parameter.
+
+  class ConnectResponse {
+  public:
+    virtual void accept(
+        uint statusCode,
+        kj::StringPtr statusText,
+        const HttpHeaders& headers) = 0;
+    // Signals acceptance of the CONNECT tunnel.
+
+    virtual kj::Own<kj::AsyncOutputStream> reject(
+        uint statusCode,
+        kj::StringPtr statusText,
+        const HttpHeaders& headers,
+        kj::Maybe<uint64_t> expectedBodySize = nullptr) = 0;
+    // Signals rejection of the CONNECT tunnel.
+  };
+
+  virtual kj::Promise<void> connect(kj::StringPtr host,
+                                    const HttpHeaders& headers,
+                                    kj::AsyncIoStream& connection,
+                                    ConnectResponse& response,
+                                    HttpConnectSettings settings);
+  // Handles CONNECT requests.
+  //
+  // The `host` must include host and port.
+  //
+  // `host` and `headers` are invalidated when accept or reject is called on the ConnectResponse
+  // or when the returned promise resolves, whichever comes first.
+  //
+  // The connection is provided to support pipelining. Writes to the connection will be blocked
+  // until one of either accept() or reject() is called on tunnel. Reads from the connection are
+  // permitted at any time.
+  //
+  // Request processing can be canceled by dropping the returned promise. HttpServer may do so if
+  // the client disconnects prematurely.
+};
+
+class HttpClientErrorHandler {
+public:
+  virtual HttpClient::Response handleProtocolError(HttpHeaders::ProtocolError protocolError);
+  // Override this function to customize error handling when the client receives an HTTP message
+  // that fails to parse. The default implementations throws an exception.
+  //
+  // There are two main use cases for overriding this:
+  // 1. `protocolError` contains the actual header content that failed to parse, giving you the
+  //    opportunity to log it for debugging purposes. The default implementation throws away this
+  //    content.
+  // 2. You could potentially convert protocol errors into HTTP error codes, e.g. 502 Bad Gateway.
+  //
+  // Note that `protocolError` may contain pointers into buffers that are no longer valid once
+  // this method returns; you will have to make copies if you want to keep them.
+
+  virtual HttpClient::WebSocketResponse handleWebSocketProtocolError(
+      HttpHeaders::ProtocolError protocolError);
+  // Like handleProtocolError() but for WebSocket requests. The default implementation calls
+  // handleProtocolError() and converts the Response to WebSocketResponse. There is probably very
+  // little reason to override this.
+};
+
+struct HttpClientSettings {
+  kj::Duration idleTimeout = 5 * kj::SECONDS;
+  // For clients which automatically create new connections, any connection idle for at least this
+  // long will be closed. Set this to 0 to prevent connection reuse entirely.
+
+  kj::Maybe<EntropySource&> entropySource = nullptr;
+  // Must be provided in order to use `openWebSocket`. If you don't need WebSockets, this can be
+  // omitted. The WebSocket protocol uses random values to avoid triggering flaws (including
+  // security flaws) in certain HTTP proxy software. Specifically, entropy is used to generate the
+  // `Sec-WebSocket-Key` header and to generate frame masks. If you know that there are no broken
+  // or vulnerable proxies between you and the server, you can provide a dummy entropy source that
+  // doesn't generate real entropy (e.g. returning the same value every time). Otherwise, you must
+  // provide a cryptographically-random entropy source.
+
+  kj::Maybe<HttpClientErrorHandler&> errorHandler = nullptr;
+  // Customize how protocol errors are handled by the HttpClient. If null, HttpClientErrorHandler's
+  // default implementation will be used.
+
+  enum WebSocketCompressionMode {
+    NO_COMPRESSION,
+    MANUAL_COMPRESSION,    // Lets the application decide the compression configuration (if any).
+    AUTOMATIC_COMPRESSION, // Automatically includes the compression header in the WebSocket request.
+  };
+  WebSocketCompressionMode webSocketCompressionMode = NO_COMPRESSION;
+
+  kj::Maybe<SecureNetworkWrapper&> tlsContext;
+  // A reference to a TLS context that will be used when tlsStarter is invoked.
+};
+
+class WebSocketErrorHandler {
+public:
+  virtual kj::Exception handleWebSocketProtocolError(WebSocket::ProtocolError protocolError);
+  // Handles low-level protocol errors in received WebSocket data.
+  //
+  // This is called when the WebSocket peer sends us bad data *after* a successful WebSocket
+  // upgrade, e.g. a continuation frame without a preceding start frame, a frame with an unknown
+  // opcode, or similar.
+  //
+  // You would override this method in order to customize the exception. You cannot prevent the
+  // exception from being thrown.
+};
+
+kj::Own<HttpClient> newHttpClient(kj::Timer& timer, const HttpHeaderTable& responseHeaderTable,
+                                  kj::Network& network, kj::Maybe<kj::Network&> tlsNetwork,
+                                  HttpClientSettings settings = HttpClientSettings());
+// Creates a proxy HttpClient that connects to hosts over the given network. The URL must always
+// be an absolute URL; the host is parsed from the URL. This implementation will automatically
+// add an appropriate Host header (and convert the URL to just a path) once it has connected.
+//
+// Note that if you wish to route traffic through an HTTP proxy server rather than connect to
+// remote hosts directly, you should use the form of newHttpClient() that takes a NetworkAddress,
+// and supply the proxy's address.
+//
+// `responseHeaderTable` is used when parsing HTTP responses. Requests can use any header table.
+//
+// `tlsNetwork` is required to support HTTPS destination URLs. If null, only HTTP URLs can be
+// fetched.
+
+kj::Own<HttpClient> newHttpClient(kj::Timer& timer, const HttpHeaderTable& responseHeaderTable,
+                                  kj::NetworkAddress& addr,
+                                  HttpClientSettings settings = HttpClientSettings());
+// Creates an HttpClient that always connects to the given address no matter what URL is requested.
+// The client will open and close connections as needed. It will attempt to reuse connections for
+// multiple requests but will not send a new request before the previous response on the same
+// connection has completed, as doing so can result in head-of-line blocking issues. The client may
+// be used as a proxy client or a host client depending on whether the peer is operating as
+// a proxy. (Hint: This is the best kind of client to use when routing traffic through an HTTP
+// proxy. `addr` should be the address of the proxy, and the proxy itself will resolve remote hosts
+// based on the URLs passed to it.)
+//
+// `responseHeaderTable` is used when parsing HTTP responses. Requests can use any header table.
+
+kj::Own<HttpClient> newHttpClient(const HttpHeaderTable& responseHeaderTable,
+                                  kj::AsyncIoStream& stream,
+                                  HttpClientSettings settings = HttpClientSettings());
+// Creates an HttpClient that speaks over the given pre-established connection. The client may
+// be used as a proxy client or a host client depending on whether the peer is operating as
+// a proxy.
+//
+// Note that since this client has only one stream to work with, it will try to pipeline all
+// requests on this stream. If one request or response has an I/O failure, all subsequent requests
+// fail as well. If the destination server chooses to close the connection after a response,
+// subsequent requests will fail. If a response takes a long time, it blocks subsequent responses.
+// If a WebSocket is opened successfully, all subsequent requests fail.
+
+kj::Own<HttpClient> newConcurrencyLimitingHttpClient(
+    HttpClient& inner, uint maxConcurrentRequests,
+    kj::Function<void(uint runningCount, uint pendingCount)> countChangedCallback);
+// Creates an HttpClient that is limited to a maximum number of concurrent requests.  Additional
+// requests are queued, to be opened only after an open request completes.  `countChangedCallback`
+// is called when a new connection is opened or enqueued and when an open connection is closed,
+// passing the number of open and pending connections.
+
+kj::Own<HttpClient> newHttpClient(HttpService& service);
+kj::Own<HttpService> newHttpService(HttpClient& client);
+// Adapts an HttpClient to an HttpService and vice versa.
+
+kj::Own<HttpInputStream> newHttpInputStream(
+    kj::AsyncInputStream& input, const HttpHeaderTable& headerTable);
+// Create an HttpInputStream on top of the given stream. Normally applications would not call this
+// directly, but it can be useful for implementing protocols that aren't quite HTTP but use similar
+// message delimiting.
+//
+// The HttpInputStream implementation does read-ahead buffering on `input`. Therefore, when the
+// HttpInputStream is destroyed, some data read from `input` may be lost, so it's not possible to
+// continue reading from `input` in a reliable way.
+
+kj::Own<WebSocket> newWebSocket(kj::Own<kj::AsyncIoStream> stream,
+                                kj::Maybe<EntropySource&> maskEntropySource,
+                                kj::Maybe<CompressionParameters> compressionConfig = nullptr,
+                                kj::Maybe<WebSocketErrorHandler&> errorHandler = nullptr);
+// Create a new WebSocket on top of the given stream. It is assumed that the HTTP -> WebSocket
+// upgrade handshake has already occurred (or is not needed), and messages can immediately be
+// sent and received on the stream. Normally applications would not call this directly.
+//
+// `maskEntropySource` is used to generate cryptographically-random frame masks. If null, outgoing
+// frames will not be masked. Servers are required NOT to mask their outgoing frames, but clients
+// ARE required to do so. So, on the client side, you MUST specify an entropy source. The mask
+// must be crytographically random if the data being sent on the WebSocket may be malicious. The
+// purpose of the mask is to prevent badly-written HTTP proxies from interpreting "things that look
+// like HTTP requests" in a message as being actual HTTP requests, which could result in cache
+// poisoning. See RFC6455 section 10.3.
+//
+// `compressionConfig` is an optional argument that allows us to specify how the WebSocket should
+// compress and decompress messages. The configuration is determined by the
+// `Sec-WebSocket-Extensions` header during WebSocket negotiation.
+//
+// `errorHandler` is an optional argument that lets callers throw custom exceptions for WebSocket
+// protocol errors.
+
+struct WebSocketPipe {
+  kj::Own<WebSocket> ends[2];
+};
+
+WebSocketPipe newWebSocketPipe();
+// Create a WebSocket pipe. Messages written to one end of the pipe will be readable from the other
+// end. No buffering occurs -- a message send does not complete until a corresponding receive
+// accepts the message.
+
+class HttpServerErrorHandler;
+class HttpServerCallbacks;
+
+struct HttpServerSettings {
+  kj::Duration headerTimeout = 15 * kj::SECONDS;
+  // After initial connection open, or after receiving the first byte of a pipelined request,
+  // the client must send the complete request within this time.
+
+  kj::Duration pipelineTimeout = 5 * kj::SECONDS;
+  // After one request/response completes, we'll wait up to this long for a pipelined request to
+  // arrive.
+
+  kj::Duration canceledUploadGracePeriod = 1 * kj::SECONDS;
+  size_t canceledUploadGraceBytes = 65536;
+  // If the HttpService sends a response and returns without having read the entire request body,
+  // then we have to decide whether to close the connection or wait for the client to finish the
+  // request so that it can pipeline the next one. We'll give them a grace period defined by the
+  // above two values -- if they hit either one, we'll close the socket, but if the request
+  // completes, we'll let the connection stay open to handle more requests.
+
+  kj::Maybe<HttpServerErrorHandler&> errorHandler = nullptr;
+  // Customize how client protocol errors and service application exceptions are handled by the
+  // HttpServer. If null, HttpServerErrorHandler's default implementation will be used.
+
+  kj::Maybe<HttpServerCallbacks&> callbacks = nullptr;
+  // Additional optional callbacks used to control some server behavior.
+
+  kj::Maybe<WebSocketErrorHandler&> webSocketErrorHandler = nullptr;
+  // Customize exceptions thrown on WebSocket protocol errors.
+
+  enum WebSocketCompressionMode {
+    NO_COMPRESSION,
+    MANUAL_COMPRESSION,    // Gives the application more control when considering whether to compress.
+    AUTOMATIC_COMPRESSION, // Will perform compression parameter negotiation if client requests it.
+  };
+  WebSocketCompressionMode webSocketCompressionMode = NO_COMPRESSION;
+};
+
+class HttpServerErrorHandler {
+public:
+  virtual kj::Promise<void> handleClientProtocolError(
+      HttpHeaders::ProtocolError protocolError, kj::HttpService::Response& response);
+  virtual kj::Promise<void> handleApplicationError(
+      kj::Exception exception, kj::Maybe<kj::HttpService::Response&> response);
+  virtual kj::Promise<void> handleNoResponse(kj::HttpService::Response& response);
+  // Override these functions to customize error handling during the request/response cycle.
+  //
+  // Client protocol errors arise when the server receives an HTTP message that fails to parse. As
+  // such, HttpService::request() will not have been called yet, and the handler is always
+  // guaranteed an opportunity to send a response. The default implementation of
+  // handleClientProtocolError() replies with a 400 Bad Request response.
+  //
+  // Application errors arise when HttpService::request() throws an exception. The default
+  // implementation of handleApplicationError() maps the following exception types to HTTP statuses,
+  // and generates bodies from the stringified exceptions:
+  //
+  //   - OVERLOADED: 503 Service Unavailable
+  //   - UNIMPLEMENTED: 501 Not Implemented
+  //   - DISCONNECTED: (no response)
+  //   - FAILED: 500 Internal Server Error
+  //
+  // No-response errors occur when HttpService::request() allows its promise to settle before
+  // sending a response. The default implementation of handleNoResponse() replies with a 500
+  // Internal Server Error response.
+  //
+  // Unlike `HttpService::request()`, when calling `response.send()` in the context of one of these
+  // functions, a "Connection: close" header will be added, and the connection will be closed.
+  //
+  // Also unlike `HttpService::request()`, it is okay to return kj::READY_NOW without calling
+  // `response.send()`. In this case, no response will be sent, and the connection will be closed.
+
+  virtual void handleListenLoopException(kj::Exception&& exception);
+  // Override this function to customize error handling for individual connections in the
+  // `listenHttp()` overload which accepts a ConnectionReceiver reference.
+  //
+  // The default handler uses KJ_LOG() to log the exception as an error.
+};
+
+class HttpServerCallbacks {
+public:
+  virtual bool shouldClose() { return false; }
+  // Whenever the HttpServer begins response headers, it will check `shouldClose()` to decide
+  // whether to send a `Connection: close` header and close the connection.
+  //
+  // This can be useful e.g. if the server has too many connections open and wants to shed some
+  // of them. Note that to implement graceful shutdown of a server, you should use
+  // `HttpServer::drain()` instead.
+};
+
+class HttpServer final: private kj::TaskSet::ErrorHandler {
+  // Class which listens for requests on ports or connections and sends them to an HttpService.
+
+public:
+  typedef HttpServerSettings Settings;
+  typedef kj::Function<kj::Own<HttpService>(kj::AsyncIoStream&)> HttpServiceFactory;
+  class SuspendableRequest;
+  typedef kj::Function<kj::Maybe<kj::Own<HttpService>>(SuspendableRequest&)>
+      SuspendableHttpServiceFactory;
+
+  HttpServer(kj::Timer& timer, const HttpHeaderTable& requestHeaderTable, HttpService& service,
+             Settings settings = Settings());
+  // Set up an HttpServer that directs incoming connections to the given service. The service
+  // may be a host service or a proxy service depending on whether you are intending to implement
+  // an HTTP server or an HTTP proxy.
+
+  HttpServer(kj::Timer& timer, const HttpHeaderTable& requestHeaderTable,
+             HttpServiceFactory serviceFactory, Settings settings = Settings());
+  // Like the other constructor, but allows a new HttpService object to be used for each
+  // connection, based on the connection object. This is particularly useful for capturing the
+  // client's IP address and injecting it as a header.
+
+  kj::Promise<void> drain();
+  // Stop accepting new connections or new requests on existing connections. Finish any requests
+  // that are already executing, then close the connections. Returns once no more requests are
+  // in-flight.
+
+  kj::Promise<void> listenHttp(kj::ConnectionReceiver& port);
+  // Accepts HTTP connections on the given port and directs them to the handler.
+  //
+  // The returned promise never completes normally. It may throw if port.accept() throws. Dropping
+  // the returned promise will cause the server to stop listening on the port, but already-open
+  // connections will continue to be served. Destroy the whole HttpServer to cancel all I/O.
+
+  kj::Promise<void> listenHttp(kj::Own<kj::AsyncIoStream> connection);
+  // Reads HTTP requests from the given connection and directs them to the handler. A successful
+  // completion of the promise indicates that all requests received on the connection resulted in
+  // a complete response, and the client closed the connection gracefully or drain() was called.
+  // The promise throws if an unparsable request is received or if some I/O error occurs. Dropping
+  // the returned promise will cancel all I/O on the connection and cancel any in-flight requests.
+
+  kj::Promise<bool> listenHttpCleanDrain(kj::AsyncIoStream& connection);
+  // Like listenHttp(), but allows you to potentially drain the server without closing connections.
+  // The returned promise resolves to `true` if the connection has been left in a state where a
+  // new HttpServer could potentially accept further requests from it. If `false`, then the
+  // connection is either in an inconsistent state or already completed a closing handshake; the
+  // caller should close it without any further reads/writes. Note this only ever returns `true`
+  // if you called `drain()` -- otherwise this server would keep handling the connection.
+
+  class SuspendedRequest {
+    // SuspendedRequest is a representation of a request immediately after parsing the method line and
+    // headers. You can obtain one of these by suspending a request by calling
+    // SuspendableRequest::suspend(), then later resume the request with another call to
+    // listenHttpCleanDrain().
+
+  public:
+    // Nothing, this is an opaque type.
+
+  private:
+    SuspendedRequest(kj::Array<byte>, kj::ArrayPtr<byte>, kj::OneOf<HttpMethod, HttpConnectMethod>, kj::StringPtr, HttpHeaders);
+
+    kj::Array<byte> buffer;
+    // A buffer containing at least the request's method, URL, and headers, and possibly content
+    // thereafter.
+
+    kj::ArrayPtr<byte> leftover;
+    // Pointer to the end of the request headers. If this has a non-zero length, then our buffer
+    // contains additional content, presumably the head of the request body.
+
+    kj::OneOf<HttpMethod, HttpConnectMethod> method;
+    kj::StringPtr url;
+    HttpHeaders headers;
+    // Parsed request front matter. `url` and `headers` both store pointers into `buffer`.
+
+    friend class HttpServer;
+  };
+
+  kj::Promise<bool> listenHttpCleanDrain(kj::AsyncIoStream& connection,
+      SuspendableHttpServiceFactory factory,
+      kj::Maybe<SuspendedRequest> suspendedRequest = nullptr);
+  // Like listenHttpCleanDrain(), but allows you to suspend requests.
+  //
+  // When this overload is in use, the HttpServer's default HttpService or HttpServiceFactory is not
+  // used. Instead, the HttpServer reads the request method line and headers, then calls `factory`
+  // with a SuspendableRequest representing the request parsed so far. The factory may then return
+  // a kj::Own<HttpService> for that specific request, or it may call SuspendableRequest::suspend()
+  // and return nullptr. (It is an error for the factory to return nullptr without also calling
+  // suspend(); this will result in a rejected listenHttpCleanDrain() promise.)
+  //
+  // If the factory chooses to suspend, the listenHttpCleanDrain() promise is resolved with false
+  // at the earliest opportunity.
+  //
+  // SuspendableRequest::suspend() returns a SuspendedRequest. You can resume this request later by
+  // calling this same listenHttpCleanDrain() overload with the original connection stream, and the
+  // SuspendedRequest in question.
+  //
+  // This overload of listenHttpCleanDrain() implements draining, as documented above. Note that the
+  // returned promise will resolve to false (not clean) if a request is suspended.
+
+private:
+  class Connection;
+
+  kj::Timer& timer;
+  const HttpHeaderTable& requestHeaderTable;
+  kj::OneOf<HttpService*, HttpServiceFactory> service;
+  Settings settings;
+
+  bool draining = false;
+  kj::ForkedPromise<void> onDrain;
+  kj::Own<kj::PromiseFulfiller<void>> drainFulfiller;
+
+  uint connectionCount = 0;
+  kj::Maybe<kj::Own<kj::PromiseFulfiller<void>>> zeroConnectionsFulfiller;
+
+  kj::TaskSet tasks;
+
+  HttpServer(kj::Timer& timer, const HttpHeaderTable& requestHeaderTable,
+             kj::OneOf<HttpService*, HttpServiceFactory> service,
+             Settings settings, kj::PromiseFulfillerPair<void> paf);
+
+  kj::Promise<void> listenLoop(kj::ConnectionReceiver& port);
+
+  void taskFailed(kj::Exception&& exception) override;
+
+  kj::Promise<bool> listenHttpImpl(kj::AsyncIoStream& connection, bool wantCleanDrain);
+  kj::Promise<bool> listenHttpImpl(kj::AsyncIoStream& connection,
+      SuspendableHttpServiceFactory factory,
+      kj::Maybe<SuspendedRequest> suspendedRequest,
+      bool wantCleanDrain);
+};
+
+class HttpServer::SuspendableRequest {
+  // Interface passed to the SuspendableHttpServiceFactory parameter of listenHttpCleanDrain().
+
+public:
+  kj::OneOf<HttpMethod,HttpConnectMethod> method;
+  kj::StringPtr url;
+  const HttpHeaders& headers;
+  // Parsed request front matter, so the implementer can decide whether to suspend the request.
+
+  SuspendedRequest suspend();
+  // Signal to the HttpServer that the current request loop should be exited. Return a
+  // SuspendedRequest, containing HTTP method, URL, and headers access, along with the actual header
+  // buffer. The request can be later resumed with a call to listenHttpCleanDrain() using the same
+  // connection.
+
+private:
+  explicit SuspendableRequest(
+      Connection& connection, kj::OneOf<HttpMethod, HttpConnectMethod> method, kj::StringPtr url, const HttpHeaders& headers)
+      : method(method), url(url), headers(headers), connection(connection) {}
+  KJ_DISALLOW_COPY_AND_MOVE(SuspendableRequest);
+
+  Connection& connection;
+
+  friend class Connection;
+};
+
+// =======================================================================================
+// inline implementation
+
+inline void HttpHeaderId::requireFrom(const HttpHeaderTable& table) const {
+  KJ_IREQUIRE(this->table == nullptr || this->table == &table,
+      "the provided HttpHeaderId is from the wrong HttpHeaderTable");
+}
+
+inline kj::Own<HttpHeaderTable> HttpHeaderTable::Builder::build() {
+  table->buildStatus = BuildStatus::FINISHED;
+  return kj::mv(table);
+}
+inline HttpHeaderTable& HttpHeaderTable::Builder::getFutureTable() { return *table; }
+
+inline uint HttpHeaderTable::idCount() const { return namesById.size(); }
+inline bool HttpHeaderTable::isReady() const {
+  switch (buildStatus) {
+    case BuildStatus::UNSTARTED: return true;
+    case BuildStatus::BUILDING: return false;
+    case BuildStatus::FINISHED: return true;
+  }
+
+  KJ_UNREACHABLE;
+}
+
+inline kj::StringPtr HttpHeaderTable::idToString(HttpHeaderId id) const {
+  id.requireFrom(*this);
+  return namesById[id.id];
+}
+
+inline kj::Maybe<kj::StringPtr> HttpHeaders::get(HttpHeaderId id) const {
+  id.requireFrom(*table);
+  auto result = indexedHeaders[id.id];
+  return result == nullptr ? kj::Maybe<kj::StringPtr>(nullptr) : result;
+}
+
+inline void HttpHeaders::unset(HttpHeaderId id) {
+  id.requireFrom(*table);
+  indexedHeaders[id.id] = nullptr;
+}
+
+template <typename Func>
+inline void HttpHeaders::forEach(Func&& func) const {
+  for (auto i: kj::indices(indexedHeaders)) {
+    if (indexedHeaders[i] != nullptr) {
+      func(table->idToString(HttpHeaderId(table, i)), indexedHeaders[i]);
+    }
+  }
+
+  for (auto& header: unindexedHeaders) {
+    func(header.name, header.value);
+  }
+}
+
+template <typename Func1, typename Func2>
+inline void HttpHeaders::forEach(Func1&& func1, Func2&& func2) const {
+  for (auto i: kj::indices(indexedHeaders)) {
+    if (indexedHeaders[i] != nullptr) {
+      func1(HttpHeaderId(table, i), indexedHeaders[i]);
+    }
+  }
+
+  for (auto& header: unindexedHeaders) {
+    func2(header.name, header.value);
+  }
+}
+
+// =======================================================================================
+namespace _ { // private implementation details for WebSocket compression
+
+kj::ArrayPtr<const char> splitNext(kj::ArrayPtr<const char>& cursor, char delimiter);
+
+void stripLeadingAndTrailingSpace(ArrayPtr<const char>& str);
+
+kj::Vector<kj::ArrayPtr<const char>> splitParts(kj::ArrayPtr<const char> input, char delim);
+
+struct KeyMaybeVal {
+  ArrayPtr<const char> key;
+  kj::Maybe<ArrayPtr<const char>> val;
+};
+
+kj::Array<KeyMaybeVal> toKeysAndVals(const kj::ArrayPtr<kj::ArrayPtr<const char>>& params);
+
+struct UnverifiedConfig {
+  // An intermediate representation of the final `CompressionParameters` struct; used during parsing.
+  // We use it to ensure the structure of an offer is generally correct, see
+  // `populateUnverifiedConfig()` for details.
+  bool clientNoContextTakeover = false;
+  bool serverNoContextTakeover = false;
+  kj::Maybe<ArrayPtr<const char>> clientMaxWindowBits = nullptr;
+  kj::Maybe<ArrayPtr<const char>> serverMaxWindowBits = nullptr;
+};
+
+kj::Maybe<UnverifiedConfig> populateUnverifiedConfig(kj::Array<KeyMaybeVal>& params);
+
+kj::Maybe<CompressionParameters> validateCompressionConfig(UnverifiedConfig&& config,
+    bool isAgreement);
+
+kj::Vector<CompressionParameters> findValidExtensionOffers(StringPtr offers);
+
+kj::String generateExtensionRequest(const ArrayPtr<CompressionParameters>& extensions);
+
+kj::Maybe<CompressionParameters> tryParseExtensionOffers(StringPtr offers);
+
+kj::Maybe<CompressionParameters> tryParseAllExtensionOffers(StringPtr offers,
+    CompressionParameters manualConfig);
+
+kj::Maybe<CompressionParameters> compareClientAndServerConfigs(CompressionParameters requestConfig,
+    CompressionParameters manualConfig);
+
+kj::String generateExtensionResponse(const CompressionParameters& parameters);
+
+kj::OneOf<CompressionParameters, kj::Exception> tryParseExtensionAgreement(
+    const Maybe<CompressionParameters>& clientOffer,
+    StringPtr agreedParameters);
+
+}; // namespace _ (private)
+
+}  // namespace kj
+
+KJ_END_HEADER