Mercurial > repos > rliterman > csp2
comparison 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 |
comparison
equal
deleted
inserted
replaced
67:0e9998148a16 | 69:33d812a61356 |
---|---|
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 #pragma once | |
23 // The KJ HTTP client/server library. | |
24 // | |
25 // This is a simple library which can be used to implement an HTTP client or server. Properties | |
26 // of this library include: | |
27 // - Uses KJ async framework. | |
28 // - Agnostic to transport layer -- you can provide your own. | |
29 // - Header parsing is zero-copy -- it results in strings that point directly into the buffer | |
30 // received off the wire. | |
31 // - Application code which reads and writes headers refers to headers by symbolic names, not by | |
32 // string literals, with lookups being array-index-based, not map-based. To make this possible, | |
33 // the application announces what headers it cares about in advance, in order to assign numeric | |
34 // values to them. | |
35 // - Methods are identified by an enum. | |
36 | |
37 #include <kj/string.h> | |
38 #include <kj/vector.h> | |
39 #include <kj/memory.h> | |
40 #include <kj/one-of.h> | |
41 #include <kj/async-io.h> | |
42 #include <kj/debug.h> | |
43 | |
44 KJ_BEGIN_HEADER | |
45 | |
46 namespace kj { | |
47 | |
48 #define KJ_HTTP_FOR_EACH_METHOD(MACRO) \ | |
49 MACRO(GET) \ | |
50 MACRO(HEAD) \ | |
51 MACRO(POST) \ | |
52 MACRO(PUT) \ | |
53 MACRO(DELETE) \ | |
54 MACRO(PATCH) \ | |
55 MACRO(PURGE) \ | |
56 MACRO(OPTIONS) \ | |
57 MACRO(TRACE) \ | |
58 /* standard methods */ \ | |
59 /* */ \ | |
60 /* (CONNECT is intentionally omitted since it should be handled specially in HttpServer) */ \ | |
61 \ | |
62 MACRO(COPY) \ | |
63 MACRO(LOCK) \ | |
64 MACRO(MKCOL) \ | |
65 MACRO(MOVE) \ | |
66 MACRO(PROPFIND) \ | |
67 MACRO(PROPPATCH) \ | |
68 MACRO(SEARCH) \ | |
69 MACRO(UNLOCK) \ | |
70 MACRO(ACL) \ | |
71 /* WebDAV */ \ | |
72 \ | |
73 MACRO(REPORT) \ | |
74 MACRO(MKACTIVITY) \ | |
75 MACRO(CHECKOUT) \ | |
76 MACRO(MERGE) \ | |
77 /* Subversion */ \ | |
78 \ | |
79 MACRO(MSEARCH) \ | |
80 MACRO(NOTIFY) \ | |
81 MACRO(SUBSCRIBE) \ | |
82 MACRO(UNSUBSCRIBE) | |
83 /* UPnP */ | |
84 | |
85 enum class HttpMethod { | |
86 // Enum of known HTTP methods. | |
87 // | |
88 // We use an enum rather than a string to allow for faster parsing and switching and to reduce | |
89 // ambiguity. | |
90 | |
91 #define DECLARE_METHOD(id) id, | |
92 KJ_HTTP_FOR_EACH_METHOD(DECLARE_METHOD) | |
93 #undef DECLARE_METHOD | |
94 }; | |
95 | |
96 struct HttpConnectMethod {}; | |
97 // CONNECT is handled specially and separately from the other HttpMethods. | |
98 | |
99 kj::StringPtr KJ_STRINGIFY(HttpMethod method); | |
100 kj::StringPtr KJ_STRINGIFY(HttpConnectMethod method); | |
101 kj::Maybe<HttpMethod> tryParseHttpMethod(kj::StringPtr name); | |
102 kj::Maybe<kj::OneOf<HttpMethod, HttpConnectMethod>> tryParseHttpMethodAllowingConnect( | |
103 kj::StringPtr name); | |
104 // Like tryParseHttpMethod but, as the name suggests, explicitly allows for the CONNECT | |
105 // method. Added as a separate function instead of modifying tryParseHttpMethod to avoid | |
106 // breaking API changes in existing uses of tryParseHttpMethod. | |
107 | |
108 class HttpHeaderTable; | |
109 | |
110 class HttpHeaderId { | |
111 // Identifies an HTTP header by numeric ID that indexes into an HttpHeaderTable. | |
112 // | |
113 // The KJ HTTP API prefers that headers be identified by these IDs for a few reasons: | |
114 // - Integer lookups are much more efficient than string lookups. | |
115 // - Case-insensitivity is awkward to deal with when const strings are being passed to the lookup | |
116 // method. | |
117 // - Writing out strings less often means fewer typos. | |
118 // | |
119 // See HttpHeaderTable for usage hints. | |
120 | |
121 public: | |
122 HttpHeaderId() = default; | |
123 | |
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 inline bool operator> (const HttpHeaderId& other) const { return id > other.id; } | |
128 inline bool operator<=(const HttpHeaderId& other) const { return id <= other.id; } | |
129 inline bool operator>=(const HttpHeaderId& other) const { return id >= other.id; } | |
130 | |
131 inline size_t hashCode() const { return id; } | |
132 // Returned value is guaranteed to be small and never collide with other headers on the same | |
133 // table. | |
134 | |
135 kj::StringPtr toString() const; | |
136 | |
137 void requireFrom(const HttpHeaderTable& table) const; | |
138 // In debug mode, throws an exception if the HttpHeaderId is not from the given table. | |
139 // | |
140 // In opt mode, no-op. | |
141 | |
142 #define KJ_HTTP_FOR_EACH_BUILTIN_HEADER(MACRO) \ | |
143 /* Headers that are always read-only. */ \ | |
144 MACRO(CONNECTION, "Connection") \ | |
145 MACRO(KEEP_ALIVE, "Keep-Alive") \ | |
146 MACRO(TE, "TE") \ | |
147 MACRO(TRAILER, "Trailer") \ | |
148 MACRO(UPGRADE, "Upgrade") \ | |
149 \ | |
150 /* Headers that are read-only except in the case of a response to a HEAD request. */ \ | |
151 MACRO(CONTENT_LENGTH, "Content-Length") \ | |
152 MACRO(TRANSFER_ENCODING, "Transfer-Encoding") \ | |
153 \ | |
154 /* Headers that are read-only for WebSocket handshakes. */ \ | |
155 MACRO(SEC_WEBSOCKET_KEY, "Sec-WebSocket-Key") \ | |
156 MACRO(SEC_WEBSOCKET_VERSION, "Sec-WebSocket-Version") \ | |
157 MACRO(SEC_WEBSOCKET_ACCEPT, "Sec-WebSocket-Accept") \ | |
158 MACRO(SEC_WEBSOCKET_EXTENSIONS, "Sec-WebSocket-Extensions") \ | |
159 \ | |
160 /* Headers that you can write. */ \ | |
161 MACRO(HOST, "Host") \ | |
162 MACRO(DATE, "Date") \ | |
163 MACRO(LOCATION, "Location") \ | |
164 MACRO(CONTENT_TYPE, "Content-Type") | |
165 // For convenience, these headers are valid for all HttpHeaderTables. You can refer to them like: | |
166 // | |
167 // HttpHeaderId::HOST | |
168 // | |
169 // TODO(someday): Fill this out with more common headers. | |
170 | |
171 #define DECLARE_HEADER(id, name) \ | |
172 static const HttpHeaderId id; | |
173 // Declare a constant for each builtin header, e.g.: HttpHeaderId::CONNECTION | |
174 | |
175 KJ_HTTP_FOR_EACH_BUILTIN_HEADER(DECLARE_HEADER); | |
176 #undef DECLARE_HEADER | |
177 | |
178 private: | |
179 const HttpHeaderTable* table; | |
180 uint id; | |
181 | |
182 inline explicit constexpr HttpHeaderId(const HttpHeaderTable* table, uint id) | |
183 : table(table), id(id) {} | |
184 friend class HttpHeaderTable; | |
185 friend class HttpHeaders; | |
186 }; | |
187 | |
188 class HttpHeaderTable { | |
189 // Construct an HttpHeaderTable to declare which headers you'll be interested in later on, and | |
190 // to manufacture IDs for them. | |
191 // | |
192 // Example: | |
193 // | |
194 // // Build a header table with the headers we are interested in. | |
195 // kj::HttpHeaderTable::Builder builder; | |
196 // const HttpHeaderId accept = builder.add("Accept"); | |
197 // const HttpHeaderId contentType = builder.add("Content-Type"); | |
198 // kj::HttpHeaderTable table(kj::mv(builder)); | |
199 // | |
200 // // Create an HTTP client. | |
201 // auto client = kj::newHttpClient(table, network); | |
202 // | |
203 // // Get http://example.com. | |
204 // HttpHeaders headers(table); | |
205 // headers.set(accept, "text/html"); | |
206 // auto response = client->send(kj::HttpMethod::GET, "http://example.com", headers) | |
207 // .wait(waitScope); | |
208 // auto msg = kj::str("Response content type: ", response.headers.get(contentType)); | |
209 | |
210 struct IdsByNameMap; | |
211 | |
212 public: | |
213 HttpHeaderTable(); | |
214 // Constructs a table that only contains the builtin headers. | |
215 | |
216 class Builder { | |
217 public: | |
218 Builder(); | |
219 HttpHeaderId add(kj::StringPtr name); | |
220 Own<HttpHeaderTable> build(); | |
221 | |
222 HttpHeaderTable& getFutureTable(); | |
223 // Get the still-unbuilt header table. You cannot actually use it until build() has been | |
224 // called. | |
225 // | |
226 // This method exists to help when building a shared header table -- the Builder may be passed | |
227 // to several components, each of which will register the headers they need and get a reference | |
228 // to the future table. | |
229 | |
230 private: | |
231 kj::Own<HttpHeaderTable> table; | |
232 }; | |
233 | |
234 KJ_DISALLOW_COPY_AND_MOVE(HttpHeaderTable); // Can't copy because HttpHeaderId points to the table. | |
235 ~HttpHeaderTable() noexcept(false); | |
236 | |
237 uint idCount() const; | |
238 // Return the number of IDs in the table. | |
239 | |
240 kj::Maybe<HttpHeaderId> stringToId(kj::StringPtr name) const; | |
241 // Try to find an ID for the given name. The matching is case-insensitive, per the HTTP spec. | |
242 // | |
243 // Note: if `name` contains characters that aren't allowed in HTTP header names, this may return | |
244 // a bogus value rather than null, due to optimizations used in case-insensitive matching. | |
245 | |
246 kj::StringPtr idToString(HttpHeaderId id) const; | |
247 // Get the canonical string name for the given ID. | |
248 | |
249 bool isReady() const; | |
250 // Returns true if this HttpHeaderTable either was default constructed or its Builder has | |
251 // invoked `build()` and released it. | |
252 | |
253 private: | |
254 kj::Vector<kj::StringPtr> namesById; | |
255 kj::Own<IdsByNameMap> idsByName; | |
256 | |
257 enum class BuildStatus { | |
258 UNSTARTED = 0, | |
259 BUILDING = 1, | |
260 FINISHED = 2, | |
261 }; | |
262 BuildStatus buildStatus = BuildStatus::UNSTARTED; | |
263 }; | |
264 | |
265 class HttpHeaders { | |
266 // Represents a set of HTTP headers. | |
267 // | |
268 // This class guards against basic HTTP header injection attacks: Trying to set a header name or | |
269 // value containing a newline, carriage return, or other invalid character will throw an | |
270 // exception. | |
271 | |
272 public: | |
273 explicit HttpHeaders(const HttpHeaderTable& table); | |
274 | |
275 static bool isValidHeaderValue(kj::StringPtr value); | |
276 // This returns whether the value is a valid parameter to the set call. While the HTTP spec | |
277 // suggests that only printable ASCII characters are allowed in header values, in practice that | |
278 // turns out to not be the case. We follow the browser's lead in disallowing \r and \n. | |
279 // https://github.com/httpwg/http11bis/issues/19 | |
280 // Use this if you want to validate the value before supplying it to set() if you want to avoid | |
281 // an exception being thrown (e.g. you have custom error reporting). NOTE that set will still | |
282 // validate the value. If performance is a problem this API needs to be adjusted to a | |
283 // `validateHeaderValue` function that returns a special type that set can be confident has | |
284 // already passed through the validation routine. | |
285 | |
286 KJ_DISALLOW_COPY(HttpHeaders); | |
287 HttpHeaders(HttpHeaders&&) = default; | |
288 HttpHeaders& operator=(HttpHeaders&&) = default; | |
289 | |
290 size_t size() const; | |
291 // Returns the number of headers that forEach() would iterate over. | |
292 | |
293 void clear(); | |
294 // Clears all contents, as if the object was freshly-allocated. However, calling this rather | |
295 // than actually re-allocating the object may avoid re-allocation of internal objects. | |
296 | |
297 HttpHeaders clone() const; | |
298 // Creates a deep clone of the HttpHeaders. The returned object owns all strings it references. | |
299 | |
300 HttpHeaders cloneShallow() const; | |
301 // Creates a shallow clone of the HttpHeaders. The returned object references the same strings | |
302 // as the original, owning none of them. | |
303 | |
304 bool isWebSocket() const; | |
305 // Convenience method that checks for the presence of the header `Upgrade: websocket`. | |
306 // | |
307 // Note that this does not actually validate that the request is a complete WebSocket handshake | |
308 // with the correct version number -- such validation will occur if and when you call | |
309 // acceptWebSocket(). | |
310 | |
311 kj::Maybe<kj::StringPtr> get(HttpHeaderId id) const; | |
312 // Read a header. | |
313 // | |
314 // Note that there is intentionally no method to look up a header by string name rather than | |
315 // header ID. The intent is that you should always allocate a header ID for any header that you | |
316 // care about, so that you can get() it by ID. Headers with registered IDs are stored in an array | |
317 // indexed by ID, making lookup fast. Headers without registered IDs are stored in a separate list | |
318 // that is optimized for re-transmission of the whole list, but not for lookup. | |
319 | |
320 template <typename Func> | |
321 void forEach(Func&& func) const; | |
322 // Calls `func(name, value)` for each header in the set -- including headers that aren't mapped | |
323 // to IDs in the header table. Both inputs are of type kj::StringPtr. | |
324 | |
325 template <typename Func1, typename Func2> | |
326 void forEach(Func1&& func1, Func2&& func2) const; | |
327 // Calls `func1(id, value)` for each header in the set that has a registered HttpHeaderId, and | |
328 // `func2(name, value)` for each header that does not. All calls to func1() precede all calls to | |
329 // func2(). | |
330 | |
331 void set(HttpHeaderId id, kj::StringPtr value); | |
332 void set(HttpHeaderId id, kj::String&& value); | |
333 // Sets a header value, overwriting the existing value. | |
334 // | |
335 // The String&& version is equivalent to calling the other version followed by takeOwnership(). | |
336 // | |
337 // WARNING: It is the caller's responsibility to ensure that `value` remains valid until the | |
338 // HttpHeaders object is destroyed. This allows string literals to be passed without making a | |
339 // copy, but complicates the use of dynamic values. Hint: Consider using `takeOwnership()`. | |
340 | |
341 void add(kj::StringPtr name, kj::StringPtr value); | |
342 void add(kj::StringPtr name, kj::String&& value); | |
343 void add(kj::String&& name, kj::String&& value); | |
344 // Append a header. `name` will be looked up in the header table, but if it's not mapped, the | |
345 // header will be added to the list of unmapped headers. | |
346 // | |
347 // The String&& versions are equivalent to calling the other version followed by takeOwnership(). | |
348 // | |
349 // WARNING: It is the caller's responsibility to ensure that `name` and `value` remain valid | |
350 // until the HttpHeaders object is destroyed. This allows string literals to be passed without | |
351 // making a copy, but complicates the use of dynamic values. Hint: Consider using | |
352 // `takeOwnership()`. | |
353 | |
354 void unset(HttpHeaderId id); | |
355 // Removes a header. | |
356 // | |
357 // It's not possible to remove a header by string name because non-indexed headers would take | |
358 // O(n) time to remove. Instead, construct a new HttpHeaders object and copy contents. | |
359 | |
360 void takeOwnership(kj::String&& string); | |
361 void takeOwnership(kj::Array<char>&& chars); | |
362 void takeOwnership(HttpHeaders&& otherHeaders); | |
363 // Takes ownership of a string so that it lives until the HttpHeaders object is destroyed. Useful | |
364 // when you've passed a dynamic value to set() or add() or parse*(). | |
365 | |
366 struct Request { | |
367 HttpMethod method; | |
368 kj::StringPtr url; | |
369 }; | |
370 struct ConnectRequest { | |
371 kj::StringPtr authority; | |
372 }; | |
373 struct Response { | |
374 uint statusCode; | |
375 kj::StringPtr statusText; | |
376 }; | |
377 | |
378 struct ProtocolError { | |
379 // Represents a protocol error, such as a bad request method or invalid headers. Debugging such | |
380 // errors is difficult without a copy of the data which we tried to parse, but this data is | |
381 // sensitive, so we can't just lump it into the error description directly. ProtocolError | |
382 // provides this sensitive data separate from the error description. | |
383 // | |
384 // TODO(cleanup): Should maybe not live in HttpHeaders? HttpServerErrorHandler::ProtocolError? | |
385 // Or HttpProtocolError? Or maybe we need a more general way of attaching sensitive context to | |
386 // kj::Exceptions? | |
387 | |
388 uint statusCode; | |
389 // Suggested HTTP status code that should be used when returning an error to the client. | |
390 // | |
391 // Most errors are 400. An unrecognized method will be 501. | |
392 | |
393 kj::StringPtr statusMessage; | |
394 // HTTP status message to go with `statusCode`, e.g. "Bad Request". | |
395 | |
396 kj::StringPtr description; | |
397 // An error description safe for all the world to see. | |
398 | |
399 kj::ArrayPtr<char> rawContent; | |
400 // Unredacted data which led to the error condition. This may contain anything transported over | |
401 // HTTP, to include sensitive PII, so you must take care to sanitize this before using it in any | |
402 // error report that may leak to unprivileged eyes. | |
403 // | |
404 // This ArrayPtr is merely a copy of the `content` parameter passed to `tryParseRequest()` / | |
405 // `tryParseResponse()`, thus it remains valid for as long as a successfully-parsed HttpHeaders | |
406 // object would remain valid. | |
407 }; | |
408 | |
409 using RequestOrProtocolError = kj::OneOf<Request, ProtocolError>; | |
410 using ResponseOrProtocolError = kj::OneOf<Response, ProtocolError>; | |
411 using RequestConnectOrProtocolError = kj::OneOf<Request, ConnectRequest, ProtocolError>; | |
412 | |
413 RequestOrProtocolError tryParseRequest(kj::ArrayPtr<char> content); | |
414 RequestConnectOrProtocolError tryParseRequestOrConnect(kj::ArrayPtr<char> content); | |
415 ResponseOrProtocolError tryParseResponse(kj::ArrayPtr<char> content); | |
416 | |
417 // Parse an HTTP header blob and add all the headers to this object. | |
418 // | |
419 // `content` should be all text from the start of the request to the first occurrence of two | |
420 // newlines in a row -- including the first of these two newlines, but excluding the second. | |
421 // | |
422 // The parse is performed with zero copies: The callee clobbers `content` with '\0' characters | |
423 // to split it into a bunch of shorter strings. The caller must keep `content` valid until the | |
424 // `HttpHeaders` is destroyed, or pass it to `takeOwnership()`. | |
425 | |
426 bool tryParse(kj::ArrayPtr<char> content); | |
427 // Like tryParseRequest()/tryParseResponse(), but don't expect any request/response line. | |
428 | |
429 kj::String serializeRequest(HttpMethod method, kj::StringPtr url, | |
430 kj::ArrayPtr<const kj::StringPtr> connectionHeaders = nullptr) const; | |
431 kj::String serializeConnectRequest(kj::StringPtr authority, | |
432 kj::ArrayPtr<const kj::StringPtr> connectionHeaders = nullptr) const; | |
433 kj::String serializeResponse(uint statusCode, kj::StringPtr statusText, | |
434 kj::ArrayPtr<const kj::StringPtr> connectionHeaders = nullptr) const; | |
435 // **Most applications will not use these methods; they are called by the HTTP client and server | |
436 // implementations.** | |
437 // | |
438 // Serialize the headers as a complete request or response blob. The blob uses '\r\n' newlines | |
439 // and includes the double-newline to indicate the end of the headers. | |
440 // | |
441 // `connectionHeaders`, if provided, contains connection-level headers supplied by the HTTP | |
442 // implementation, in the order specified by the KJ_HTTP_FOR_EACH_BUILTIN_HEADER macro. These | |
443 // headers values override any corresponding header value in the HttpHeaders object. The | |
444 // CONNECTION_HEADERS_COUNT constants below can help you construct this `connectionHeaders` array. | |
445 | |
446 enum class BuiltinIndicesEnum { | |
447 #define HEADER_ID(id, name) id, | |
448 KJ_HTTP_FOR_EACH_BUILTIN_HEADER(HEADER_ID) | |
449 #undef HEADER_ID | |
450 }; | |
451 | |
452 struct BuiltinIndices { | |
453 #define HEADER_ID(id, name) static constexpr uint id = static_cast<uint>(BuiltinIndicesEnum::id); | |
454 KJ_HTTP_FOR_EACH_BUILTIN_HEADER(HEADER_ID) | |
455 #undef HEADER_ID | |
456 }; | |
457 | |
458 static constexpr uint HEAD_RESPONSE_CONNECTION_HEADERS_COUNT = BuiltinIndices::CONTENT_LENGTH; | |
459 static constexpr uint CONNECTION_HEADERS_COUNT = BuiltinIndices::SEC_WEBSOCKET_KEY; | |
460 static constexpr uint WEBSOCKET_CONNECTION_HEADERS_COUNT = BuiltinIndices::HOST; | |
461 // Constants for use with HttpHeaders::serialize*(). | |
462 | |
463 kj::String toString() const; | |
464 | |
465 private: | |
466 const HttpHeaderTable* table; | |
467 | |
468 kj::Array<kj::StringPtr> indexedHeaders; | |
469 // Size is always table->idCount(). | |
470 | |
471 struct Header { | |
472 kj::StringPtr name; | |
473 kj::StringPtr value; | |
474 }; | |
475 kj::Vector<Header> unindexedHeaders; | |
476 | |
477 kj::Vector<kj::Array<char>> ownedStrings; | |
478 | |
479 void addNoCheck(kj::StringPtr name, kj::StringPtr value); | |
480 | |
481 kj::StringPtr cloneToOwn(kj::StringPtr str); | |
482 | |
483 kj::String serialize(kj::ArrayPtr<const char> word1, | |
484 kj::ArrayPtr<const char> word2, | |
485 kj::ArrayPtr<const char> word3, | |
486 kj::ArrayPtr<const kj::StringPtr> connectionHeaders) const; | |
487 | |
488 bool parseHeaders(char* ptr, char* end); | |
489 | |
490 // TODO(perf): Arguably we should store a map, but header sets are never very long | |
491 // TODO(perf): We could optimize for common headers by storing them directly as fields. We could | |
492 // also add direct accessors for those headers. | |
493 }; | |
494 | |
495 class HttpInputStream { | |
496 // Low-level interface to receive HTTP-formatted messages (headers followed by body) from an | |
497 // input stream, without a paired output stream. | |
498 // | |
499 // Most applications will not use this. Regular HTTP clients and servers don't need this. This | |
500 // is mainly useful for apps implementing various protocols that look like HTTP but aren't | |
501 // really. | |
502 | |
503 public: | |
504 struct Request { | |
505 HttpMethod method; | |
506 kj::StringPtr url; | |
507 const HttpHeaders& headers; | |
508 kj::Own<kj::AsyncInputStream> body; | |
509 }; | |
510 virtual kj::Promise<Request> readRequest() = 0; | |
511 // Reads one HTTP request from the input stream. | |
512 // | |
513 // The returned struct contains pointers directly into a buffer that is invalidated on the next | |
514 // message read. | |
515 | |
516 struct Connect { | |
517 kj::StringPtr authority; | |
518 const HttpHeaders& headers; | |
519 kj::Own<kj::AsyncInputStream> body; | |
520 }; | |
521 virtual kj::Promise<kj::OneOf<Request, Connect>> readRequestAllowingConnect() = 0; | |
522 // Reads one HTTP request from the input stream. | |
523 // | |
524 // The returned struct contains pointers directly into a buffer that is invalidated on the next | |
525 // message read. | |
526 | |
527 struct Response { | |
528 uint statusCode; | |
529 kj::StringPtr statusText; | |
530 const HttpHeaders& headers; | |
531 kj::Own<kj::AsyncInputStream> body; | |
532 }; | |
533 virtual kj::Promise<Response> readResponse(HttpMethod requestMethod) = 0; | |
534 // Reads one HTTP response from the input stream. | |
535 // | |
536 // You must provide the request method because responses to HEAD requests require special | |
537 // treatment. | |
538 // | |
539 // The returned struct contains pointers directly into a buffer that is invalidated on the next | |
540 // message read. | |
541 | |
542 struct Message { | |
543 const HttpHeaders& headers; | |
544 kj::Own<kj::AsyncInputStream> body; | |
545 }; | |
546 virtual kj::Promise<Message> readMessage() = 0; | |
547 // Reads an HTTP header set followed by a body, with no request or response line. This is not | |
548 // useful for HTTP but may be useful for other protocols that make the unfortunate choice to | |
549 // mimic HTTP message format, such as Visual Studio Code's JSON-RPC transport. | |
550 // | |
551 // The returned struct contains pointers directly into a buffer that is invalidated on the next | |
552 // message read. | |
553 | |
554 virtual kj::Promise<bool> awaitNextMessage() = 0; | |
555 // Waits until more data is available, but doesn't consume it. Returns false on EOF. | |
556 }; | |
557 | |
558 class EntropySource { | |
559 // Interface for an object that generates entropy. Typically, cryptographically-random entropy | |
560 // is expected. | |
561 // | |
562 // TODO(cleanup): Put this somewhere more general. | |
563 | |
564 public: | |
565 virtual void generate(kj::ArrayPtr<byte> buffer) = 0; | |
566 }; | |
567 | |
568 struct CompressionParameters { | |
569 // These are the parameters for `Sec-WebSocket-Extensions` permessage-deflate extension. | |
570 // Since we cannot distinguish the client/server in `upgradeToWebSocket`, we use the prefixes | |
571 // `inbound` and `outbound` instead. | |
572 bool outboundNoContextTakeover = false; | |
573 bool inboundNoContextTakeover = false; | |
574 kj::Maybe<size_t> outboundMaxWindowBits = nullptr; | |
575 kj::Maybe<size_t> inboundMaxWindowBits = nullptr; | |
576 }; | |
577 | |
578 class WebSocket { | |
579 // Interface representincg an open WebSocket session. | |
580 // | |
581 // Each side can send and receive data and "close" messages. | |
582 // | |
583 // Ping/Pong and message fragmentation are not exposed through this interface. These features of | |
584 // the underlying WebSocket protocol are not exposed by the browser-level JavaScript API either, | |
585 // and thus applications typically need to implement these features at the application protocol | |
586 // level instead. The implementation is, however, expected to reply to Ping messages it receives. | |
587 | |
588 public: | |
589 virtual kj::Promise<void> send(kj::ArrayPtr<const byte> message) = 0; | |
590 virtual kj::Promise<void> send(kj::ArrayPtr<const char> message) = 0; | |
591 // Send a message (binary or text). The underlying buffer must remain valid, and you must not | |
592 // call send() again, until the returned promise resolves. | |
593 | |
594 virtual kj::Promise<void> close(uint16_t code, kj::StringPtr reason) = 0; | |
595 // Send a Close message. | |
596 // | |
597 // Note that the returned Promise resolves once the message has been sent -- it does NOT wait | |
598 // for the other end to send a Close reply. The application should await a reply before dropping | |
599 // the WebSocket object. | |
600 | |
601 virtual kj::Promise<void> disconnect() = 0; | |
602 // Sends EOF on the underlying connection without sending a "close" message. This is NOT a clean | |
603 // shutdown, but is sometimes useful when you want the other end to trigger whatever behavior | |
604 // it normally triggers when a connection is dropped. | |
605 | |
606 virtual void abort() = 0; | |
607 // Forcefully close this WebSocket, such that the remote end should get a DISCONNECTED error if | |
608 // it continues to write. This differs from disconnect(), which only closes the sending | |
609 // direction, but still allows receives. | |
610 | |
611 virtual kj::Promise<void> whenAborted() = 0; | |
612 // Resolves when the remote side aborts the connection such that send() would throw DISCONNECTED, | |
613 // if this can be detected without actually writing a message. (If not, this promise never | |
614 // resolves, but send() or receive() will throw DISCONNECTED when appropriate. See also | |
615 // kj::AsyncOutputStream::whenWriteDisconnected().) | |
616 | |
617 struct ProtocolError { | |
618 // Represents a protocol error, such as a bad opcode or oversize message. | |
619 | |
620 uint statusCode; | |
621 // Suggested WebSocket status code that should be used when returning an error to the client. | |
622 // | |
623 // Most errors are 1002; an oversize message will be 1009. | |
624 | |
625 kj::StringPtr description; | |
626 // An error description safe for all the world to see. This should be at most 123 bytes so that | |
627 // it can be used as the body of a Close frame (RFC 6455 sections 5.5 and 5.5.1). | |
628 }; | |
629 | |
630 struct Close { | |
631 uint16_t code; | |
632 kj::String reason; | |
633 }; | |
634 | |
635 typedef kj::OneOf<kj::String, kj::Array<byte>, Close> Message; | |
636 | |
637 static constexpr size_t SUGGESTED_MAX_MESSAGE_SIZE = 1u << 20; // 1MB | |
638 | |
639 virtual kj::Promise<Message> receive(size_t maxSize = SUGGESTED_MAX_MESSAGE_SIZE) = 0; | |
640 // Read one message from the WebSocket and return it. Can only call once at a time. Do not call | |
641 // again after Close is received. | |
642 | |
643 virtual kj::Promise<void> pumpTo(WebSocket& other); | |
644 // Continuously receives messages from this WebSocket and send them to `other`. | |
645 // | |
646 // On EOF, calls other.disconnect(), then resolves. | |
647 // | |
648 // On other read errors, calls other.close() with the error, then resolves. | |
649 // | |
650 // On write error, rejects with the error. | |
651 | |
652 virtual kj::Maybe<kj::Promise<void>> tryPumpFrom(WebSocket& other); | |
653 // Either returns null, or performs the equivalent of other.pumpTo(*this). Only returns non-null | |
654 // if this WebSocket implementation is able to perform the pump in an optimized way, better than | |
655 // the default implementation of pumpTo(). The default implementation of pumpTo() always tries | |
656 // calling this first, and the default implementation of tryPumpFrom() always returns null. | |
657 | |
658 virtual uint64_t sentByteCount() = 0; | |
659 virtual uint64_t receivedByteCount() = 0; | |
660 | |
661 enum ExtensionsContext { | |
662 // Indicate whether a Sec-WebSocket-Extension header should be rendered for use in request | |
663 // headers or response headers. | |
664 REQUEST, | |
665 RESPONSE | |
666 }; | |
667 virtual kj::Maybe<kj::String> getPreferredExtensions(ExtensionsContext ctx) { return nullptr; } | |
668 // If pumpTo() / tryPumpFrom() is able to be optimized only if the other WebSocket is using | |
669 // certain extensions (e.g. compression settings), then this method returns what those extensions | |
670 // are. For example, matching extensions between standard WebSockets allows pumping to be | |
671 // implemented by pumping raw bytes between network connections, without reading individual frames. | |
672 // | |
673 // A null return value indicates that there is no preference. A non-null return value containing | |
674 // an empty string indicates a preference for no extensions to be applied. | |
675 }; | |
676 | |
677 using TlsStarterCallback = kj::Maybe<kj::Function<kj::Promise<void>(kj::StringPtr)>>; | |
678 struct HttpConnectSettings { | |
679 bool useTls = false; | |
680 // Requests to automatically establish a TLS session over the connection. The remote party | |
681 // will be expected to present a valid certificate matching the requested hostname. | |
682 kj::Maybe<TlsStarterCallback&> tlsStarter; | |
683 // This is an output parameter. It doesn't need to be set. But if it is set, then it may get | |
684 // filled with a callback function. It will get filled with `nullptr` if any of the following | |
685 // are true: | |
686 // | |
687 // * kj is not built with TLS support | |
688 // * the underlying HttpClient does not support the startTls mechanism | |
689 // * `useTls` has been set to `true` and so TLS has already been started | |
690 // | |
691 // The callback function itself can be called to initiate a TLS handshake on the connection in | |
692 // between write() operations. It is not allowed to initiate a TLS handshake while a write | |
693 // operation or a pump operation to the connection exists. Read operations are not subject to | |
694 // the same constraint, however: implementations are required to be able to handle TLS | |
695 // initiation while a read operation or pump operation from the connection exists. Once the | |
696 // promise returned from the callback is fulfilled, the connection has become a secure stream, | |
697 // and write operations are once again permitted. The StringPtr parameter to the callback, | |
698 // expectedServerHostname may be dropped after the function synchronously returns. | |
699 // | |
700 // The PausableReadAsyncIoStream class defined below can be used to ensure that read operations | |
701 // are not pending when the tlsStarter is invoked. | |
702 // | |
703 // This mechanism is required for certain protocols, more info can be found on | |
704 // https://en.wikipedia.org/wiki/Opportunistic_TLS. | |
705 }; | |
706 | |
707 | |
708 class PausableReadAsyncIoStream final: public kj::AsyncIoStream { | |
709 // A custom AsyncIoStream which can pause pending reads. This is used by startTls to pause a | |
710 // a read before TLS is initiated. | |
711 // | |
712 // TODO(cleanup): this class should be rewritten to use a CRTP mixin approach so that pumps | |
713 // can be optimised once startTls is invoked. | |
714 class PausableRead; | |
715 public: | |
716 PausableReadAsyncIoStream(kj::Own<kj::AsyncIoStream> stream) | |
717 : inner(kj::mv(stream)), currentlyWriting(false), currentlyReading(false) {} | |
718 | |
719 _::Deferred<kj::Function<void()>> trackRead(); | |
720 | |
721 _::Deferred<kj::Function<void()>> trackWrite(); | |
722 | |
723 kj::Promise<size_t> tryRead(void* buffer, size_t minBytes, size_t maxBytes) override; | |
724 | |
725 kj::Promise<size_t> tryReadImpl(void* buffer, size_t minBytes, size_t maxBytes); | |
726 | |
727 kj::Maybe<uint64_t> tryGetLength() override; | |
728 | |
729 kj::Promise<uint64_t> pumpTo(kj::AsyncOutputStream& output, uint64_t amount) override; | |
730 | |
731 kj::Promise<void> write(const void* buffer, size_t size) override; | |
732 | |
733 kj::Promise<void> write(kj::ArrayPtr<const kj::ArrayPtr<const byte>> pieces) override; | |
734 | |
735 kj::Maybe<kj::Promise<uint64_t>> tryPumpFrom( | |
736 kj::AsyncInputStream& input, uint64_t amount = kj::maxValue) override; | |
737 | |
738 kj::Promise<void> whenWriteDisconnected() override; | |
739 | |
740 void shutdownWrite() override; | |
741 | |
742 void abortRead() override; | |
743 | |
744 kj::Maybe<int> getFd() const override; | |
745 | |
746 void pause(); | |
747 | |
748 void unpause(); | |
749 | |
750 bool getCurrentlyReading(); | |
751 | |
752 bool getCurrentlyWriting(); | |
753 | |
754 kj::Own<kj::AsyncIoStream> takeStream(); | |
755 | |
756 void replaceStream(kj::Own<kj::AsyncIoStream> stream); | |
757 | |
758 void reject(kj::Exception&& exc); | |
759 | |
760 private: | |
761 kj::Own<kj::AsyncIoStream> inner; | |
762 kj::Maybe<PausableRead&> maybePausableRead; | |
763 bool currentlyWriting; | |
764 bool currentlyReading; | |
765 }; | |
766 | |
767 class HttpClient { | |
768 // Interface to the client end of an HTTP connection. | |
769 // | |
770 // There are two kinds of clients: | |
771 // * Host clients are used when talking to a specific host. The `url` specified in a request | |
772 // is actually just a path. (A `Host` header is still required in all requests.) | |
773 // * Proxy clients are used when the target could be any arbitrary host on the internet. | |
774 // The `url` specified in a request is a full URL including protocol and hostname. | |
775 | |
776 public: | |
777 struct Response { | |
778 uint statusCode; | |
779 kj::StringPtr statusText; | |
780 const HttpHeaders* headers; | |
781 kj::Own<kj::AsyncInputStream> body; | |
782 // `statusText` and `headers` remain valid until `body` is dropped or read from. | |
783 }; | |
784 | |
785 struct Request { | |
786 kj::Own<kj::AsyncOutputStream> body; | |
787 // Write the request entity body to this stream, then drop it when done. | |
788 // | |
789 // May be null for GET and HEAD requests (which have no body) and requests that have | |
790 // Content-Length: 0. | |
791 | |
792 kj::Promise<Response> response; | |
793 // Promise for the eventual response. | |
794 }; | |
795 | |
796 virtual Request request(HttpMethod method, kj::StringPtr url, const HttpHeaders& headers, | |
797 kj::Maybe<uint64_t> expectedBodySize = nullptr) = 0; | |
798 // Perform an HTTP request. | |
799 // | |
800 // `url` may be a full URL (with protocol and host) or it may be only the path part of the URL, | |
801 // depending on whether the client is a proxy client or a host client. | |
802 // | |
803 // `url` and `headers` need only remain valid until `request()` returns (they can be | |
804 // stack-allocated). | |
805 // | |
806 // `expectedBodySize`, if provided, must be exactly the number of bytes that will be written to | |
807 // the body. This will trigger use of the `Content-Length` connection header. Otherwise, | |
808 // `Transfer-Encoding: chunked` will be used. | |
809 | |
810 struct WebSocketResponse { | |
811 uint statusCode; | |
812 kj::StringPtr statusText; | |
813 const HttpHeaders* headers; | |
814 kj::OneOf<kj::Own<kj::AsyncInputStream>, kj::Own<WebSocket>> webSocketOrBody; | |
815 // `statusText` and `headers` remain valid until `webSocketOrBody` is dropped or read from. | |
816 }; | |
817 virtual kj::Promise<WebSocketResponse> openWebSocket( | |
818 kj::StringPtr url, const HttpHeaders& headers); | |
819 // Tries to open a WebSocket. Default implementation calls send() and never returns a WebSocket. | |
820 // | |
821 // `url` and `headers` need only remain valid until `openWebSocket()` returns (they can be | |
822 // stack-allocated). | |
823 | |
824 struct ConnectRequest { | |
825 struct Status { | |
826 uint statusCode; | |
827 kj::String statusText; | |
828 kj::Own<HttpHeaders> headers; | |
829 kj::Maybe<kj::Own<kj::AsyncInputStream>> errorBody; | |
830 // If the connect request is rejected, the statusCode can be any HTTP status code | |
831 // outside the 200-299 range and errorBody *may* be specified if there is a rejection | |
832 // payload. | |
833 | |
834 // TODO(perf): Having Status own the statusText and headers is a bit unfortunate. | |
835 // Ideally we could have these be non-owned so that the headers object could just | |
836 // point directly into HttpOutputStream's buffer and not be copied. That's a bit | |
837 // more difficult to with CONNECT since the lifetimes of the buffers are a little | |
838 // different than with regular HTTP requests. It should still be possible but for | |
839 // now copying and owning the status text and headers is easier. | |
840 | |
841 Status(uint statusCode, | |
842 kj::String statusText, | |
843 kj::Own<HttpHeaders> headers, | |
844 kj::Maybe<kj::Own<kj::AsyncInputStream>> errorBody = nullptr) | |
845 : statusCode(statusCode), | |
846 statusText(kj::mv(statusText)), | |
847 headers(kj::mv(headers)), | |
848 errorBody(kj::mv(errorBody)) {} | |
849 }; | |
850 | |
851 kj::Promise<Status> status; | |
852 kj::Own<kj::AsyncIoStream> connection; | |
853 }; | |
854 | |
855 virtual ConnectRequest connect( | |
856 kj::StringPtr host, const HttpHeaders& headers, HttpConnectSettings settings); | |
857 // Handles CONNECT requests. | |
858 // | |
859 // `host` must specify both the host and port (e.g. "example.org:1234"). | |
860 // | |
861 // The `host` and `headers` need only remain valid until `connect()` returns (it can be | |
862 // stack-allocated). | |
863 }; | |
864 | |
865 class HttpService { | |
866 // Interface which HTTP services should implement. | |
867 // | |
868 // This interface is functionally equivalent to HttpClient, but is intended for applications to | |
869 // implement rather than call. The ergonomics and performance of the method signatures are | |
870 // optimized for the serving end. | |
871 // | |
872 // As with clients, there are two kinds of services: | |
873 // * Host services are used when talking to a specific host. The `url` specified in a request | |
874 // is actually just a path. (A `Host` header is still required in all requests, and the service | |
875 // may in fact serve multiple origins via this header.) | |
876 // * Proxy services are used when the target could be any arbitrary host on the internet, i.e. to | |
877 // implement an HTTP proxy. The `url` specified in a request is a full URL including protocol | |
878 // and hostname. | |
879 | |
880 public: | |
881 class Response { | |
882 public: | |
883 virtual kj::Own<kj::AsyncOutputStream> send( | |
884 uint statusCode, kj::StringPtr statusText, const HttpHeaders& headers, | |
885 kj::Maybe<uint64_t> expectedBodySize = nullptr) = 0; | |
886 // Begin the response. | |
887 // | |
888 // `statusText` and `headers` need only remain valid until send() returns (they can be | |
889 // stack-allocated). | |
890 // | |
891 // `send()` may only be called a single time. Calling it a second time will cause an exception | |
892 // to be thrown. | |
893 | |
894 virtual kj::Own<WebSocket> acceptWebSocket(const HttpHeaders& headers) = 0; | |
895 // If headers.isWebSocket() is true then you can call acceptWebSocket() instead of send(). | |
896 // | |
897 // If the request is an invalid WebSocket request (e.g., it has an Upgrade: websocket header, | |
898 // but other WebSocket-related headers are invalid), `acceptWebSocket()` will throw an | |
899 // exception, and the HttpServer will return a 400 Bad Request response and close the | |
900 // connection. In this circumstance, the HttpServer will ignore any exceptions which propagate | |
901 // from the `HttpService::request()` promise. `HttpServerErrorHandler::handleApplicationError()` | |
902 // will not be invoked, and the HttpServer's listen task will be fulfilled normally. | |
903 // | |
904 // `acceptWebSocket()` may only be called a single time. Calling it a second time will cause an | |
905 // exception to be thrown. | |
906 | |
907 kj::Promise<void> sendError(uint statusCode, kj::StringPtr statusText, | |
908 const HttpHeaders& headers); | |
909 kj::Promise<void> sendError(uint statusCode, kj::StringPtr statusText, | |
910 const HttpHeaderTable& headerTable); | |
911 // Convenience wrapper around send() which sends a basic error. A generic error page specifying | |
912 // the error code is sent as the body. | |
913 // | |
914 // You must provide headers or a header table because downstream service wrappers may be | |
915 // expecting response headers built with a particular table so that they can insert additional | |
916 // headers. | |
917 }; | |
918 | |
919 virtual kj::Promise<void> request( | |
920 HttpMethod method, kj::StringPtr url, const HttpHeaders& headers, | |
921 kj::AsyncInputStream& requestBody, Response& response) = 0; | |
922 // Perform an HTTP request. | |
923 // | |
924 // `url` may be a full URL (with protocol and host) or it may be only the path part of the URL, | |
925 // depending on whether the service is a proxy service or a host service. | |
926 // | |
927 // `url` and `headers` are invalidated on the first read from `requestBody` or when the returned | |
928 // promise resolves, whichever comes first. | |
929 // | |
930 // Request processing can be canceled by dropping the returned promise. HttpServer may do so if | |
931 // the client disconnects prematurely. | |
932 // | |
933 // The implementation of `request()` should usually not try to use `response` in any way in | |
934 // exception-handling code, because it is often not possible to tell whether `Response::send()` or | |
935 // `Response::acceptWebSocket()` has already been called. Instead, to generate error HTTP | |
936 // responses for the client, implement an HttpServerErrorHandler and pass it to the HttpServer via | |
937 // HttpServerSettings. If the `HttpService::request()` promise rejects and no response has yet | |
938 // been sent, `HttpServerErrorHandler::handleApplicationError()` will be passed a non-null | |
939 // `Maybe<Response&>` parameter. | |
940 | |
941 class ConnectResponse { | |
942 public: | |
943 virtual void accept( | |
944 uint statusCode, | |
945 kj::StringPtr statusText, | |
946 const HttpHeaders& headers) = 0; | |
947 // Signals acceptance of the CONNECT tunnel. | |
948 | |
949 virtual kj::Own<kj::AsyncOutputStream> reject( | |
950 uint statusCode, | |
951 kj::StringPtr statusText, | |
952 const HttpHeaders& headers, | |
953 kj::Maybe<uint64_t> expectedBodySize = nullptr) = 0; | |
954 // Signals rejection of the CONNECT tunnel. | |
955 }; | |
956 | |
957 virtual kj::Promise<void> connect(kj::StringPtr host, | |
958 const HttpHeaders& headers, | |
959 kj::AsyncIoStream& connection, | |
960 ConnectResponse& response, | |
961 HttpConnectSettings settings); | |
962 // Handles CONNECT requests. | |
963 // | |
964 // The `host` must include host and port. | |
965 // | |
966 // `host` and `headers` are invalidated when accept or reject is called on the ConnectResponse | |
967 // or when the returned promise resolves, whichever comes first. | |
968 // | |
969 // The connection is provided to support pipelining. Writes to the connection will be blocked | |
970 // until one of either accept() or reject() is called on tunnel. Reads from the connection are | |
971 // permitted at any time. | |
972 // | |
973 // Request processing can be canceled by dropping the returned promise. HttpServer may do so if | |
974 // the client disconnects prematurely. | |
975 }; | |
976 | |
977 class HttpClientErrorHandler { | |
978 public: | |
979 virtual HttpClient::Response handleProtocolError(HttpHeaders::ProtocolError protocolError); | |
980 // Override this function to customize error handling when the client receives an HTTP message | |
981 // that fails to parse. The default implementations throws an exception. | |
982 // | |
983 // There are two main use cases for overriding this: | |
984 // 1. `protocolError` contains the actual header content that failed to parse, giving you the | |
985 // opportunity to log it for debugging purposes. The default implementation throws away this | |
986 // content. | |
987 // 2. You could potentially convert protocol errors into HTTP error codes, e.g. 502 Bad Gateway. | |
988 // | |
989 // Note that `protocolError` may contain pointers into buffers that are no longer valid once | |
990 // this method returns; you will have to make copies if you want to keep them. | |
991 | |
992 virtual HttpClient::WebSocketResponse handleWebSocketProtocolError( | |
993 HttpHeaders::ProtocolError protocolError); | |
994 // Like handleProtocolError() but for WebSocket requests. The default implementation calls | |
995 // handleProtocolError() and converts the Response to WebSocketResponse. There is probably very | |
996 // little reason to override this. | |
997 }; | |
998 | |
999 struct HttpClientSettings { | |
1000 kj::Duration idleTimeout = 5 * kj::SECONDS; | |
1001 // For clients which automatically create new connections, any connection idle for at least this | |
1002 // long will be closed. Set this to 0 to prevent connection reuse entirely. | |
1003 | |
1004 kj::Maybe<EntropySource&> entropySource = nullptr; | |
1005 // Must be provided in order to use `openWebSocket`. If you don't need WebSockets, this can be | |
1006 // omitted. The WebSocket protocol uses random values to avoid triggering flaws (including | |
1007 // security flaws) in certain HTTP proxy software. Specifically, entropy is used to generate the | |
1008 // `Sec-WebSocket-Key` header and to generate frame masks. If you know that there are no broken | |
1009 // or vulnerable proxies between you and the server, you can provide a dummy entropy source that | |
1010 // doesn't generate real entropy (e.g. returning the same value every time). Otherwise, you must | |
1011 // provide a cryptographically-random entropy source. | |
1012 | |
1013 kj::Maybe<HttpClientErrorHandler&> errorHandler = nullptr; | |
1014 // Customize how protocol errors are handled by the HttpClient. If null, HttpClientErrorHandler's | |
1015 // default implementation will be used. | |
1016 | |
1017 enum WebSocketCompressionMode { | |
1018 NO_COMPRESSION, | |
1019 MANUAL_COMPRESSION, // Lets the application decide the compression configuration (if any). | |
1020 AUTOMATIC_COMPRESSION, // Automatically includes the compression header in the WebSocket request. | |
1021 }; | |
1022 WebSocketCompressionMode webSocketCompressionMode = NO_COMPRESSION; | |
1023 | |
1024 kj::Maybe<SecureNetworkWrapper&> tlsContext; | |
1025 // A reference to a TLS context that will be used when tlsStarter is invoked. | |
1026 }; | |
1027 | |
1028 class WebSocketErrorHandler { | |
1029 public: | |
1030 virtual kj::Exception handleWebSocketProtocolError(WebSocket::ProtocolError protocolError); | |
1031 // Handles low-level protocol errors in received WebSocket data. | |
1032 // | |
1033 // This is called when the WebSocket peer sends us bad data *after* a successful WebSocket | |
1034 // upgrade, e.g. a continuation frame without a preceding start frame, a frame with an unknown | |
1035 // opcode, or similar. | |
1036 // | |
1037 // You would override this method in order to customize the exception. You cannot prevent the | |
1038 // exception from being thrown. | |
1039 }; | |
1040 | |
1041 kj::Own<HttpClient> newHttpClient(kj::Timer& timer, const HttpHeaderTable& responseHeaderTable, | |
1042 kj::Network& network, kj::Maybe<kj::Network&> tlsNetwork, | |
1043 HttpClientSettings settings = HttpClientSettings()); | |
1044 // Creates a proxy HttpClient that connects to hosts over the given network. The URL must always | |
1045 // be an absolute URL; the host is parsed from the URL. This implementation will automatically | |
1046 // add an appropriate Host header (and convert the URL to just a path) once it has connected. | |
1047 // | |
1048 // Note that if you wish to route traffic through an HTTP proxy server rather than connect to | |
1049 // remote hosts directly, you should use the form of newHttpClient() that takes a NetworkAddress, | |
1050 // and supply the proxy's address. | |
1051 // | |
1052 // `responseHeaderTable` is used when parsing HTTP responses. Requests can use any header table. | |
1053 // | |
1054 // `tlsNetwork` is required to support HTTPS destination URLs. If null, only HTTP URLs can be | |
1055 // fetched. | |
1056 | |
1057 kj::Own<HttpClient> newHttpClient(kj::Timer& timer, const HttpHeaderTable& responseHeaderTable, | |
1058 kj::NetworkAddress& addr, | |
1059 HttpClientSettings settings = HttpClientSettings()); | |
1060 // Creates an HttpClient that always connects to the given address no matter what URL is requested. | |
1061 // The client will open and close connections as needed. It will attempt to reuse connections for | |
1062 // multiple requests but will not send a new request before the previous response on the same | |
1063 // connection has completed, as doing so can result in head-of-line blocking issues. The client may | |
1064 // be used as a proxy client or a host client depending on whether the peer is operating as | |
1065 // a proxy. (Hint: This is the best kind of client to use when routing traffic through an HTTP | |
1066 // proxy. `addr` should be the address of the proxy, and the proxy itself will resolve remote hosts | |
1067 // based on the URLs passed to it.) | |
1068 // | |
1069 // `responseHeaderTable` is used when parsing HTTP responses. Requests can use any header table. | |
1070 | |
1071 kj::Own<HttpClient> newHttpClient(const HttpHeaderTable& responseHeaderTable, | |
1072 kj::AsyncIoStream& stream, | |
1073 HttpClientSettings settings = HttpClientSettings()); | |
1074 // Creates an HttpClient that speaks over the given pre-established connection. The client may | |
1075 // be used as a proxy client or a host client depending on whether the peer is operating as | |
1076 // a proxy. | |
1077 // | |
1078 // Note that since this client has only one stream to work with, it will try to pipeline all | |
1079 // requests on this stream. If one request or response has an I/O failure, all subsequent requests | |
1080 // fail as well. If the destination server chooses to close the connection after a response, | |
1081 // subsequent requests will fail. If a response takes a long time, it blocks subsequent responses. | |
1082 // If a WebSocket is opened successfully, all subsequent requests fail. | |
1083 | |
1084 kj::Own<HttpClient> newConcurrencyLimitingHttpClient( | |
1085 HttpClient& inner, uint maxConcurrentRequests, | |
1086 kj::Function<void(uint runningCount, uint pendingCount)> countChangedCallback); | |
1087 // Creates an HttpClient that is limited to a maximum number of concurrent requests. Additional | |
1088 // requests are queued, to be opened only after an open request completes. `countChangedCallback` | |
1089 // is called when a new connection is opened or enqueued and when an open connection is closed, | |
1090 // passing the number of open and pending connections. | |
1091 | |
1092 kj::Own<HttpClient> newHttpClient(HttpService& service); | |
1093 kj::Own<HttpService> newHttpService(HttpClient& client); | |
1094 // Adapts an HttpClient to an HttpService and vice versa. | |
1095 | |
1096 kj::Own<HttpInputStream> newHttpInputStream( | |
1097 kj::AsyncInputStream& input, const HttpHeaderTable& headerTable); | |
1098 // Create an HttpInputStream on top of the given stream. Normally applications would not call this | |
1099 // directly, but it can be useful for implementing protocols that aren't quite HTTP but use similar | |
1100 // message delimiting. | |
1101 // | |
1102 // The HttpInputStream implementation does read-ahead buffering on `input`. Therefore, when the | |
1103 // HttpInputStream is destroyed, some data read from `input` may be lost, so it's not possible to | |
1104 // continue reading from `input` in a reliable way. | |
1105 | |
1106 kj::Own<WebSocket> newWebSocket(kj::Own<kj::AsyncIoStream> stream, | |
1107 kj::Maybe<EntropySource&> maskEntropySource, | |
1108 kj::Maybe<CompressionParameters> compressionConfig = nullptr, | |
1109 kj::Maybe<WebSocketErrorHandler&> errorHandler = nullptr); | |
1110 // Create a new WebSocket on top of the given stream. It is assumed that the HTTP -> WebSocket | |
1111 // upgrade handshake has already occurred (or is not needed), and messages can immediately be | |
1112 // sent and received on the stream. Normally applications would not call this directly. | |
1113 // | |
1114 // `maskEntropySource` is used to generate cryptographically-random frame masks. If null, outgoing | |
1115 // frames will not be masked. Servers are required NOT to mask their outgoing frames, but clients | |
1116 // ARE required to do so. So, on the client side, you MUST specify an entropy source. The mask | |
1117 // must be crytographically random if the data being sent on the WebSocket may be malicious. The | |
1118 // purpose of the mask is to prevent badly-written HTTP proxies from interpreting "things that look | |
1119 // like HTTP requests" in a message as being actual HTTP requests, which could result in cache | |
1120 // poisoning. See RFC6455 section 10.3. | |
1121 // | |
1122 // `compressionConfig` is an optional argument that allows us to specify how the WebSocket should | |
1123 // compress and decompress messages. The configuration is determined by the | |
1124 // `Sec-WebSocket-Extensions` header during WebSocket negotiation. | |
1125 // | |
1126 // `errorHandler` is an optional argument that lets callers throw custom exceptions for WebSocket | |
1127 // protocol errors. | |
1128 | |
1129 struct WebSocketPipe { | |
1130 kj::Own<WebSocket> ends[2]; | |
1131 }; | |
1132 | |
1133 WebSocketPipe newWebSocketPipe(); | |
1134 // Create a WebSocket pipe. Messages written to one end of the pipe will be readable from the other | |
1135 // end. No buffering occurs -- a message send does not complete until a corresponding receive | |
1136 // accepts the message. | |
1137 | |
1138 class HttpServerErrorHandler; | |
1139 class HttpServerCallbacks; | |
1140 | |
1141 struct HttpServerSettings { | |
1142 kj::Duration headerTimeout = 15 * kj::SECONDS; | |
1143 // After initial connection open, or after receiving the first byte of a pipelined request, | |
1144 // the client must send the complete request within this time. | |
1145 | |
1146 kj::Duration pipelineTimeout = 5 * kj::SECONDS; | |
1147 // After one request/response completes, we'll wait up to this long for a pipelined request to | |
1148 // arrive. | |
1149 | |
1150 kj::Duration canceledUploadGracePeriod = 1 * kj::SECONDS; | |
1151 size_t canceledUploadGraceBytes = 65536; | |
1152 // If the HttpService sends a response and returns without having read the entire request body, | |
1153 // then we have to decide whether to close the connection or wait for the client to finish the | |
1154 // request so that it can pipeline the next one. We'll give them a grace period defined by the | |
1155 // above two values -- if they hit either one, we'll close the socket, but if the request | |
1156 // completes, we'll let the connection stay open to handle more requests. | |
1157 | |
1158 kj::Maybe<HttpServerErrorHandler&> errorHandler = nullptr; | |
1159 // Customize how client protocol errors and service application exceptions are handled by the | |
1160 // HttpServer. If null, HttpServerErrorHandler's default implementation will be used. | |
1161 | |
1162 kj::Maybe<HttpServerCallbacks&> callbacks = nullptr; | |
1163 // Additional optional callbacks used to control some server behavior. | |
1164 | |
1165 kj::Maybe<WebSocketErrorHandler&> webSocketErrorHandler = nullptr; | |
1166 // Customize exceptions thrown on WebSocket protocol errors. | |
1167 | |
1168 enum WebSocketCompressionMode { | |
1169 NO_COMPRESSION, | |
1170 MANUAL_COMPRESSION, // Gives the application more control when considering whether to compress. | |
1171 AUTOMATIC_COMPRESSION, // Will perform compression parameter negotiation if client requests it. | |
1172 }; | |
1173 WebSocketCompressionMode webSocketCompressionMode = NO_COMPRESSION; | |
1174 }; | |
1175 | |
1176 class HttpServerErrorHandler { | |
1177 public: | |
1178 virtual kj::Promise<void> handleClientProtocolError( | |
1179 HttpHeaders::ProtocolError protocolError, kj::HttpService::Response& response); | |
1180 virtual kj::Promise<void> handleApplicationError( | |
1181 kj::Exception exception, kj::Maybe<kj::HttpService::Response&> response); | |
1182 virtual kj::Promise<void> handleNoResponse(kj::HttpService::Response& response); | |
1183 // Override these functions to customize error handling during the request/response cycle. | |
1184 // | |
1185 // Client protocol errors arise when the server receives an HTTP message that fails to parse. As | |
1186 // such, HttpService::request() will not have been called yet, and the handler is always | |
1187 // guaranteed an opportunity to send a response. The default implementation of | |
1188 // handleClientProtocolError() replies with a 400 Bad Request response. | |
1189 // | |
1190 // Application errors arise when HttpService::request() throws an exception. The default | |
1191 // implementation of handleApplicationError() maps the following exception types to HTTP statuses, | |
1192 // and generates bodies from the stringified exceptions: | |
1193 // | |
1194 // - OVERLOADED: 503 Service Unavailable | |
1195 // - UNIMPLEMENTED: 501 Not Implemented | |
1196 // - DISCONNECTED: (no response) | |
1197 // - FAILED: 500 Internal Server Error | |
1198 // | |
1199 // No-response errors occur when HttpService::request() allows its promise to settle before | |
1200 // sending a response. The default implementation of handleNoResponse() replies with a 500 | |
1201 // Internal Server Error response. | |
1202 // | |
1203 // Unlike `HttpService::request()`, when calling `response.send()` in the context of one of these | |
1204 // functions, a "Connection: close" header will be added, and the connection will be closed. | |
1205 // | |
1206 // Also unlike `HttpService::request()`, it is okay to return kj::READY_NOW without calling | |
1207 // `response.send()`. In this case, no response will be sent, and the connection will be closed. | |
1208 | |
1209 virtual void handleListenLoopException(kj::Exception&& exception); | |
1210 // Override this function to customize error handling for individual connections in the | |
1211 // `listenHttp()` overload which accepts a ConnectionReceiver reference. | |
1212 // | |
1213 // The default handler uses KJ_LOG() to log the exception as an error. | |
1214 }; | |
1215 | |
1216 class HttpServerCallbacks { | |
1217 public: | |
1218 virtual bool shouldClose() { return false; } | |
1219 // Whenever the HttpServer begins response headers, it will check `shouldClose()` to decide | |
1220 // whether to send a `Connection: close` header and close the connection. | |
1221 // | |
1222 // This can be useful e.g. if the server has too many connections open and wants to shed some | |
1223 // of them. Note that to implement graceful shutdown of a server, you should use | |
1224 // `HttpServer::drain()` instead. | |
1225 }; | |
1226 | |
1227 class HttpServer final: private kj::TaskSet::ErrorHandler { | |
1228 // Class which listens for requests on ports or connections and sends them to an HttpService. | |
1229 | |
1230 public: | |
1231 typedef HttpServerSettings Settings; | |
1232 typedef kj::Function<kj::Own<HttpService>(kj::AsyncIoStream&)> HttpServiceFactory; | |
1233 class SuspendableRequest; | |
1234 typedef kj::Function<kj::Maybe<kj::Own<HttpService>>(SuspendableRequest&)> | |
1235 SuspendableHttpServiceFactory; | |
1236 | |
1237 HttpServer(kj::Timer& timer, const HttpHeaderTable& requestHeaderTable, HttpService& service, | |
1238 Settings settings = Settings()); | |
1239 // Set up an HttpServer that directs incoming connections to the given service. The service | |
1240 // may be a host service or a proxy service depending on whether you are intending to implement | |
1241 // an HTTP server or an HTTP proxy. | |
1242 | |
1243 HttpServer(kj::Timer& timer, const HttpHeaderTable& requestHeaderTable, | |
1244 HttpServiceFactory serviceFactory, Settings settings = Settings()); | |
1245 // Like the other constructor, but allows a new HttpService object to be used for each | |
1246 // connection, based on the connection object. This is particularly useful for capturing the | |
1247 // client's IP address and injecting it as a header. | |
1248 | |
1249 kj::Promise<void> drain(); | |
1250 // Stop accepting new connections or new requests on existing connections. Finish any requests | |
1251 // that are already executing, then close the connections. Returns once no more requests are | |
1252 // in-flight. | |
1253 | |
1254 kj::Promise<void> listenHttp(kj::ConnectionReceiver& port); | |
1255 // Accepts HTTP connections on the given port and directs them to the handler. | |
1256 // | |
1257 // The returned promise never completes normally. It may throw if port.accept() throws. Dropping | |
1258 // the returned promise will cause the server to stop listening on the port, but already-open | |
1259 // connections will continue to be served. Destroy the whole HttpServer to cancel all I/O. | |
1260 | |
1261 kj::Promise<void> listenHttp(kj::Own<kj::AsyncIoStream> connection); | |
1262 // Reads HTTP requests from the given connection and directs them to the handler. A successful | |
1263 // completion of the promise indicates that all requests received on the connection resulted in | |
1264 // a complete response, and the client closed the connection gracefully or drain() was called. | |
1265 // The promise throws if an unparsable request is received or if some I/O error occurs. Dropping | |
1266 // the returned promise will cancel all I/O on the connection and cancel any in-flight requests. | |
1267 | |
1268 kj::Promise<bool> listenHttpCleanDrain(kj::AsyncIoStream& connection); | |
1269 // Like listenHttp(), but allows you to potentially drain the server without closing connections. | |
1270 // The returned promise resolves to `true` if the connection has been left in a state where a | |
1271 // new HttpServer could potentially accept further requests from it. If `false`, then the | |
1272 // connection is either in an inconsistent state or already completed a closing handshake; the | |
1273 // caller should close it without any further reads/writes. Note this only ever returns `true` | |
1274 // if you called `drain()` -- otherwise this server would keep handling the connection. | |
1275 | |
1276 class SuspendedRequest { | |
1277 // SuspendedRequest is a representation of a request immediately after parsing the method line and | |
1278 // headers. You can obtain one of these by suspending a request by calling | |
1279 // SuspendableRequest::suspend(), then later resume the request with another call to | |
1280 // listenHttpCleanDrain(). | |
1281 | |
1282 public: | |
1283 // Nothing, this is an opaque type. | |
1284 | |
1285 private: | |
1286 SuspendedRequest(kj::Array<byte>, kj::ArrayPtr<byte>, kj::OneOf<HttpMethod, HttpConnectMethod>, kj::StringPtr, HttpHeaders); | |
1287 | |
1288 kj::Array<byte> buffer; | |
1289 // A buffer containing at least the request's method, URL, and headers, and possibly content | |
1290 // thereafter. | |
1291 | |
1292 kj::ArrayPtr<byte> leftover; | |
1293 // Pointer to the end of the request headers. If this has a non-zero length, then our buffer | |
1294 // contains additional content, presumably the head of the request body. | |
1295 | |
1296 kj::OneOf<HttpMethod, HttpConnectMethod> method; | |
1297 kj::StringPtr url; | |
1298 HttpHeaders headers; | |
1299 // Parsed request front matter. `url` and `headers` both store pointers into `buffer`. | |
1300 | |
1301 friend class HttpServer; | |
1302 }; | |
1303 | |
1304 kj::Promise<bool> listenHttpCleanDrain(kj::AsyncIoStream& connection, | |
1305 SuspendableHttpServiceFactory factory, | |
1306 kj::Maybe<SuspendedRequest> suspendedRequest = nullptr); | |
1307 // Like listenHttpCleanDrain(), but allows you to suspend requests. | |
1308 // | |
1309 // When this overload is in use, the HttpServer's default HttpService or HttpServiceFactory is not | |
1310 // used. Instead, the HttpServer reads the request method line and headers, then calls `factory` | |
1311 // with a SuspendableRequest representing the request parsed so far. The factory may then return | |
1312 // a kj::Own<HttpService> for that specific request, or it may call SuspendableRequest::suspend() | |
1313 // and return nullptr. (It is an error for the factory to return nullptr without also calling | |
1314 // suspend(); this will result in a rejected listenHttpCleanDrain() promise.) | |
1315 // | |
1316 // If the factory chooses to suspend, the listenHttpCleanDrain() promise is resolved with false | |
1317 // at the earliest opportunity. | |
1318 // | |
1319 // SuspendableRequest::suspend() returns a SuspendedRequest. You can resume this request later by | |
1320 // calling this same listenHttpCleanDrain() overload with the original connection stream, and the | |
1321 // SuspendedRequest in question. | |
1322 // | |
1323 // This overload of listenHttpCleanDrain() implements draining, as documented above. Note that the | |
1324 // returned promise will resolve to false (not clean) if a request is suspended. | |
1325 | |
1326 private: | |
1327 class Connection; | |
1328 | |
1329 kj::Timer& timer; | |
1330 const HttpHeaderTable& requestHeaderTable; | |
1331 kj::OneOf<HttpService*, HttpServiceFactory> service; | |
1332 Settings settings; | |
1333 | |
1334 bool draining = false; | |
1335 kj::ForkedPromise<void> onDrain; | |
1336 kj::Own<kj::PromiseFulfiller<void>> drainFulfiller; | |
1337 | |
1338 uint connectionCount = 0; | |
1339 kj::Maybe<kj::Own<kj::PromiseFulfiller<void>>> zeroConnectionsFulfiller; | |
1340 | |
1341 kj::TaskSet tasks; | |
1342 | |
1343 HttpServer(kj::Timer& timer, const HttpHeaderTable& requestHeaderTable, | |
1344 kj::OneOf<HttpService*, HttpServiceFactory> service, | |
1345 Settings settings, kj::PromiseFulfillerPair<void> paf); | |
1346 | |
1347 kj::Promise<void> listenLoop(kj::ConnectionReceiver& port); | |
1348 | |
1349 void taskFailed(kj::Exception&& exception) override; | |
1350 | |
1351 kj::Promise<bool> listenHttpImpl(kj::AsyncIoStream& connection, bool wantCleanDrain); | |
1352 kj::Promise<bool> listenHttpImpl(kj::AsyncIoStream& connection, | |
1353 SuspendableHttpServiceFactory factory, | |
1354 kj::Maybe<SuspendedRequest> suspendedRequest, | |
1355 bool wantCleanDrain); | |
1356 }; | |
1357 | |
1358 class HttpServer::SuspendableRequest { | |
1359 // Interface passed to the SuspendableHttpServiceFactory parameter of listenHttpCleanDrain(). | |
1360 | |
1361 public: | |
1362 kj::OneOf<HttpMethod,HttpConnectMethod> method; | |
1363 kj::StringPtr url; | |
1364 const HttpHeaders& headers; | |
1365 // Parsed request front matter, so the implementer can decide whether to suspend the request. | |
1366 | |
1367 SuspendedRequest suspend(); | |
1368 // Signal to the HttpServer that the current request loop should be exited. Return a | |
1369 // SuspendedRequest, containing HTTP method, URL, and headers access, along with the actual header | |
1370 // buffer. The request can be later resumed with a call to listenHttpCleanDrain() using the same | |
1371 // connection. | |
1372 | |
1373 private: | |
1374 explicit SuspendableRequest( | |
1375 Connection& connection, kj::OneOf<HttpMethod, HttpConnectMethod> method, kj::StringPtr url, const HttpHeaders& headers) | |
1376 : method(method), url(url), headers(headers), connection(connection) {} | |
1377 KJ_DISALLOW_COPY_AND_MOVE(SuspendableRequest); | |
1378 | |
1379 Connection& connection; | |
1380 | |
1381 friend class Connection; | |
1382 }; | |
1383 | |
1384 // ======================================================================================= | |
1385 // inline implementation | |
1386 | |
1387 inline void HttpHeaderId::requireFrom(const HttpHeaderTable& table) const { | |
1388 KJ_IREQUIRE(this->table == nullptr || this->table == &table, | |
1389 "the provided HttpHeaderId is from the wrong HttpHeaderTable"); | |
1390 } | |
1391 | |
1392 inline kj::Own<HttpHeaderTable> HttpHeaderTable::Builder::build() { | |
1393 table->buildStatus = BuildStatus::FINISHED; | |
1394 return kj::mv(table); | |
1395 } | |
1396 inline HttpHeaderTable& HttpHeaderTable::Builder::getFutureTable() { return *table; } | |
1397 | |
1398 inline uint HttpHeaderTable::idCount() const { return namesById.size(); } | |
1399 inline bool HttpHeaderTable::isReady() const { | |
1400 switch (buildStatus) { | |
1401 case BuildStatus::UNSTARTED: return true; | |
1402 case BuildStatus::BUILDING: return false; | |
1403 case BuildStatus::FINISHED: return true; | |
1404 } | |
1405 | |
1406 KJ_UNREACHABLE; | |
1407 } | |
1408 | |
1409 inline kj::StringPtr HttpHeaderTable::idToString(HttpHeaderId id) const { | |
1410 id.requireFrom(*this); | |
1411 return namesById[id.id]; | |
1412 } | |
1413 | |
1414 inline kj::Maybe<kj::StringPtr> HttpHeaders::get(HttpHeaderId id) const { | |
1415 id.requireFrom(*table); | |
1416 auto result = indexedHeaders[id.id]; | |
1417 return result == nullptr ? kj::Maybe<kj::StringPtr>(nullptr) : result; | |
1418 } | |
1419 | |
1420 inline void HttpHeaders::unset(HttpHeaderId id) { | |
1421 id.requireFrom(*table); | |
1422 indexedHeaders[id.id] = nullptr; | |
1423 } | |
1424 | |
1425 template <typename Func> | |
1426 inline void HttpHeaders::forEach(Func&& func) const { | |
1427 for (auto i: kj::indices(indexedHeaders)) { | |
1428 if (indexedHeaders[i] != nullptr) { | |
1429 func(table->idToString(HttpHeaderId(table, i)), indexedHeaders[i]); | |
1430 } | |
1431 } | |
1432 | |
1433 for (auto& header: unindexedHeaders) { | |
1434 func(header.name, header.value); | |
1435 } | |
1436 } | |
1437 | |
1438 template <typename Func1, typename Func2> | |
1439 inline void HttpHeaders::forEach(Func1&& func1, Func2&& func2) const { | |
1440 for (auto i: kj::indices(indexedHeaders)) { | |
1441 if (indexedHeaders[i] != nullptr) { | |
1442 func1(HttpHeaderId(table, i), indexedHeaders[i]); | |
1443 } | |
1444 } | |
1445 | |
1446 for (auto& header: unindexedHeaders) { | |
1447 func2(header.name, header.value); | |
1448 } | |
1449 } | |
1450 | |
1451 // ======================================================================================= | |
1452 namespace _ { // private implementation details for WebSocket compression | |
1453 | |
1454 kj::ArrayPtr<const char> splitNext(kj::ArrayPtr<const char>& cursor, char delimiter); | |
1455 | |
1456 void stripLeadingAndTrailingSpace(ArrayPtr<const char>& str); | |
1457 | |
1458 kj::Vector<kj::ArrayPtr<const char>> splitParts(kj::ArrayPtr<const char> input, char delim); | |
1459 | |
1460 struct KeyMaybeVal { | |
1461 ArrayPtr<const char> key; | |
1462 kj::Maybe<ArrayPtr<const char>> val; | |
1463 }; | |
1464 | |
1465 kj::Array<KeyMaybeVal> toKeysAndVals(const kj::ArrayPtr<kj::ArrayPtr<const char>>& params); | |
1466 | |
1467 struct UnverifiedConfig { | |
1468 // An intermediate representation of the final `CompressionParameters` struct; used during parsing. | |
1469 // We use it to ensure the structure of an offer is generally correct, see | |
1470 // `populateUnverifiedConfig()` for details. | |
1471 bool clientNoContextTakeover = false; | |
1472 bool serverNoContextTakeover = false; | |
1473 kj::Maybe<ArrayPtr<const char>> clientMaxWindowBits = nullptr; | |
1474 kj::Maybe<ArrayPtr<const char>> serverMaxWindowBits = nullptr; | |
1475 }; | |
1476 | |
1477 kj::Maybe<UnverifiedConfig> populateUnverifiedConfig(kj::Array<KeyMaybeVal>& params); | |
1478 | |
1479 kj::Maybe<CompressionParameters> validateCompressionConfig(UnverifiedConfig&& config, | |
1480 bool isAgreement); | |
1481 | |
1482 kj::Vector<CompressionParameters> findValidExtensionOffers(StringPtr offers); | |
1483 | |
1484 kj::String generateExtensionRequest(const ArrayPtr<CompressionParameters>& extensions); | |
1485 | |
1486 kj::Maybe<CompressionParameters> tryParseExtensionOffers(StringPtr offers); | |
1487 | |
1488 kj::Maybe<CompressionParameters> tryParseAllExtensionOffers(StringPtr offers, | |
1489 CompressionParameters manualConfig); | |
1490 | |
1491 kj::Maybe<CompressionParameters> compareClientAndServerConfigs(CompressionParameters requestConfig, | |
1492 CompressionParameters manualConfig); | |
1493 | |
1494 kj::String generateExtensionResponse(const CompressionParameters& parameters); | |
1495 | |
1496 kj::OneOf<CompressionParameters, kj::Exception> tryParseExtensionAgreement( | |
1497 const Maybe<CompressionParameters>& clientOffer, | |
1498 StringPtr agreedParameters); | |
1499 | |
1500 }; // namespace _ (private) | |
1501 | |
1502 } // namespace kj | |
1503 | |
1504 KJ_END_HEADER |