VirtualBox

source: vbox/trunk/src/libs/curl-7.83.1/lib/h2h3.c@ 97623

Last change on this file since 97623 was 95312, checked in by vboxsync, 3 years ago

libs/{curl,libxml2}: OSE export fixes, bugref:8515

  • Property svn:eol-style set to native
File size: 8.7 KB
Line 
1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2022, Daniel Stenberg, <[email protected]>, et al.
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.se/docs/copyright.html.
13 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ***************************************************************************/
22
23#include "curl_setup.h"
24#include "urldata.h"
25#include "h2h3.h"
26#include "transfer.h"
27#include "sendf.h"
28#include "strcase.h"
29
30/* The last 3 #include files should be in this order */
31#include "curl_printf.h"
32#include "curl_memory.h"
33#include "memdebug.h"
34
35/*
36 * Curl_pseudo_headers() creates the array with pseudo headers to be
37 * used in a HTTP/2 or HTTP/3 request.
38 */
39
40#if defined(USE_NGHTTP2) || defined(ENABLE_QUIC)
41
42/* Index where :authority header field will appear in request header
43 field list. */
44#define AUTHORITY_DST_IDX 3
45
46/* USHRT_MAX is 65535 == 0xffff */
47#define HEADER_OVERFLOW(x) \
48 (x.namelen > 0xffff || x.valuelen > 0xffff - x.namelen)
49
50/*
51 * Check header memory for the token "trailers".
52 * Parse the tokens as separated by comma and surrounded by whitespace.
53 * Returns TRUE if found or FALSE if not.
54 */
55static bool contains_trailers(const char *p, size_t len)
56{
57 const char *end = p + len;
58 for(;;) {
59 for(; p != end && (*p == ' ' || *p == '\t'); ++p)
60 ;
61 if(p == end || (size_t)(end - p) < sizeof("trailers") - 1)
62 return FALSE;
63 if(strncasecompare("trailers", p, sizeof("trailers") - 1)) {
64 p += sizeof("trailers") - 1;
65 for(; p != end && (*p == ' ' || *p == '\t'); ++p)
66 ;
67 if(p == end || *p == ',')
68 return TRUE;
69 }
70 /* skip to next token */
71 for(; p != end && *p != ','; ++p)
72 ;
73 if(p == end)
74 return FALSE;
75 ++p;
76 }
77}
78
79typedef enum {
80 /* Send header to server */
81 HEADERINST_FORWARD,
82 /* Don't send header to server */
83 HEADERINST_IGNORE,
84 /* Discard header, and replace it with "te: trailers" */
85 HEADERINST_TE_TRAILERS
86} header_instruction;
87
88/* Decides how to treat given header field. */
89static header_instruction inspect_header(const char *name, size_t namelen,
90 const char *value, size_t valuelen) {
91 switch(namelen) {
92 case 2:
93 if(!strncasecompare("te", name, namelen))
94 return HEADERINST_FORWARD;
95
96 return contains_trailers(value, valuelen) ?
97 HEADERINST_TE_TRAILERS : HEADERINST_IGNORE;
98 case 7:
99 return strncasecompare("upgrade", name, namelen) ?
100 HEADERINST_IGNORE : HEADERINST_FORWARD;
101 case 10:
102 return (strncasecompare("connection", name, namelen) ||
103 strncasecompare("keep-alive", name, namelen)) ?
104 HEADERINST_IGNORE : HEADERINST_FORWARD;
105 case 16:
106 return strncasecompare("proxy-connection", name, namelen) ?
107 HEADERINST_IGNORE : HEADERINST_FORWARD;
108 case 17:
109 return strncasecompare("transfer-encoding", name, namelen) ?
110 HEADERINST_IGNORE : HEADERINST_FORWARD;
111 default:
112 return HEADERINST_FORWARD;
113 }
114}
115
116CURLcode Curl_pseudo_headers(struct Curl_easy *data,
117 const char *mem, /* the request */
118 const size_t len /* size of request */,
119 struct h2h3req **hp)
120{
121 struct connectdata *conn = data->conn;
122 size_t nheader = 0;
123 size_t i;
124 size_t authority_idx;
125 char *hdbuf = (char *)mem;
126 char *end, *line_end;
127 struct h2h3pseudo *nva = NULL;
128 struct h2h3req *hreq = NULL;
129 char *vptr;
130
131 /* Calculate number of headers contained in [mem, mem + len). Assumes a
132 correctly generated HTTP header field block. */
133 for(i = 1; i < len; ++i) {
134 if(hdbuf[i] == '\n' && hdbuf[i - 1] == '\r') {
135 ++nheader;
136 ++i;
137 }
138 }
139 if(nheader < 2) {
140 goto fail;
141 }
142 /* We counted additional 2 \r\n in the first and last line. We need 3
143 new headers: :method, :path and :scheme. Therefore we need one
144 more space. */
145 nheader += 1;
146 hreq = malloc(sizeof(struct h2h3req) +
147 sizeof(struct h2h3pseudo) * (nheader - 1));
148 if(!hreq) {
149 goto fail;
150 }
151
152 nva = &hreq->header[0];
153
154 /* Extract :method, :path from request line
155 We do line endings with CRLF so checking for CR is enough */
156 line_end = memchr(hdbuf, '\r', len);
157 if(!line_end) {
158 goto fail;
159 }
160
161 /* Method does not contain spaces */
162 end = memchr(hdbuf, ' ', line_end - hdbuf);
163 if(!end || end == hdbuf)
164 goto fail;
165 nva[0].name = H2H3_PSEUDO_METHOD;
166 nva[0].namelen = sizeof(H2H3_PSEUDO_METHOD) - 1;
167 nva[0].value = hdbuf;
168 nva[0].valuelen = (size_t)(end - hdbuf);
169
170 hdbuf = end + 1;
171
172 /* Path may contain spaces so scan backwards */
173 end = NULL;
174 for(i = (size_t)(line_end - hdbuf); i; --i) {
175 if(hdbuf[i - 1] == ' ') {
176 end = &hdbuf[i - 1];
177 break;
178 }
179 }
180 if(!end || end == hdbuf)
181 goto fail;
182 nva[1].name = H2H3_PSEUDO_PATH;
183 nva[1].namelen = sizeof(H2H3_PSEUDO_PATH) - 1;
184 nva[1].value = hdbuf;
185 nva[1].valuelen = (end - hdbuf);
186
187 nva[2].name = H2H3_PSEUDO_SCHEME;
188 nva[2].namelen = sizeof(H2H3_PSEUDO_SCHEME) - 1;
189 vptr = Curl_checkheaders(data, STRCONST(H2H3_PSEUDO_SCHEME));
190 if(vptr) {
191 vptr += sizeof(H2H3_PSEUDO_SCHEME);
192 while(*vptr && ISSPACE(*vptr))
193 vptr++;
194 nva[2].value = vptr;
195 infof(data, "set pseudo header %s to %s", H2H3_PSEUDO_SCHEME, vptr);
196 }
197 else {
198 if(conn->handler->flags & PROTOPT_SSL)
199 nva[2].value = "https";
200 else
201 nva[2].value = "http";
202 }
203 nva[2].valuelen = strlen((char *)nva[2].value);
204
205 authority_idx = 0;
206 i = 3;
207 while(i < nheader) {
208 size_t hlen;
209
210 hdbuf = line_end + 2;
211
212 /* check for next CR, but only within the piece of data left in the given
213 buffer */
214 line_end = memchr(hdbuf, '\r', len - (hdbuf - (char *)mem));
215 if(!line_end || (line_end == hdbuf))
216 goto fail;
217
218 /* header continuation lines are not supported */
219 if(*hdbuf == ' ' || *hdbuf == '\t')
220 goto fail;
221
222 for(end = hdbuf; end < line_end && *end != ':'; ++end)
223 ;
224 if(end == hdbuf || end == line_end)
225 goto fail;
226 hlen = end - hdbuf;
227
228 if(hlen == 4 && strncasecompare("host", hdbuf, 4)) {
229 authority_idx = i;
230 nva[i].name = H2H3_PSEUDO_AUTHORITY;
231 nva[i].namelen = sizeof(H2H3_PSEUDO_AUTHORITY) - 1;
232 }
233 else {
234 nva[i].namelen = (size_t)(end - hdbuf);
235 /* Lower case the header name for HTTP/3 */
236 Curl_strntolower((char *)hdbuf, hdbuf, nva[i].namelen);
237 nva[i].name = hdbuf;
238 }
239 hdbuf = end + 1;
240 while(*hdbuf == ' ' || *hdbuf == '\t')
241 ++hdbuf;
242 end = line_end;
243
244 switch(inspect_header((const char *)nva[i].name, nva[i].namelen, hdbuf,
245 end - hdbuf)) {
246 case HEADERINST_IGNORE:
247 /* skip header fields prohibited by HTTP/2 specification. */
248 --nheader;
249 continue;
250 case HEADERINST_TE_TRAILERS:
251 nva[i].value = "trailers";
252 nva[i].valuelen = sizeof("trailers") - 1;
253 break;
254 default:
255 nva[i].value = hdbuf;
256 nva[i].valuelen = (end - hdbuf);
257 }
258
259 nva[i].value = hdbuf;
260 nva[i].valuelen = (end - hdbuf);
261
262 ++i;
263 }
264
265 /* :authority must come before non-pseudo header fields */
266 if(authority_idx && authority_idx != AUTHORITY_DST_IDX) {
267 struct h2h3pseudo authority = nva[authority_idx];
268 for(i = authority_idx; i > AUTHORITY_DST_IDX; --i) {
269 nva[i] = nva[i - 1];
270 }
271 nva[i] = authority;
272 }
273
274 /* Warn stream may be rejected if cumulative length of headers is too
275 large. */
276#define MAX_ACC 60000 /* <64KB to account for some overhead */
277 {
278 size_t acc = 0;
279
280 for(i = 0; i < nheader; ++i) {
281 acc += nva[i].namelen + nva[i].valuelen;
282
283 infof(data, "h2h3 [%.*s: %.*s]",
284 (int)nva[i].namelen, nva[i].name,
285 (int)nva[i].valuelen, nva[i].value);
286 }
287
288 if(acc > MAX_ACC) {
289 infof(data, "http_request: Warning: The cumulative length of all "
290 "headers exceeds %d bytes and that could cause the "
291 "stream to be rejected.", MAX_ACC);
292 }
293 }
294
295 hreq->entries = nheader;
296 *hp = hreq;
297
298 return CURLE_OK;
299
300 fail:
301 free(hreq);
302 return CURLE_OUT_OF_MEMORY;
303}
304
305void Curl_pseudo_free(struct h2h3req *hp)
306{
307 free(hp);
308}
309
310#endif /* USE_NGHTTP2 or HTTP/3 enabled */
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette