Imported Upstream version 1.46.0
[platform/upstream/nghttp2.git] / src / http3.cc
1 /*
2  * nghttp2 - HTTP/2 C Library
3  *
4  * Copyright (c) 2021 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 #include "http3.h"
26
27 namespace nghttp2 {
28
29 namespace http3 {
30
31 namespace {
32 nghttp3_nv make_nv_internal(const std::string &name, const std::string &value,
33                             bool never_index, uint8_t nv_flags) {
34   uint8_t flags;
35
36   flags = nv_flags |
37           (never_index ? NGHTTP3_NV_FLAG_NEVER_INDEX : NGHTTP3_NV_FLAG_NONE);
38
39   return {(uint8_t *)name.c_str(), (uint8_t *)value.c_str(), name.size(),
40           value.size(), flags};
41 }
42 } // namespace
43
44 namespace {
45 nghttp3_nv make_nv_internal(const StringRef &name, const StringRef &value,
46                             bool never_index, uint8_t nv_flags) {
47   uint8_t flags;
48
49   flags = nv_flags |
50           (never_index ? NGHTTP3_NV_FLAG_NEVER_INDEX : NGHTTP3_NV_FLAG_NONE);
51
52   return {(uint8_t *)name.c_str(), (uint8_t *)value.c_str(), name.size(),
53           value.size(), flags};
54 }
55 } // namespace
56
57 nghttp3_nv make_nv(const std::string &name, const std::string &value,
58                    bool never_index) {
59   return make_nv_internal(name, value, never_index, NGHTTP3_NV_FLAG_NONE);
60 }
61
62 nghttp3_nv make_nv(const StringRef &name, const StringRef &value,
63                    bool never_index) {
64   return make_nv_internal(name, value, never_index, NGHTTP3_NV_FLAG_NONE);
65 }
66
67 nghttp3_nv make_nv_nocopy(const std::string &name, const std::string &value,
68                           bool never_index) {
69   return make_nv_internal(name, value, never_index,
70                           NGHTTP3_NV_FLAG_NO_COPY_NAME |
71                               NGHTTP3_NV_FLAG_NO_COPY_VALUE);
72 }
73
74 nghttp3_nv make_nv_nocopy(const StringRef &name, const StringRef &value,
75                           bool never_index) {
76   return make_nv_internal(name, value, never_index,
77                           NGHTTP3_NV_FLAG_NO_COPY_NAME |
78                               NGHTTP3_NV_FLAG_NO_COPY_VALUE);
79 }
80
81 namespace {
82 void copy_headers_to_nva_internal(std::vector<nghttp3_nv> &nva,
83                                   const HeaderRefs &headers, uint8_t nv_flags,
84                                   uint32_t flags) {
85   auto it_forwarded = std::end(headers);
86   auto it_xff = std::end(headers);
87   auto it_xfp = std::end(headers);
88   auto it_via = std::end(headers);
89
90   for (auto it = std::begin(headers); it != std::end(headers); ++it) {
91     auto kv = &(*it);
92     if (kv->name.empty() || kv->name[0] == ':') {
93       continue;
94     }
95     switch (kv->token) {
96     case http2::HD_COOKIE:
97     case http2::HD_CONNECTION:
98     case http2::HD_HOST:
99     case http2::HD_HTTP2_SETTINGS:
100     case http2::HD_KEEP_ALIVE:
101     case http2::HD_PROXY_CONNECTION:
102     case http2::HD_SERVER:
103     case http2::HD_TE:
104     case http2::HD_TRANSFER_ENCODING:
105     case http2::HD_UPGRADE:
106       continue;
107     case http2::HD_EARLY_DATA:
108       if (flags & http2::HDOP_STRIP_EARLY_DATA) {
109         continue;
110       }
111       break;
112     case http2::HD_SEC_WEBSOCKET_ACCEPT:
113       if (flags & http2::HDOP_STRIP_SEC_WEBSOCKET_ACCEPT) {
114         continue;
115       }
116       break;
117     case http2::HD_SEC_WEBSOCKET_KEY:
118       if (flags & http2::HDOP_STRIP_SEC_WEBSOCKET_KEY) {
119         continue;
120       }
121       break;
122     case http2::HD_FORWARDED:
123       if (flags & http2::HDOP_STRIP_FORWARDED) {
124         continue;
125       }
126
127       if (it_forwarded == std::end(headers)) {
128         it_forwarded = it;
129         continue;
130       }
131
132       kv = &(*it_forwarded);
133       it_forwarded = it;
134       break;
135     case http2::HD_X_FORWARDED_FOR:
136       if (flags & http2::HDOP_STRIP_X_FORWARDED_FOR) {
137         continue;
138       }
139
140       if (it_xff == std::end(headers)) {
141         it_xff = it;
142         continue;
143       }
144
145       kv = &(*it_xff);
146       it_xff = it;
147       break;
148     case http2::HD_X_FORWARDED_PROTO:
149       if (flags & http2::HDOP_STRIP_X_FORWARDED_PROTO) {
150         continue;
151       }
152
153       if (it_xfp == std::end(headers)) {
154         it_xfp = it;
155         continue;
156       }
157
158       kv = &(*it_xfp);
159       it_xfp = it;
160       break;
161     case http2::HD_VIA:
162       if (flags & http2::HDOP_STRIP_VIA) {
163         continue;
164       }
165
166       if (it_via == std::end(headers)) {
167         it_via = it;
168         continue;
169       }
170
171       kv = &(*it_via);
172       it_via = it;
173       break;
174     }
175     nva.push_back(
176         make_nv_internal(kv->name, kv->value, kv->no_index, nv_flags));
177   }
178 }
179 } // namespace
180
181 void copy_headers_to_nva(std::vector<nghttp3_nv> &nva,
182                          const HeaderRefs &headers, uint32_t flags) {
183   copy_headers_to_nva_internal(nva, headers, NGHTTP3_NV_FLAG_NONE, flags);
184 }
185
186 void copy_headers_to_nva_nocopy(std::vector<nghttp3_nv> &nva,
187                                 const HeaderRefs &headers, uint32_t flags) {
188   copy_headers_to_nva_internal(
189       nva, headers,
190       NGHTTP3_NV_FLAG_NO_COPY_NAME | NGHTTP3_NV_FLAG_NO_COPY_VALUE, flags);
191 }
192
193 int check_nv(const uint8_t *name, size_t namelen, const uint8_t *value,
194              size_t valuelen) {
195   if (!nghttp3_check_header_name(name, namelen)) {
196     return 0;
197   }
198   if (!nghttp3_check_header_value(value, valuelen)) {
199     return 0;
200   }
201   return 1;
202 }
203
204 } // namespace http3
205
206 } // namespace nghttp2