summaryrefslogtreecommitdiffstats
path: root/src/http2.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/http2.h')
-rw-r--r--src/http2.h457
1 files changed, 457 insertions, 0 deletions
diff --git a/src/http2.h b/src/http2.h
new file mode 100644
index 0000000..7cfe461
--- /dev/null
+++ b/src/http2.h
@@ -0,0 +1,457 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2013 Tatsuhiro Tsujikawa
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef HTTP2_H
+#define HTTP2_H
+
+#include "nghttp2_config.h"
+
+#include <cstdio>
+#include <cstring>
+#include <string>
+#include <vector>
+#include <array>
+
+#include <nghttp2/nghttp2.h>
+
+#include "url-parser/url_parser.h"
+
+#include "util.h"
+#include "memchunk.h"
+#include "template.h"
+#include "allocator.h"
+#include "base64.h"
+
+namespace nghttp2 {
+
+struct Header {
+ Header(std::string name, std::string value, bool no_index = false,
+ int32_t token = -1)
+ : name(std::move(name)),
+ value(std::move(value)),
+ token(token),
+ no_index(no_index) {}
+
+ Header() : token(-1), no_index(false) {}
+
+ bool operator==(const Header &other) const {
+ return name == other.name && value == other.value;
+ }
+
+ bool operator<(const Header &rhs) const {
+ return name < rhs.name || (name == rhs.name && value < rhs.value);
+ }
+
+ std::string name;
+ std::string value;
+ int32_t token;
+ bool no_index;
+};
+
+struct HeaderRef {
+ HeaderRef(const StringRef &name, const StringRef &value,
+ bool no_index = false, int32_t token = -1)
+ : name(name), value(value), token(token), no_index(no_index) {}
+
+ HeaderRef() : token(-1), no_index(false) {}
+
+ bool operator==(const HeaderRef &other) const {
+ return name == other.name && value == other.value;
+ }
+
+ bool operator<(const HeaderRef &rhs) const {
+ return name < rhs.name || (name == rhs.name && value < rhs.value);
+ }
+
+ StringRef name;
+ StringRef value;
+ int32_t token;
+ bool no_index;
+};
+
+using Headers = std::vector<Header>;
+using HeaderRefs = std::vector<HeaderRef>;
+
+namespace http2 {
+
+// Returns reason-phrase for given |status code|. If there is no
+// known reason-phrase for the given code, returns empty string.
+StringRef get_reason_phrase(unsigned int status_code);
+
+// Returns string version of |status_code|. (e.g., "404")
+StringRef stringify_status(BlockAllocator &balloc, unsigned int status_code);
+
+void capitalize(DefaultMemchunks *buf, const StringRef &s);
+
+// Returns true if |value| is LWS
+bool lws(const char *value);
+
+// Copies the |field| component value from |u| and |url| to the
+// |dest|. If |u| does not have |field|, then this function does
+// nothing.
+void copy_url_component(std::string &dest, const http_parser_url *u, int field,
+ const char *url);
+
+Headers::value_type to_header(const uint8_t *name, size_t namelen,
+ const uint8_t *value, size_t valuelen,
+ bool no_index, int32_t token);
+
+// Add name/value pairs to |nva|. If |no_index| is true, this
+// name/value pair won't be indexed when it is forwarded to the next
+// hop. This function strips white spaces around |value|.
+void add_header(Headers &nva, const uint8_t *name, size_t namelen,
+ const uint8_t *value, size_t valuelen, bool no_index,
+ int32_t token);
+
+// Returns pointer to the entry in |nva| which has name |name|. If
+// more than one entries which have the name |name|, last occurrence
+// in |nva| is returned. If no such entry exist, returns nullptr.
+const Headers::value_type *get_header(const Headers &nva, const char *name);
+
+// Returns true if the value of |nv| is not empty.
+bool non_empty_value(const HeaderRefs::value_type *nv);
+
+// Creates nghttp2_nv using |name| and |value| and returns it. The
+// returned value only references the data pointer to name.c_str() and
+// value.c_str(). If |no_index| is true, nghttp2_nv flags member has
+// NGHTTP2_NV_FLAG_NO_INDEX flag set.
+nghttp2_nv make_nv(const std::string &name, const std::string &value,
+ bool no_index = false);
+
+nghttp2_nv make_nv(const StringRef &name, const StringRef &value,
+ bool no_index = false);
+
+nghttp2_nv make_nv_nocopy(const std::string &name, const std::string &value,
+ bool no_index = false);
+
+nghttp2_nv make_nv_nocopy(const StringRef &name, const StringRef &value,
+ bool no_index = false);
+
+// Create nghttp2_nv from string literal |name| and |value|.
+template <size_t N, size_t M>
+constexpr nghttp2_nv make_nv_ll(const char (&name)[N], const char (&value)[M]) {
+ return {(uint8_t *)name, (uint8_t *)value, N - 1, M - 1,
+ NGHTTP2_NV_FLAG_NO_COPY_NAME | NGHTTP2_NV_FLAG_NO_COPY_VALUE};
+}
+
+// Create nghttp2_nv from string literal |name| and c-string |value|.
+template <size_t N>
+nghttp2_nv make_nv_lc(const char (&name)[N], const char *value) {
+ return {(uint8_t *)name, (uint8_t *)value, N - 1, strlen(value),
+ NGHTTP2_NV_FLAG_NO_COPY_NAME};
+}
+
+template <size_t N>
+nghttp2_nv make_nv_lc_nocopy(const char (&name)[N], const char *value) {
+ return {(uint8_t *)name, (uint8_t *)value, N - 1, strlen(value),
+ NGHTTP2_NV_FLAG_NO_COPY_NAME | NGHTTP2_NV_FLAG_NO_COPY_VALUE};
+}
+
+// Create nghttp2_nv from string literal |name| and std::string
+// |value|.
+template <size_t N>
+nghttp2_nv make_nv_ls(const char (&name)[N], const std::string &value) {
+ return {(uint8_t *)name, (uint8_t *)value.c_str(), N - 1, value.size(),
+ NGHTTP2_NV_FLAG_NO_COPY_NAME};
+}
+
+template <size_t N>
+nghttp2_nv make_nv_ls_nocopy(const char (&name)[N], const std::string &value) {
+ return {(uint8_t *)name, (uint8_t *)value.c_str(), N - 1, value.size(),
+ NGHTTP2_NV_FLAG_NO_COPY_NAME | NGHTTP2_NV_FLAG_NO_COPY_VALUE};
+}
+
+template <size_t N>
+nghttp2_nv make_nv_ls_nocopy(const char (&name)[N], const StringRef &value) {
+ return {(uint8_t *)name, (uint8_t *)value.c_str(), N - 1, value.size(),
+ NGHTTP2_NV_FLAG_NO_COPY_NAME | NGHTTP2_NV_FLAG_NO_COPY_VALUE};
+}
+
+enum HeaderBuildOp {
+ HDOP_NONE,
+ // Forwarded header fields must be stripped. If this flag is not
+ // set, all Forwarded header fields other than last one are added.
+ HDOP_STRIP_FORWARDED = 1,
+ // X-Forwarded-For header fields must be stripped. If this flag is
+ // not set, all X-Forwarded-For header fields other than last one
+ // are added.
+ HDOP_STRIP_X_FORWARDED_FOR = 1 << 1,
+ // X-Forwarded-Proto header fields must be stripped. If this flag
+ // is not set, all X-Forwarded-Proto header fields other than last
+ // one are added.
+ HDOP_STRIP_X_FORWARDED_PROTO = 1 << 2,
+ // Via header fields must be stripped. If this flag is not set, all
+ // Via header fields other than last one are added.
+ HDOP_STRIP_VIA = 1 << 3,
+ // Early-Data header fields must be stripped. If this flag is not
+ // set, all Early-Data header fields are added.
+ HDOP_STRIP_EARLY_DATA = 1 << 4,
+ // Strip above all header fields.
+ HDOP_STRIP_ALL = HDOP_STRIP_FORWARDED | HDOP_STRIP_X_FORWARDED_FOR |
+ HDOP_STRIP_X_FORWARDED_PROTO | HDOP_STRIP_VIA |
+ HDOP_STRIP_EARLY_DATA,
+ // Sec-WebSocket-Accept header field must be stripped. If this flag
+ // is not set, all Sec-WebSocket-Accept header fields are added.
+ HDOP_STRIP_SEC_WEBSOCKET_ACCEPT = 1 << 5,
+ // Sec-WebSocket-Key header field must be stripped. If this flag is
+ // not set, all Sec-WebSocket-Key header fields are added.
+ HDOP_STRIP_SEC_WEBSOCKET_KEY = 1 << 6,
+ // Transfer-Encoding header field must be stripped. If this flag is
+ // not set, all Transfer-Encoding header fields are added.
+ HDOP_STRIP_TRANSFER_ENCODING = 1 << 7,
+};
+
+// Appends headers in |headers| to |nv|. |headers| must be indexed
+// before this call (its element's token field is assigned). Certain
+// headers, including disallowed headers in HTTP/2 spec and headers
+// which require special handling (i.e. via), are not copied. |flags|
+// is one or more of HeaderBuildOp flags. They tell function that
+// certain header fields should not be added.
+void copy_headers_to_nva(std::vector<nghttp2_nv> &nva,
+ const HeaderRefs &headers, uint32_t flags);
+
+// Just like copy_headers_to_nva(), but this adds
+// NGHTTP2_NV_FLAG_NO_COPY_NAME and NGHTTP2_NV_FLAG_NO_COPY_VALUE.
+void copy_headers_to_nva_nocopy(std::vector<nghttp2_nv> &nva,
+ const HeaderRefs &headers, uint32_t flags);
+
+// Appends HTTP/1.1 style header lines to |buf| from headers in
+// |headers|. |headers| must be indexed before this call (its
+// element's token field is assigned). Certain headers, which
+// requires special handling (i.e. via and cookie), are not appended.
+// |flags| is one or more of HeaderBuildOp flags. They tell function
+// that certain header fields should not be added.
+void build_http1_headers_from_headers(DefaultMemchunks *buf,
+ const HeaderRefs &headers,
+ uint32_t flags);
+
+// Return positive window_size_increment if WINDOW_UPDATE should be
+// sent for the stream |stream_id|. If |stream_id| == 0, this function
+// determines the necessity of the WINDOW_UPDATE for a connection.
+//
+// If the function determines WINDOW_UPDATE is not necessary at the
+// moment, it returns -1.
+int32_t determine_window_update_transmission(nghttp2_session *session,
+ int32_t stream_id);
+
+// Dumps name/value pairs in |nv| to |out|. The |nv| must be
+// terminated by nullptr.
+void dump_nv(FILE *out, const char **nv);
+
+// Dumps name/value pairs in |nva| to |out|.
+void dump_nv(FILE *out, const nghttp2_nv *nva, size_t nvlen);
+
+// Dumps name/value pairs in |nva| to |out|.
+void dump_nv(FILE *out, const Headers &nva);
+
+void dump_nv(FILE *out, const HeaderRefs &nva);
+
+// Ereases header in |hd|.
+void erase_header(HeaderRef *hd);
+
+// Rewrites redirection URI which usually appears in location header
+// field. The |uri| is the URI in the location header field. The |u|
+// stores the result of parsed |uri|. The |request_authority| is the
+// host or :authority header field value in the request. The
+// |upstream_scheme| is either "https" or "http" in the upstream
+// interface. Rewrite is done only if location header field value
+// contains |match_host| as host excluding port. The |match_host| and
+// |request_authority| could be different. If |request_authority| is
+// empty, strip authority.
+//
+// This function returns the new rewritten URI on success. If the
+// location URI is not subject to the rewrite, this function returns
+// empty string.
+StringRef rewrite_location_uri(BlockAllocator &balloc, const StringRef &uri,
+ const http_parser_url &u,
+ const StringRef &match_host,
+ const StringRef &request_authority,
+ const StringRef &upstream_scheme);
+
+// Returns parsed HTTP status code. Returns -1 on failure.
+int parse_http_status_code(const StringRef &src);
+
+// Header fields to be indexed, except HD_MAXIDX which is convenient
+// member to get maximum value.
+//
+// generated by genheaderfunc.py
+enum {
+ HD__AUTHORITY,
+ HD__HOST,
+ HD__METHOD,
+ HD__PATH,
+ HD__PROTOCOL,
+ HD__SCHEME,
+ HD__STATUS,
+ HD_ACCEPT_ENCODING,
+ HD_ACCEPT_LANGUAGE,
+ HD_ALT_SVC,
+ HD_CACHE_CONTROL,
+ HD_CONNECTION,
+ HD_CONTENT_LENGTH,
+ HD_CONTENT_TYPE,
+ HD_COOKIE,
+ HD_DATE,
+ HD_EARLY_DATA,
+ HD_EXPECT,
+ HD_FORWARDED,
+ HD_HOST,
+ HD_HTTP2_SETTINGS,
+ HD_IF_MODIFIED_SINCE,
+ HD_KEEP_ALIVE,
+ HD_LINK,
+ HD_LOCATION,
+ HD_PRIORITY,
+ HD_PROXY_CONNECTION,
+ HD_SEC_WEBSOCKET_ACCEPT,
+ HD_SEC_WEBSOCKET_KEY,
+ HD_SERVER,
+ HD_TE,
+ HD_TRAILER,
+ HD_TRANSFER_ENCODING,
+ HD_UPGRADE,
+ HD_USER_AGENT,
+ HD_VIA,
+ HD_X_FORWARDED_FOR,
+ HD_X_FORWARDED_PROTO,
+ HD_MAXIDX,
+};
+
+using HeaderIndex = std::array<int16_t, HD_MAXIDX>;
+
+// Looks up header token for header name |name| of length |namelen|.
+// Only headers we are interested in are tokenized. If header name
+// cannot be tokenized, returns -1.
+int lookup_token(const uint8_t *name, size_t namelen);
+int lookup_token(const StringRef &name);
+
+// Initializes |hdidx|, header index. The |hdidx| must point to the
+// array containing at least HD_MAXIDX elements.
+void init_hdidx(HeaderIndex &hdidx);
+// Indexes header |token| using index |idx|.
+void index_header(HeaderIndex &hdidx, int32_t token, size_t idx);
+
+// Returns header denoted by |token| using index |hdidx|.
+const Headers::value_type *get_header(const HeaderIndex &hdidx, int32_t token,
+ const Headers &nva);
+
+Headers::value_type *get_header(const HeaderIndex &hdidx, int32_t token,
+ Headers &nva);
+
+struct LinkHeader {
+ // The region of URI. This might not be NULL-terminated.
+ StringRef uri;
+};
+
+// Returns next URI-reference in Link header field value |src|. If no
+// URI-reference found after searching all input, returned uri field
+// is empty. This imply that empty URI-reference is ignored during
+// parsing.
+std::vector<LinkHeader> parse_link_header(const StringRef &src);
+
+// Constructs path by combining base path |base_path| with another
+// path |rel_path|. The base path and another path can have optional
+// query component. This function assumes |base_path| is normalized.
+// In other words, it does not contain ".." or "." path components
+// and starts with "/" if it is not empty.
+std::string path_join(const StringRef &base, const StringRef &base_query,
+ const StringRef &rel_path, const StringRef &rel_query);
+
+StringRef path_join(BlockAllocator &balloc, const StringRef &base_path,
+ const StringRef &base_query, const StringRef &rel_path,
+ const StringRef &rel_query);
+
+// true if response has body, taking into account the request method
+// and status code.
+bool expect_response_body(const std::string &method, int status_code);
+bool expect_response_body(int method_token, int status_code);
+
+// true if response has body, taking into account status code only.
+bool expect_response_body(int status_code);
+
+// Looks up method token for method name |name| of length |namelen|.
+// Only methods defined in llhttp.h (llhttp_method) are tokenized. If
+// method name cannot be tokenized, returns -1.
+int lookup_method_token(const uint8_t *name, size_t namelen);
+int lookup_method_token(const StringRef &name);
+
+// Returns string representation of |method_token|. This is wrapper
+// around llhttp_method_name from llhttp. If |method_token| is
+// unknown, program aborts. The returned StringRef is guaranteed to
+// be NULL-terminated.
+StringRef to_method_string(int method_token);
+
+StringRef normalize_path(BlockAllocator &balloc, const StringRef &path,
+ const StringRef &query);
+
+// normalize_path_colon is like normalize_path, but it additionally
+// does percent-decoding %3A in order to workaround the issue that ':'
+// cannot be included in backend pattern.
+StringRef normalize_path_colon(BlockAllocator &balloc, const StringRef &path,
+ const StringRef &query);
+
+std::string normalize_path(const StringRef &path, const StringRef &query);
+
+StringRef rewrite_clean_path(BlockAllocator &balloc, const StringRef &src);
+
+// Returns path component of |uri|. The returned path does not
+// include query component. This function returns empty string if it
+// fails.
+StringRef get_pure_path_component(const StringRef &uri);
+
+// Deduces scheme, authority and path from given |uri|, and stores
+// them in |scheme|, |authority|, and |path| respectively. If |uri|
+// is relative path, path resolution takes place using path given in
+// |base| of length |baselen|. This function returns 0 if it
+// succeeds, or -1.
+int construct_push_component(BlockAllocator &balloc, StringRef &scheme,
+ StringRef &authority, StringRef &path,
+ const StringRef &base, const StringRef &uri);
+
+// Copies |src| and return its lower-cased version.
+StringRef copy_lower(BlockAllocator &balloc, const StringRef &src);
+
+// Returns true if te header field value |s| contains "trailers".
+bool contains_trailers(const StringRef &s);
+
+// Creates Sec-WebSocket-Accept value for |key|. The capacity of
+// buffer pointed by |dest| must have at least 24 bytes (base64
+// encoded length of 16 bytes data). It returns empty string in case
+// of error.
+StringRef make_websocket_accept_token(uint8_t *dest, const StringRef &key);
+
+// Returns true if HTTP version represents pre-HTTP/1.1 (e.g.,
+// HTTP/0.9 or HTTP/1.0).
+bool legacy_http1(int major, int minor);
+
+// Returns true if transfer-encoding field value |s| conforms RFC
+// strictly. This function does not allow empty value, BWS, and empty
+// list elements.
+bool check_transfer_encoding(const StringRef &s);
+
+} // namespace http2
+
+} // namespace nghttp2
+
+#endif // HTTP2_H