2 * nghttp2 - HTTP/2 C Library
4 * Copyright (c) 2013 Tatsuhiro Tsujikawa
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 #include "nghttp2_config.h"
36 #include <nghttp2/nghttp2.h>
38 #include "url-parser/url_parser.h"
43 #include "allocator.h"
49 Header(std::string name, std::string value, bool no_index = false,
51 : name(std::move(name)),
52 value(std::move(value)),
56 Header() : token(-1), no_index(false) {}
58 bool operator==(const Header &other) const {
59 return name == other.name && value == other.value;
62 bool operator<(const Header &rhs) const {
63 return name < rhs.name || (name == rhs.name && value < rhs.value);
73 HeaderRef(const StringRef &name, const StringRef &value,
74 bool no_index = false, int32_t token = -1)
75 : name(name), value(value), token(token), no_index(no_index) {}
77 HeaderRef() : token(-1), no_index(false) {}
79 bool operator==(const HeaderRef &other) const {
80 return name == other.name && value == other.value;
83 bool operator<(const HeaderRef &rhs) const {
84 return name < rhs.name || (name == rhs.name && value < rhs.value);
93 using Headers = std::vector<Header>;
94 using HeaderRefs = std::vector<HeaderRef>;
98 // Returns reason-phrase for given |status code|. If there is no
99 // known reason-phrase for the given code, returns empty string.
100 StringRef get_reason_phrase(unsigned int status_code);
102 // Returns string version of |status_code|. (e.g., "404")
103 StringRef stringify_status(BlockAllocator &balloc, unsigned int status_code);
105 void capitalize(DefaultMemchunks *buf, const StringRef &s);
107 // Returns true if |value| is LWS
108 bool lws(const char *value);
110 // Copies the |field| component value from |u| and |url| to the
111 // |dest|. If |u| does not have |field|, then this function does
113 void copy_url_component(std::string &dest, const http_parser_url *u, int field,
116 Headers::value_type to_header(const uint8_t *name, size_t namelen,
117 const uint8_t *value, size_t valuelen,
118 bool no_index, int32_t token);
120 // Add name/value pairs to |nva|. If |no_index| is true, this
121 // name/value pair won't be indexed when it is forwarded to the next
122 // hop. This function strips white spaces around |value|.
123 void add_header(Headers &nva, const uint8_t *name, size_t namelen,
124 const uint8_t *value, size_t valuelen, bool no_index,
127 // Returns pointer to the entry in |nva| which has name |name|. If
128 // more than one entries which have the name |name|, last occurrence
129 // in |nva| is returned. If no such entry exist, returns nullptr.
130 const Headers::value_type *get_header(const Headers &nva, const char *name);
132 // Returns true if the value of |nv| is not empty.
133 bool non_empty_value(const HeaderRefs::value_type *nv);
135 // Creates nghttp2_nv using |name| and |value| and returns it. The
136 // returned value only references the data pointer to name.c_str() and
137 // value.c_str(). If |no_index| is true, nghttp2_nv flags member has
138 // NGHTTP2_NV_FLAG_NO_INDEX flag set.
139 nghttp2_nv make_nv(const std::string &name, const std::string &value,
140 bool no_index = false);
142 nghttp2_nv make_nv(const StringRef &name, const StringRef &value,
143 bool no_index = false);
145 nghttp2_nv make_nv_nocopy(const std::string &name, const std::string &value,
146 bool no_index = false);
148 nghttp2_nv make_nv_nocopy(const StringRef &name, const StringRef &value,
149 bool no_index = false);
151 // Create nghttp2_nv from string literal |name| and |value|.
152 template <size_t N, size_t M>
153 constexpr nghttp2_nv make_nv_ll(const char (&name)[N], const char (&value)[M]) {
154 return {(uint8_t *)name, (uint8_t *)value, N - 1, M - 1,
155 NGHTTP2_NV_FLAG_NO_COPY_NAME | NGHTTP2_NV_FLAG_NO_COPY_VALUE};
158 // Create nghttp2_nv from string literal |name| and c-string |value|.
160 nghttp2_nv make_nv_lc(const char (&name)[N], const char *value) {
161 return {(uint8_t *)name, (uint8_t *)value, N - 1, strlen(value),
162 NGHTTP2_NV_FLAG_NO_COPY_NAME};
166 nghttp2_nv make_nv_lc_nocopy(const char (&name)[N], const char *value) {
167 return {(uint8_t *)name, (uint8_t *)value, N - 1, strlen(value),
168 NGHTTP2_NV_FLAG_NO_COPY_NAME | NGHTTP2_NV_FLAG_NO_COPY_VALUE};
171 // Create nghttp2_nv from string literal |name| and std::string
174 nghttp2_nv make_nv_ls(const char (&name)[N], const std::string &value) {
175 return {(uint8_t *)name, (uint8_t *)value.c_str(), N - 1, value.size(),
176 NGHTTP2_NV_FLAG_NO_COPY_NAME};
180 nghttp2_nv make_nv_ls_nocopy(const char (&name)[N], const std::string &value) {
181 return {(uint8_t *)name, (uint8_t *)value.c_str(), N - 1, value.size(),
182 NGHTTP2_NV_FLAG_NO_COPY_NAME | NGHTTP2_NV_FLAG_NO_COPY_VALUE};
186 nghttp2_nv make_nv_ls_nocopy(const char (&name)[N], const StringRef &value) {
187 return {(uint8_t *)name, (uint8_t *)value.c_str(), N - 1, value.size(),
188 NGHTTP2_NV_FLAG_NO_COPY_NAME | NGHTTP2_NV_FLAG_NO_COPY_VALUE};
193 // Forwarded header fields must be stripped. If this flag is not
194 // set, all Forwarded header fields other than last one are added.
195 HDOP_STRIP_FORWARDED = 1,
196 // X-Forwarded-For header fields must be stripped. If this flag is
197 // not set, all X-Forwarded-For header fields other than last one
199 HDOP_STRIP_X_FORWARDED_FOR = 1 << 1,
200 // X-Forwarded-Proto header fields must be stripped. If this flag
201 // is not set, all X-Forwarded-Proto header fields other than last
203 HDOP_STRIP_X_FORWARDED_PROTO = 1 << 2,
204 // Via header fields must be stripped. If this flag is not set, all
205 // Via header fields other than last one are added.
206 HDOP_STRIP_VIA = 1 << 3,
207 // Early-Data header fields must be stripped. If this flag is not
208 // set, all Early-Data header fields are added.
209 HDOP_STRIP_EARLY_DATA = 1 << 4,
210 // Strip above all header fields.
211 HDOP_STRIP_ALL = HDOP_STRIP_FORWARDED | HDOP_STRIP_X_FORWARDED_FOR |
212 HDOP_STRIP_X_FORWARDED_PROTO | HDOP_STRIP_VIA |
213 HDOP_STRIP_EARLY_DATA,
214 // Sec-WebSocket-Accept header field must be stripped. If this flag
215 // is not set, all Sec-WebSocket-Accept header fields are added.
216 HDOP_STRIP_SEC_WEBSOCKET_ACCEPT = 1 << 5,
217 // Sec-WebSocket-Key header field must be stripped. If this flag is
218 // not set, all Sec-WebSocket-Key header fields are added.
219 HDOP_STRIP_SEC_WEBSOCKET_KEY = 1 << 6,
220 // Transfer-Encoding header field must be stripped. If this flag is
221 // not set, all Transfer-Encoding header fields are added.
222 HDOP_STRIP_TRANSFER_ENCODING = 1 << 7,
225 // Appends headers in |headers| to |nv|. |headers| must be indexed
226 // before this call (its element's token field is assigned). Certain
227 // headers, including disallowed headers in HTTP/2 spec and headers
228 // which require special handling (i.e. via), are not copied. |flags|
229 // is one or more of HeaderBuildOp flags. They tell function that
230 // certain header fields should not be added.
231 void copy_headers_to_nva(std::vector<nghttp2_nv> &nva,
232 const HeaderRefs &headers, uint32_t flags);
234 // Just like copy_headers_to_nva(), but this adds
235 // NGHTTP2_NV_FLAG_NO_COPY_NAME and NGHTTP2_NV_FLAG_NO_COPY_VALUE.
236 void copy_headers_to_nva_nocopy(std::vector<nghttp2_nv> &nva,
237 const HeaderRefs &headers, uint32_t flags);
239 // Appends HTTP/1.1 style header lines to |buf| from headers in
240 // |headers|. |headers| must be indexed before this call (its
241 // element's token field is assigned). Certain headers, which
242 // requires special handling (i.e. via and cookie), are not appended.
243 // |flags| is one or more of HeaderBuildOp flags. They tell function
244 // that certain header fields should not be added.
245 void build_http1_headers_from_headers(DefaultMemchunks *buf,
246 const HeaderRefs &headers,
249 // Return positive window_size_increment if WINDOW_UPDATE should be
250 // sent for the stream |stream_id|. If |stream_id| == 0, this function
251 // determines the necessity of the WINDOW_UPDATE for a connection.
253 // If the function determines WINDOW_UPDATE is not necessary at the
254 // moment, it returns -1.
255 int32_t determine_window_update_transmission(nghttp2_session *session,
258 // Dumps name/value pairs in |nv| to |out|. The |nv| must be
259 // terminated by nullptr.
260 void dump_nv(FILE *out, const char **nv);
262 // Dumps name/value pairs in |nva| to |out|.
263 void dump_nv(FILE *out, const nghttp2_nv *nva, size_t nvlen);
265 // Dumps name/value pairs in |nva| to |out|.
266 void dump_nv(FILE *out, const Headers &nva);
268 void dump_nv(FILE *out, const HeaderRefs &nva);
270 // Ereases header in |hd|.
271 void erase_header(HeaderRef *hd);
273 // Rewrites redirection URI which usually appears in location header
274 // field. The |uri| is the URI in the location header field. The |u|
275 // stores the result of parsed |uri|. The |request_authority| is the
276 // host or :authority header field value in the request. The
277 // |upstream_scheme| is either "https" or "http" in the upstream
278 // interface. Rewrite is done only if location header field value
279 // contains |match_host| as host excluding port. The |match_host| and
280 // |request_authority| could be different. If |request_authority| is
281 // empty, strip authority.
283 // This function returns the new rewritten URI on success. If the
284 // location URI is not subject to the rewrite, this function returns
286 StringRef rewrite_location_uri(BlockAllocator &balloc, const StringRef &uri,
287 const http_parser_url &u,
288 const StringRef &match_host,
289 const StringRef &request_authority,
290 const StringRef &upstream_scheme);
292 // Checks the header name/value pair using nghttp2_check_header_name()
293 // and nghttp2_check_header_value(). If both function returns nonzero,
294 // this function returns nonzero.
295 int check_nv(const uint8_t *name, size_t namelen, const uint8_t *value,
298 // Returns parsed HTTP status code. Returns -1 on failure.
299 int parse_http_status_code(const StringRef &src);
301 // Header fields to be indexed, except HD_MAXIDX which is convenient
302 // member to get maximum value.
304 // generated by genheaderfunc.py
327 HD_IF_MODIFIED_SINCE,
332 HD_SEC_WEBSOCKET_ACCEPT,
333 HD_SEC_WEBSOCKET_KEY,
337 HD_TRANSFER_ENCODING,
342 HD_X_FORWARDED_PROTO,
346 using HeaderIndex = std::array<int16_t, HD_MAXIDX>;
348 // Looks up header token for header name |name| of length |namelen|.
349 // Only headers we are interested in are tokenized. If header name
350 // cannot be tokenized, returns -1.
351 int lookup_token(const uint8_t *name, size_t namelen);
352 int lookup_token(const StringRef &name);
354 // Initializes |hdidx|, header index. The |hdidx| must point to the
355 // array containing at least HD_MAXIDX elements.
356 void init_hdidx(HeaderIndex &hdidx);
357 // Indexes header |token| using index |idx|.
358 void index_header(HeaderIndex &hdidx, int32_t token, size_t idx);
360 // Returns header denoted by |token| using index |hdidx|.
361 const Headers::value_type *get_header(const HeaderIndex &hdidx, int32_t token,
364 Headers::value_type *get_header(const HeaderIndex &hdidx, int32_t token,
368 // The region of URI. This might not be NULL-terminated.
372 // Returns next URI-reference in Link header field value |src|. If no
373 // URI-reference found after searching all input, returned uri field
374 // is empty. This imply that empty URI-reference is ignored during
376 std::vector<LinkHeader> parse_link_header(const StringRef &src);
378 // Constructs path by combining base path |base_path| with another
379 // path |rel_path|. The base path and another path can have optional
380 // query component. This function assumes |base_path| is normalized.
381 // In other words, it does not contain ".." or "." path components
382 // and starts with "/" if it is not empty.
383 std::string path_join(const StringRef &base, const StringRef &base_query,
384 const StringRef &rel_path, const StringRef &rel_query);
386 StringRef path_join(BlockAllocator &balloc, const StringRef &base_path,
387 const StringRef &base_query, const StringRef &rel_path,
388 const StringRef &rel_query);
390 // true if response has body, taking into account the request method
392 bool expect_response_body(const std::string &method, int status_code);
393 bool expect_response_body(int method_token, int status_code);
395 // true if response has body, taking into account status code only.
396 bool expect_response_body(int status_code);
398 // Looks up method token for method name |name| of length |namelen|.
399 // Only methods defined in llhttp.h (llhttp_method) are tokenized. If
400 // method name cannot be tokenized, returns -1.
401 int lookup_method_token(const uint8_t *name, size_t namelen);
402 int lookup_method_token(const StringRef &name);
404 // Returns string representation of |method_token|. This is wrapper
405 // around llhttp_method_name from llhttp. If |method_token| is
406 // unknown, program aborts. The returned StringRef is guaranteed to
407 // be NULL-terminated.
408 StringRef to_method_string(int method_token);
410 StringRef normalize_path(BlockAllocator &balloc, const StringRef &path,
411 const StringRef &query);
413 std::string normalize_path(const StringRef &path, const StringRef &query);
415 StringRef rewrite_clean_path(BlockAllocator &balloc, const StringRef &src);
417 // Returns path component of |uri|. The returned path does not
418 // include query component. This function returns empty string if it
420 StringRef get_pure_path_component(const StringRef &uri);
422 // Deduces scheme, authority and path from given |uri|, and stores
423 // them in |scheme|, |authority|, and |path| respectively. If |uri|
424 // is relative path, path resolution takes place using path given in
425 // |base| of length |baselen|. This function returns 0 if it
427 int construct_push_component(BlockAllocator &balloc, StringRef &scheme,
428 StringRef &authority, StringRef &path,
429 const StringRef &base, const StringRef &uri);
431 // Copies |src| and return its lower-cased version.
432 StringRef copy_lower(BlockAllocator &balloc, const StringRef &src);
434 // Returns true if te header field value |s| contains "trailers".
435 bool contains_trailers(const StringRef &s);
437 // Creates Sec-WebSocket-Accept value for |key|. The capacity of
438 // buffer pointed by |dest| must have at least 24 bytes (base64
439 // encoded length of 16 bytes data). It returns empty string in case
441 StringRef make_websocket_accept_token(uint8_t *dest, const StringRef &key);
443 // Returns true if HTTP version represents pre-HTTP/1.1 (e.g.,
444 // HTTP/0.9 or HTTP/1.0).
445 bool legacy_http1(int major, int minor);
449 } // namespace nghttp2