tizen 2.4 release
[external/nghttp2.git] / src / http2.h
1 /*
2  * nghttp2 - HTTP/2 C Library
3  *
4  * Copyright (c) 2013 Tatsuhiro Tsujikawa
5  *
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:
13  *
14  * The above copyright notice and this permission notice shall be
15  * included in all copies or substantial portions of the Software.
16  *
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.
24  */
25 #ifndef HTTP2_H
26 #define HTTP2_H
27
28 #include "nghttp2_config.h"
29
30 #include <cstdio>
31 #include <cstring>
32 #include <string>
33 #include <vector>
34 #include <array>
35
36 #include <nghttp2/nghttp2.h>
37
38 #include "http-parser/http_parser.h"
39
40 namespace nghttp2 {
41
42 struct Header {
43   Header(std::string name, std::string value, bool no_index = false,
44          int16_t token = -1)
45       : name(std::move(name)), value(std::move(value)), token(token),
46         no_index(no_index) {}
47
48   Header() : token(-1), no_index(false) {}
49
50   bool operator==(const Header &other) const {
51     return name == other.name && value == other.value;
52   }
53
54   bool operator<(const Header &rhs) const {
55     return name < rhs.name || (name == rhs.name && value < rhs.value);
56   }
57
58   std::string name;
59   std::string value;
60   int16_t token;
61   bool no_index;
62 };
63
64 typedef std::vector<Header> Headers;
65
66 namespace http2 {
67
68 std::string get_status_string(unsigned int status_code);
69
70 void capitalize(std::string &s, size_t offset);
71
72 // Returns true if |value| is LWS
73 bool lws(const char *value);
74
75 // Copies the |field| component value from |u| and |url| to the
76 // |dest|. If |u| does not have |field|, then this function does
77 // nothing.
78 void copy_url_component(std::string &dest, const http_parser_url *u, int field,
79                         const char *url);
80
81 Headers::value_type to_header(const uint8_t *name, size_t namelen,
82                               const uint8_t *value, size_t valuelen,
83                               bool no_index, int16_t token);
84
85 // Add name/value pairs to |nva|.  If |no_index| is true, this
86 // name/value pair won't be indexed when it is forwarded to the next
87 // hop.  This function strips white spaces around |value|.
88 void add_header(Headers &nva, const uint8_t *name, size_t namelen,
89                 const uint8_t *value, size_t valuelen, bool no_index,
90                 int16_t token);
91
92 // Returns pointer to the entry in |nva| which has name |name|.  If
93 // more than one entries which have the name |name|, last occurrence
94 // in |nva| is returned.  If no such entry exist, returns nullptr.
95 const Headers::value_type *get_header(const Headers &nva, const char *name);
96
97 // Returns nv->second if nv is not nullptr. Otherwise, returns "".
98 std::string value_to_str(const Headers::value_type *nv);
99
100 // Returns true if the value of |nv| is not empty.
101 bool non_empty_value(const Headers::value_type *nv);
102
103 // Creates nghttp2_nv using |name| and |value| and returns it. The
104 // returned value only references the data pointer to name.c_str() and
105 // value.c_str().  If |no_index| is true, nghttp2_nv flags member has
106 // NGHTTP2_NV_FLAG_NO_INDEX flag set.
107 nghttp2_nv make_nv(const std::string &name, const std::string &value,
108                    bool no_index = false);
109
110 // Create nghttp2_nv from string literal |name| and |value|.
111 template <size_t N, size_t M>
112 nghttp2_nv make_nv_ll(const char (&name)[N], const char (&value)[M]) {
113   return {(uint8_t *)name, (uint8_t *)value, N - 1, M - 1,
114           NGHTTP2_NV_FLAG_NONE};
115 }
116
117 // Create nghttp2_nv from string literal |name| and c-string |value|.
118 template <size_t N>
119 nghttp2_nv make_nv_lc(const char (&name)[N], const char *value) {
120   return {(uint8_t *)name, (uint8_t *)value, N - 1, strlen(value),
121           NGHTTP2_NV_FLAG_NONE};
122 }
123
124 // Create nghttp2_nv from string literal |name| and std::string
125 // |value|.
126 template <size_t N>
127 nghttp2_nv make_nv_ls(const char (&name)[N], const std::string &value) {
128   return {(uint8_t *)name, (uint8_t *)value.c_str(), N - 1, value.size(),
129           NGHTTP2_NV_FLAG_NONE};
130 }
131
132 // Appends headers in |headers| to |nv|.  |headers| must be indexed
133 // before this call (its element's token field is assigned).  Certain
134 // headers, including disallowed headers in HTTP/2 spec and headers
135 // which require special handling (i.e. via), are not copied.
136 void copy_headers_to_nva(std::vector<nghttp2_nv> &nva, const Headers &headers);
137
138 // Appends HTTP/1.1 style header lines to |hdrs| from headers in
139 // |headers|.  |headers| must be indexed before this call (its
140 // element's token field is assigned).  Certain headers, which
141 // requires special handling (i.e. via and cookie), are not appended.
142 void build_http1_headers_from_headers(std::string &hdrs,
143                                       const Headers &headers);
144
145 // Return positive window_size_increment if WINDOW_UPDATE should be
146 // sent for the stream |stream_id|. If |stream_id| == 0, this function
147 // determines the necessity of the WINDOW_UPDATE for a connection.
148 //
149 // If the function determines WINDOW_UPDATE is not necessary at the
150 // moment, it returns -1.
151 int32_t determine_window_update_transmission(nghttp2_session *session,
152                                              int32_t stream_id);
153
154 // Dumps name/value pairs in |nv| to |out|. The |nv| must be
155 // terminated by nullptr.
156 void dump_nv(FILE *out, const char **nv);
157
158 // Dumps name/value pairs in |nva| to |out|.
159 void dump_nv(FILE *out, const nghttp2_nv *nva, size_t nvlen);
160
161 // Dumps name/value pairs in |nva| to |out|.
162 void dump_nv(FILE *out, const Headers &nva);
163
164 // Rewrites redirection URI which usually appears in location header
165 // field. The |uri| is the URI in the location header field. The |u|
166 // stores the result of parsed |uri|. The |request_authority| is the
167 // host or :authority header field value in the request. The
168 // |upstream_scheme| is either "https" or "http" in the upstream
169 // interface.  Rewrite is done only if location header field value
170 // contains |match_host| as host excluding port.  The |match_host| and
171 // |request_authority| could be different.  If |request_authority| is
172 // empty, strip authority.
173 //
174 // This function returns the new rewritten URI on success. If the
175 // location URI is not subject to the rewrite, this function returns
176 // emtpy string.
177 std::string rewrite_location_uri(const std::string &uri,
178                                  const http_parser_url &u,
179                                  const std::string &match_host,
180                                  const std::string &request_authority,
181                                  const std::string &upstream_scheme);
182
183 // Checks the header name/value pair using nghttp2_check_header_name()
184 // and nghttp2_check_header_value(). If both function returns nonzero,
185 // this function returns nonzero.
186 int check_nv(const uint8_t *name, size_t namelen, const uint8_t *value,
187              size_t valuelen);
188
189 // Returns parsed HTTP status code.  Returns -1 on failure.
190 int parse_http_status_code(const std::string &src);
191
192 // Header fields to be indexed, except HD_MAXIDX which is convenient
193 // member to get maximum value.
194 enum {
195   HD__AUTHORITY,
196   HD__HOST,
197   HD__METHOD,
198   HD__PATH,
199   HD__SCHEME,
200   HD__STATUS,
201   HD_ACCEPT_ENCODING,
202   HD_ACCEPT_LANGUAGE,
203   HD_ALT_SVC,
204   HD_CACHE_CONTROL,
205   HD_CONNECTION,
206   HD_CONTENT_LENGTH,
207   HD_COOKIE,
208   HD_EXPECT,
209   HD_HOST,
210   HD_HTTP2_SETTINGS,
211   HD_IF_MODIFIED_SINCE,
212   HD_KEEP_ALIVE,
213   HD_LINK,
214   HD_LOCATION,
215   HD_PROXY_CONNECTION,
216   HD_SERVER,
217   HD_TE,
218   HD_TRAILER,
219   HD_TRANSFER_ENCODING,
220   HD_UPGRADE,
221   HD_USER_AGENT,
222   HD_VIA,
223   HD_X_FORWARDED_FOR,
224   HD_X_FORWARDED_PROTO,
225   HD_MAXIDX,
226 };
227
228 using HeaderIndex = std::array<int16_t, HD_MAXIDX>;
229
230 // Looks up header token for header name |name| of length |namelen|.
231 // Only headers we are interested in are tokenized.  If header name
232 // cannot be tokenized, returns -1.
233 int lookup_token(const uint8_t *name, size_t namelen);
234 int lookup_token(const std::string &name);
235
236 // Initializes |hdidx|, header index.  The |hdidx| must point to the
237 // array containing at least HD_MAXIDX elements.
238 void init_hdidx(HeaderIndex &hdidx);
239 // Indexes header |token| using index |idx|.
240 void index_header(HeaderIndex &hdidx, int16_t token, size_t idx);
241
242 // Returns true if HTTP/2 request pseudo header |token| is not indexed
243 // yet and not -1.
244 bool check_http2_request_pseudo_header(const HeaderIndex &hdidx, int16_t token);
245
246 // Returns true if HTTP/2 response pseudo header |token| is not
247 // indexed yet and not -1.
248 bool check_http2_response_pseudo_header(const HeaderIndex &hdidx,
249                                         int16_t token);
250
251 // Returns true if header field denoted by |token| is allowed for
252 // HTTP/2.
253 bool http2_header_allowed(int16_t token);
254
255 // Returns true that |hdidx| contains mandatory HTTP/2 request
256 // headers.
257 bool http2_mandatory_request_headers_presence(const HeaderIndex &hdidx);
258
259 // Returns header denoted by |token| using index |hdidx|.
260 const Headers::value_type *get_header(const HeaderIndex &hdidx, int16_t token,
261                                       const Headers &nva);
262
263 struct LinkHeader {
264   // The region of URI is [uri.first, uri.second).
265   std::pair<const char *, const char *> uri;
266 };
267
268 // Returns next URI-reference in Link header field value |src| of
269 // length |len|.  If no URI-reference found after searching all input,
270 // returned uri field is empty.  This imply that empty URI-reference
271 // is ignored during parsing.
272 std::vector<LinkHeader> parse_link_header(const char *src, size_t len);
273
274 // Constructs path by combining base path |base_path| of length
275 // |base_pathlen| with another path |rel_path| of length
276 // |rel_pathlen|.  The base path and another path can have optional
277 // query component.  This function assumes |base_path| is
278 // cannibalized.  In other words, it does not contain ".." or "." path
279 // components and starts with "/" if it is not empty.
280 std::string path_join(const char *base_path, size_t base_pathlen,
281                       const char *base_query, size_t base_querylen,
282                       const char *rel_path, size_t rel_pathlen,
283                       const char *rel_query, size_t rel_querylen);
284
285 } // namespace http2
286
287 } // namespace nghttp2
288
289 #endif // HTTP2_H