Mercurial > hg > sv-dependency-builds
comparison osx/include/kj/compat/http.h @ 147:45360b968bf4
Cap'n Proto v0.6 + build for OSX
author | Chris Cannam <cannam@all-day-breakfast.com> |
---|---|
date | Mon, 22 May 2017 10:01:37 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
146:206f0eb279b8 | 147:45360b968bf4 |
---|---|
1 // Copyright (c) 2017 Sandstorm Development Group, Inc. and contributors | |
2 // Licensed under the MIT License: | |
3 // | |
4 // Permission is hereby granted, free of charge, to any person obtaining a copy | |
5 // of this software and associated documentation files (the "Software"), to deal | |
6 // in the Software without restriction, including without limitation the rights | |
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
8 // copies of the Software, and to permit persons to whom the Software is | |
9 // furnished to do so, subject to the following conditions: | |
10 // | |
11 // The above copyright notice and this permission notice shall be included in | |
12 // all copies or substantial portions of the Software. | |
13 // | |
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
20 // THE SOFTWARE. | |
21 | |
22 #ifndef KJ_COMPAT_HTTP_H_ | |
23 #define KJ_COMPAT_HTTP_H_ | |
24 // The KJ HTTP client/server library. | |
25 // | |
26 // This is a simple library which can be used to implement an HTTP client or server. Properties | |
27 // of this library include: | |
28 // - Uses KJ async framework. | |
29 // - Agnostic to transport layer -- you can provide your own. | |
30 // - Header parsing is zero-copy -- it results in strings that point directly into the buffer | |
31 // received off the wire. | |
32 // - Application code which reads and writes headers refers to headers by symbolic names, not by | |
33 // string literals, with lookups being array-index-based, not map-based. To make this possible, | |
34 // the application announces what headers it cares about in advance, in order to assign numeric | |
35 // values to them. | |
36 // - Methods are identified by an enum. | |
37 | |
38 #include <kj/string.h> | |
39 #include <kj/vector.h> | |
40 #include <kj/memory.h> | |
41 #include <kj/one-of.h> | |
42 #include <kj/async-io.h> | |
43 | |
44 namespace kj { | |
45 | |
46 #define KJ_HTTP_FOR_EACH_METHOD(MACRO) \ | |
47 MACRO(GET) \ | |
48 MACRO(HEAD) \ | |
49 MACRO(POST) \ | |
50 MACRO(PUT) \ | |
51 MACRO(DELETE) \ | |
52 MACRO(PATCH) \ | |
53 MACRO(PURGE) \ | |
54 MACRO(OPTIONS) \ | |
55 MACRO(TRACE) \ | |
56 /* standard methods */ \ | |
57 /* */ \ | |
58 /* (CONNECT is intentionally omitted since it is handled specially in HttpHandler) */ \ | |
59 \ | |
60 MACRO(COPY) \ | |
61 MACRO(LOCK) \ | |
62 MACRO(MKCOL) \ | |
63 MACRO(MOVE) \ | |
64 MACRO(PROPFIND) \ | |
65 MACRO(PROPPATCH) \ | |
66 MACRO(SEARCH) \ | |
67 MACRO(UNLOCK) \ | |
68 /* WebDAV */ \ | |
69 \ | |
70 MACRO(REPORT) \ | |
71 MACRO(MKACTIVITY) \ | |
72 MACRO(CHECKOUT) \ | |
73 MACRO(MERGE) \ | |
74 /* Subversion */ \ | |
75 \ | |
76 MACRO(MSEARCH) \ | |
77 MACRO(NOTIFY) \ | |
78 MACRO(SUBSCRIBE) \ | |
79 MACRO(UNSUBSCRIBE) | |
80 /* UPnP */ | |
81 | |
82 #define KJ_HTTP_FOR_EACH_CONNECTION_HEADER(MACRO) \ | |
83 MACRO(connection, "Connection") \ | |
84 MACRO(contentLength, "Content-Length") \ | |
85 MACRO(keepAlive, "Keep-Alive") \ | |
86 MACRO(te, "TE") \ | |
87 MACRO(trailer, "Trailer") \ | |
88 MACRO(transferEncoding, "Transfer-Encoding") \ | |
89 MACRO(upgrade, "Upgrade") | |
90 | |
91 enum class HttpMethod { | |
92 // Enum of known HTTP methods. | |
93 // | |
94 // We use an enum rather than a string to allow for faster parsing and switching and to reduce | |
95 // ambiguity. | |
96 | |
97 #define DECLARE_METHOD(id) id, | |
98 KJ_HTTP_FOR_EACH_METHOD(DECLARE_METHOD) | |
99 #undef DECALRE_METHOD | |
100 }; | |
101 | |
102 kj::StringPtr KJ_STRINGIFY(HttpMethod method); | |
103 kj::Maybe<HttpMethod> tryParseHttpMethod(kj::StringPtr name); | |
104 | |
105 class HttpHeaderTable; | |
106 | |
107 class HttpHeaderId { | |
108 // Identifies an HTTP header by numeric ID that indexes into an HttpHeaderTable. | |
109 // | |
110 // The KJ HTTP API prefers that headers be identified by these IDs for a few reasons: | |
111 // - Integer lookups are much more efficient than string lookups. | |
112 // - Case-insensitivity is awkward to deal with when const strings are being passed to the lookup | |
113 // method. | |
114 // - Writing out strings less often means fewer typos. | |
115 // | |
116 // See HttpHeaderTable for usage hints. | |
117 | |
118 public: | |
119 HttpHeaderId() = default; | |
120 | |
121 inline bool operator==(const HttpHeaderId& other) const { return id == other.id; } | |
122 inline bool operator!=(const HttpHeaderId& other) const { return id != other.id; } | |
123 inline bool operator< (const HttpHeaderId& other) const { return id < other.id; } | |
124 inline bool operator> (const HttpHeaderId& other) const { return id > other.id; } | |
125 inline bool operator<=(const HttpHeaderId& other) const { return id <= other.id; } | |
126 inline bool operator>=(const HttpHeaderId& other) const { return id >= other.id; } | |
127 | |
128 inline size_t hashCode() const { return id; } | |
129 | |
130 kj::StringPtr toString() const; | |
131 | |
132 void requireFrom(HttpHeaderTable& table) const; | |
133 // In debug mode, throws an exception if the HttpHeaderId is not from the given table. | |
134 // | |
135 // In opt mode, no-op. | |
136 | |
137 #define KJ_HTTP_FOR_EACH_BUILTIN_HEADER(MACRO) \ | |
138 MACRO(HOST, "Host") \ | |
139 MACRO(DATE, "Date") \ | |
140 MACRO(LOCATION, "Location") \ | |
141 MACRO(CONTENT_TYPE, "Content-Type") | |
142 // For convenience, these very-common headers are valid for all HttpHeaderTables. You can refer | |
143 // to them like: | |
144 // | |
145 // HttpHeaderId::HOST | |
146 // | |
147 // TODO(0.7): Fill this out with more common headers. | |
148 | |
149 #define DECLARE_HEADER(id, name) \ | |
150 static const HttpHeaderId id; | |
151 // Declare a constant for each builtin header, e.g.: HttpHeaderId::CONNECTION | |
152 | |
153 KJ_HTTP_FOR_EACH_BUILTIN_HEADER(DECLARE_HEADER); | |
154 #undef DECLARE_HEADER | |
155 | |
156 private: | |
157 HttpHeaderTable* table; | |
158 uint id; | |
159 | |
160 inline explicit constexpr HttpHeaderId(HttpHeaderTable* table, uint id): table(table), id(id) {} | |
161 friend class HttpHeaderTable; | |
162 friend class HttpHeaders; | |
163 }; | |
164 | |
165 class HttpHeaderTable { | |
166 // Construct an HttpHeaderTable to declare which headers you'll be interested in later on, and | |
167 // to manufacture IDs for them. | |
168 // | |
169 // Example: | |
170 // | |
171 // // Build a header table with the headers we are interested in. | |
172 // kj::HttpHeaderTable::Builder builder; | |
173 // const HttpHeaderId accept = builder.add("Accept"); | |
174 // const HttpHeaderId contentType = builder.add("Content-Type"); | |
175 // kj::HttpHeaderTable table(kj::mv(builder)); | |
176 // | |
177 // // Create an HTTP client. | |
178 // auto client = kj::newHttpClient(table, network); | |
179 // | |
180 // // Get http://example.com. | |
181 // HttpHeaders headers(table); | |
182 // headers.set(accept, "text/html"); | |
183 // auto response = client->send(kj::HttpMethod::GET, "http://example.com", headers) | |
184 // .wait(waitScope); | |
185 // auto msg = kj::str("Response content type: ", response.headers.get(contentType)); | |
186 | |
187 struct IdsByNameMap; | |
188 | |
189 public: | |
190 HttpHeaderTable(); | |
191 // Constructs a table that only contains the builtin headers. | |
192 | |
193 class Builder { | |
194 public: | |
195 Builder(); | |
196 HttpHeaderId add(kj::StringPtr name); | |
197 Own<HttpHeaderTable> build(); | |
198 | |
199 HttpHeaderTable& getFutureTable(); | |
200 // Get the still-unbuilt header table. You cannot actually use it until build() has been | |
201 // called. | |
202 // | |
203 // This method exists to help when building a shared header table -- the Builder may be passed | |
204 // to several components, each of which will register the headers they need and get a reference | |
205 // to the future table. | |
206 | |
207 private: | |
208 kj::Own<HttpHeaderTable> table; | |
209 }; | |
210 | |
211 KJ_DISALLOW_COPY(HttpHeaderTable); // Can't copy because HttpHeaderId points to the table. | |
212 ~HttpHeaderTable() noexcept(false); | |
213 | |
214 uint idCount(); | |
215 // Return the number of IDs in the table. | |
216 | |
217 kj::Maybe<HttpHeaderId> stringToId(kj::StringPtr name); | |
218 // Try to find an ID for the given name. The matching is case-insensitive, per the HTTP spec. | |
219 // | |
220 // Note: if `name` contains characters that aren't allowed in HTTP header names, this may return | |
221 // a bogus value rather than null, due to optimizations used in case-insensitive matching. | |
222 | |
223 kj::StringPtr idToString(HttpHeaderId id); | |
224 // Get the canonical string name for the given ID. | |
225 | |
226 private: | |
227 kj::Vector<kj::StringPtr> namesById; | |
228 kj::Own<IdsByNameMap> idsByName; | |
229 }; | |
230 | |
231 class HttpHeaders { | |
232 // Represents a set of HTTP headers. | |
233 // | |
234 // This class guards against basic HTTP header injection attacks: Trying to set a header name or | |
235 // value containing a newline, carriage return, or other invalid character will throw an | |
236 // exception. | |
237 | |
238 public: | |
239 explicit HttpHeaders(HttpHeaderTable& table); | |
240 | |
241 KJ_DISALLOW_COPY(HttpHeaders); | |
242 HttpHeaders(HttpHeaders&&) = default; | |
243 HttpHeaders& operator=(HttpHeaders&&) = default; | |
244 | |
245 void clear(); | |
246 // Clears all contents, as if the object was freshly-allocated. However, calling this rather | |
247 // than actually re-allocating the object may avoid re-allocation of internal objects. | |
248 | |
249 HttpHeaders clone() const; | |
250 // Creates a deep clone of the HttpHeaders. The returned object owns all strings it references. | |
251 | |
252 HttpHeaders cloneShallow() const; | |
253 // Creates a shallow clone of the HttpHeaders. The returned object references the same strings | |
254 // as the original, owning none of them. | |
255 | |
256 kj::Maybe<kj::StringPtr> get(HttpHeaderId id) const; | |
257 // Read a header. | |
258 | |
259 template <typename Func> | |
260 void forEach(Func&& func) const; | |
261 // Calls `func(name, value)` for each header in the set -- including headers that aren't mapped | |
262 // to IDs in the header table. Both inputs are of type kj::StringPtr. | |
263 | |
264 void set(HttpHeaderId id, kj::StringPtr value); | |
265 void set(HttpHeaderId id, kj::String&& value); | |
266 // Sets a header value, overwriting the existing value. | |
267 // | |
268 // The String&& version is equivalent to calling the other version followed by takeOwnership(). | |
269 // | |
270 // WARNING: It is the caller's responsibility to ensure that `value` remains valid until the | |
271 // HttpHeaders object is destroyed. This allows string literals to be passed without making a | |
272 // copy, but complicates the use of dynamic values. Hint: Consider using `takeOwnership()`. | |
273 | |
274 void add(kj::StringPtr name, kj::StringPtr value); | |
275 void add(kj::StringPtr name, kj::String&& value); | |
276 void add(kj::String&& name, kj::String&& value); | |
277 // Append a header. `name` will be looked up in the header table, but if it's not mapped, the | |
278 // header will be added to the list of unmapped headers. | |
279 // | |
280 // The String&& versions are equivalent to calling the other version followed by takeOwnership(). | |
281 // | |
282 // WARNING: It is the caller's responsibility to ensure that `name` and `value` remain valid | |
283 // until the HttpHeaders object is destroyed. This allows string literals to be passed without | |
284 // making a copy, but complicates the use of dynamic values. Hint: Consider using | |
285 // `takeOwnership()`. | |
286 | |
287 void unset(HttpHeaderId id); | |
288 // Removes a header. | |
289 // | |
290 // It's not possible to remove a header by string name because non-indexed headers would take | |
291 // O(n) time to remove. Instead, construct a new HttpHeaders object and copy contents. | |
292 | |
293 void takeOwnership(kj::String&& string); | |
294 void takeOwnership(kj::Array<char>&& chars); | |
295 void takeOwnership(HttpHeaders&& otherHeaders); | |
296 // Takes overship of a string so that it lives until the HttpHeaders object is destroyed. Useful | |
297 // when you've passed a dynamic value to set() or add() or parse*(). | |
298 | |
299 struct ConnectionHeaders { | |
300 // These headers govern details of the specific HTTP connection or framing of the content. | |
301 // Hence, they are managed internally within the HTTP library, and never appear in an | |
302 // HttpHeaders structure. | |
303 | |
304 #define DECLARE_HEADER(id, name) \ | |
305 kj::StringPtr id; | |
306 KJ_HTTP_FOR_EACH_CONNECTION_HEADER(DECLARE_HEADER) | |
307 #undef DECLARE_HEADER | |
308 }; | |
309 | |
310 struct Request { | |
311 HttpMethod method; | |
312 kj::StringPtr url; | |
313 ConnectionHeaders connectionHeaders; | |
314 }; | |
315 struct Response { | |
316 uint statusCode; | |
317 kj::StringPtr statusText; | |
318 ConnectionHeaders connectionHeaders; | |
319 }; | |
320 | |
321 kj::Maybe<Request> tryParseRequest(kj::ArrayPtr<char> content); | |
322 kj::Maybe<Response> tryParseResponse(kj::ArrayPtr<char> content); | |
323 // Parse an HTTP header blob and add all the headers to this object. | |
324 // | |
325 // `content` should be all text from the start of the request to the first occurrance of two | |
326 // newlines in a row -- including the first of these two newlines, but excluding the second. | |
327 // | |
328 // The parse is performed with zero copies: The callee clobbers `content` with '\0' characters | |
329 // to split it into a bunch of shorter strings. The caller must keep `content` valid until the | |
330 // `HttpHeaders` is destroyed, or pass it to `takeOwnership()`. | |
331 | |
332 kj::String serializeRequest(HttpMethod method, kj::StringPtr url, | |
333 const ConnectionHeaders& connectionHeaders) const; | |
334 kj::String serializeResponse(uint statusCode, kj::StringPtr statusText, | |
335 const ConnectionHeaders& connectionHeaders) const; | |
336 // Serialize the headers as a complete request or response blob. The blob uses '\r\n' newlines | |
337 // and includes the double-newline to indicate the end of the headers. | |
338 | |
339 kj::String toString() const; | |
340 | |
341 private: | |
342 HttpHeaderTable* table; | |
343 | |
344 kj::Array<kj::StringPtr> indexedHeaders; | |
345 // Size is always table->idCount(). | |
346 | |
347 struct Header { | |
348 kj::StringPtr name; | |
349 kj::StringPtr value; | |
350 }; | |
351 kj::Vector<Header> unindexedHeaders; | |
352 | |
353 kj::Vector<kj::Array<char>> ownedStrings; | |
354 | |
355 kj::Maybe<uint> addNoCheck(kj::StringPtr name, kj::StringPtr value); | |
356 | |
357 kj::StringPtr cloneToOwn(kj::StringPtr str); | |
358 | |
359 kj::String serialize(kj::ArrayPtr<const char> word1, | |
360 kj::ArrayPtr<const char> word2, | |
361 kj::ArrayPtr<const char> word3, | |
362 const ConnectionHeaders& connectionHeaders) const; | |
363 | |
364 bool parseHeaders(char* ptr, char* end, ConnectionHeaders& connectionHeaders); | |
365 | |
366 // TODO(perf): Arguably we should store a map, but header sets are never very long | |
367 // TODO(perf): We could optimize for common headers by storing them directly as fields. We could | |
368 // also add direct accessors for those headers. | |
369 }; | |
370 | |
371 class WebSocket { | |
372 public: | |
373 WebSocket(kj::Own<kj::AsyncIoStream> stream); | |
374 // Create a WebSocket wrapping the given I/O stream. | |
375 | |
376 kj::Promise<void> send(kj::ArrayPtr<const byte> message); | |
377 kj::Promise<void> send(kj::ArrayPtr<const char> message); | |
378 }; | |
379 | |
380 class HttpClient { | |
381 // Interface to the client end of an HTTP connection. | |
382 // | |
383 // There are two kinds of clients: | |
384 // * Host clients are used when talking to a specific host. The `url` specified in a request | |
385 // is actually just a path. (A `Host` header is still required in all requests.) | |
386 // * Proxy clients are used when the target could be any arbitrary host on the internet. | |
387 // The `url` specified in a request is a full URL including protocol and hostname. | |
388 | |
389 public: | |
390 struct Response { | |
391 uint statusCode; | |
392 kj::StringPtr statusText; | |
393 const HttpHeaders* headers; | |
394 kj::Own<kj::AsyncInputStream> body; | |
395 // `statusText` and `headers` remain valid until `body` is dropped. | |
396 }; | |
397 | |
398 struct Request { | |
399 kj::Own<kj::AsyncOutputStream> body; | |
400 // Write the request entity body to this stream, then drop it when done. | |
401 // | |
402 // May be null for GET and HEAD requests (which have no body) and requests that have | |
403 // Content-Length: 0. | |
404 | |
405 kj::Promise<Response> response; | |
406 // Promise for the eventual respnose. | |
407 }; | |
408 | |
409 virtual Request request(HttpMethod method, kj::StringPtr url, const HttpHeaders& headers, | |
410 kj::Maybe<uint64_t> expectedBodySize = nullptr) = 0; | |
411 // Perform an HTTP request. | |
412 // | |
413 // `url` may be a full URL (with protocol and host) or it may be only the path part of the URL, | |
414 // depending on whether the client is a proxy client or a host client. | |
415 // | |
416 // `url` and `headers` need only remain valid until `request()` returns (they can be | |
417 // stack-allocated). | |
418 // | |
419 // `expectedBodySize`, if provided, must be exactly the number of bytes that will be written to | |
420 // the body. This will trigger use of the `Content-Length` connection header. Otherwise, | |
421 // `Transfer-Encoding: chunked` will be used. | |
422 | |
423 struct WebSocketResponse { | |
424 uint statusCode; | |
425 kj::StringPtr statusText; | |
426 const HttpHeaders* headers; | |
427 kj::OneOf<kj::Own<kj::AsyncInputStream>, kj::Own<WebSocket>> upstreamOrBody; | |
428 // `statusText` and `headers` remain valid until `upstreamOrBody` is dropped. | |
429 }; | |
430 virtual kj::Promise<WebSocketResponse> openWebSocket( | |
431 kj::StringPtr url, const HttpHeaders& headers, kj::Own<WebSocket> downstream); | |
432 // Tries to open a WebSocket. Default implementation calls send() and never returns a WebSocket. | |
433 // | |
434 // `url` and `headers` are invalidated when the returned promise resolves. | |
435 | |
436 virtual kj::Promise<kj::Own<kj::AsyncIoStream>> connect(kj::String host); | |
437 // Handles CONNECT requests. Only relevant for proxy clients. Default implementation throws | |
438 // UNIMPLEMENTED. | |
439 }; | |
440 | |
441 class HttpService { | |
442 // Interface which HTTP services should implement. | |
443 // | |
444 // This interface is functionally equivalent to HttpClient, but is intended for applications to | |
445 // implement rather than call. The ergonomics and performance of the method signatures are | |
446 // optimized for the serving end. | |
447 // | |
448 // As with clients, there are two kinds of services: | |
449 // * Host services are used when talking to a specific host. The `url` specified in a request | |
450 // is actually just a path. (A `Host` header is still required in all requests, and the service | |
451 // may in fact serve multiple origins via this header.) | |
452 // * Proxy services are used when the target could be any arbitrary host on the internet, i.e. to | |
453 // implement an HTTP proxy. The `url` specified in a request is a full URL including protocol | |
454 // and hostname. | |
455 | |
456 public: | |
457 class Response { | |
458 public: | |
459 virtual kj::Own<kj::AsyncOutputStream> send( | |
460 uint statusCode, kj::StringPtr statusText, const HttpHeaders& headers, | |
461 kj::Maybe<uint64_t> expectedBodySize = nullptr) = 0; | |
462 // Begin the response. | |
463 // | |
464 // `statusText` and `headers` need only remain valid until send() returns (they can be | |
465 // stack-allocated). | |
466 }; | |
467 | |
468 virtual kj::Promise<void> request( | |
469 HttpMethod method, kj::StringPtr url, const HttpHeaders& headers, | |
470 kj::AsyncInputStream& requestBody, Response& response) = 0; | |
471 // Perform an HTTP request. | |
472 // | |
473 // `url` may be a full URL (with protocol and host) or it may be only the path part of the URL, | |
474 // depending on whether the service is a proxy service or a host service. | |
475 // | |
476 // `url` and `headers` are invalidated on the first read from `requestBody` or when the returned | |
477 // promise resolves, whichever comes first. | |
478 | |
479 class WebSocketResponse: public Response { | |
480 public: | |
481 kj::Own<WebSocket> startWebSocket( | |
482 uint statusCode, kj::StringPtr statusText, const HttpHeaders& headers, | |
483 WebSocket& upstream); | |
484 // Begin the response. | |
485 // | |
486 // `statusText` and `headers` need only remain valid until startWebSocket() returns (they can | |
487 // be stack-allocated). | |
488 }; | |
489 | |
490 virtual kj::Promise<void> openWebSocket( | |
491 kj::StringPtr url, const HttpHeaders& headers, WebSocketResponse& response); | |
492 // Tries to open a WebSocket. Default implementation calls request() and never returns a | |
493 // WebSocket. | |
494 // | |
495 // `url` and `headers` are invalidated when the returned promise resolves. | |
496 | |
497 virtual kj::Promise<kj::Own<kj::AsyncIoStream>> connect(kj::String host); | |
498 // Handles CONNECT requests. Only relevant for proxy services. Default implementation throws | |
499 // UNIMPLEMENTED. | |
500 }; | |
501 | |
502 kj::Own<HttpClient> newHttpClient(HttpHeaderTable& responseHeaderTable, kj::Network& network, | |
503 kj::Maybe<kj::Network&> tlsNetwork = nullptr); | |
504 // Creates a proxy HttpClient that connects to hosts over the given network. | |
505 // | |
506 // `responseHeaderTable` is used when parsing HTTP responses. Requests can use any header table. | |
507 // | |
508 // `tlsNetwork` is required to support HTTPS destination URLs. Otherwise, only HTTP URLs can be | |
509 // fetched. | |
510 | |
511 kj::Own<HttpClient> newHttpClient(HttpHeaderTable& responseHeaderTable, kj::AsyncIoStream& stream); | |
512 // Creates an HttpClient that speaks over the given pre-established connection. The client may | |
513 // be used as a proxy client or a host client depending on whether the peer is operating as | |
514 // a proxy. | |
515 // | |
516 // Note that since this client has only one stream to work with, it will try to pipeline all | |
517 // requests on this stream. If one request or response has an I/O failure, all subsequent requests | |
518 // fail as well. If the destination server chooses to close the connection after a response, | |
519 // subsequent requests will fail. If a response takes a long time, it blocks subsequent responses. | |
520 // If a WebSocket is opened successfully, all subsequent requests fail. | |
521 | |
522 kj::Own<HttpClient> newHttpClient(HttpService& service); | |
523 kj::Own<HttpService> newHttpService(HttpClient& client); | |
524 // Adapts an HttpClient to an HttpService and vice versa. | |
525 | |
526 struct HttpServerSettings { | |
527 kj::Duration headerTimeout = 15 * kj::SECONDS; | |
528 // After initial connection open, or after receiving the first byte of a pipelined request, | |
529 // the client must send the complete request within this time. | |
530 | |
531 kj::Duration pipelineTimeout = 5 * kj::SECONDS; | |
532 // After one request/response completes, we'll wait up to this long for a pipelined request to | |
533 // arrive. | |
534 }; | |
535 | |
536 class HttpServer: private kj::TaskSet::ErrorHandler { | |
537 // Class which listens for requests on ports or connections and sends them to an HttpService. | |
538 | |
539 public: | |
540 typedef HttpServerSettings Settings; | |
541 | |
542 HttpServer(kj::Timer& timer, HttpHeaderTable& requestHeaderTable, HttpService& service, | |
543 Settings settings = Settings()); | |
544 // Set up an HttpServer that directs incoming connections to the given service. The service | |
545 // may be a host service or a proxy service depending on whether you are intending to implement | |
546 // an HTTP server or an HTTP proxy. | |
547 | |
548 kj::Promise<void> drain(); | |
549 // Stop accepting new connections or new requests on existing connections. Finish any requests | |
550 // that are already executing, then close the connections. Returns once no more requests are | |
551 // in-flight. | |
552 | |
553 kj::Promise<void> listenHttp(kj::ConnectionReceiver& port); | |
554 // Accepts HTTP connections on the given port and directs them to the handler. | |
555 // | |
556 // The returned promise never completes normally. It may throw if port.accept() throws. Dropping | |
557 // the returned promise will cause the server to stop listening on the port, but already-open | |
558 // connections will continue to be served. Destroy the whole HttpServer to cancel all I/O. | |
559 | |
560 kj::Promise<void> listenHttp(kj::Own<kj::AsyncIoStream> connection); | |
561 // Reads HTTP requests from the given connection and directs them to the handler. A successful | |
562 // completion of the promise indicates that all requests received on the connection resulted in | |
563 // a complete response, and the client closed the connection gracefully or drain() was called. | |
564 // The promise throws if an unparseable request is received or if some I/O error occurs. Dropping | |
565 // the returned promise will cancel all I/O on the connection and cancel any in-flight requests. | |
566 | |
567 private: | |
568 class Connection; | |
569 | |
570 kj::Timer& timer; | |
571 HttpHeaderTable& requestHeaderTable; | |
572 HttpService& service; | |
573 Settings settings; | |
574 | |
575 bool draining = false; | |
576 kj::ForkedPromise<void> onDrain; | |
577 kj::Own<kj::PromiseFulfiller<void>> drainFulfiller; | |
578 | |
579 uint connectionCount = 0; | |
580 kj::Maybe<kj::Own<kj::PromiseFulfiller<void>>> zeroConnectionsFulfiller; | |
581 | |
582 kj::TaskSet tasks; | |
583 | |
584 HttpServer(kj::Timer& timer, HttpHeaderTable& requestHeaderTable, HttpService& service, | |
585 Settings settings, kj::PromiseFulfillerPair<void> paf); | |
586 | |
587 kj::Promise<void> listenLoop(kj::ConnectionReceiver& port); | |
588 | |
589 void taskFailed(kj::Exception&& exception) override; | |
590 }; | |
591 | |
592 // ======================================================================================= | |
593 // inline implementation | |
594 | |
595 inline void HttpHeaderId::requireFrom(HttpHeaderTable& table) const { | |
596 KJ_IREQUIRE(this->table == nullptr || this->table == &table, | |
597 "the provided HttpHeaderId is from the wrong HttpHeaderTable"); | |
598 } | |
599 | |
600 inline kj::Own<HttpHeaderTable> HttpHeaderTable::Builder::build() { return kj::mv(table); } | |
601 inline HttpHeaderTable& HttpHeaderTable::Builder::getFutureTable() { return *table; } | |
602 | |
603 inline uint HttpHeaderTable::idCount() { return namesById.size(); } | |
604 | |
605 inline kj::StringPtr HttpHeaderTable::idToString(HttpHeaderId id) { | |
606 id.requireFrom(*this); | |
607 return namesById[id.id]; | |
608 } | |
609 | |
610 inline kj::Maybe<kj::StringPtr> HttpHeaders::get(HttpHeaderId id) const { | |
611 id.requireFrom(*table); | |
612 auto result = indexedHeaders[id.id]; | |
613 return result == nullptr ? kj::Maybe<kj::StringPtr>(nullptr) : result; | |
614 } | |
615 | |
616 inline void HttpHeaders::unset(HttpHeaderId id) { | |
617 id.requireFrom(*table); | |
618 indexedHeaders[id.id] = nullptr; | |
619 } | |
620 | |
621 template <typename Func> | |
622 inline void HttpHeaders::forEach(Func&& func) const { | |
623 for (auto i: kj::indices(indexedHeaders)) { | |
624 if (indexedHeaders[i] != nullptr) { | |
625 func(table->idToString(HttpHeaderId(table, i)), indexedHeaders[i]); | |
626 } | |
627 } | |
628 | |
629 for (auto& header: unindexedHeaders) { | |
630 func(header.name, header.value); | |
631 } | |
632 } | |
633 | |
634 } // namespace kj | |
635 | |
636 #endif // KJ_COMPAT_HTTP_H_ |