VirtualBox

source: vbox/trunk/src/libs/curl-8.0.1/lib/headers.c@ 100906

Last change on this file since 100906 was 99344, checked in by vboxsync, 2 years ago

curl-8.0.1: Applied and adjusted our curl changes to 7.87.0 bugref:10417

  • Property svn:eol-style set to native
File size: 11.0 KB
Line 
1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 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 * SPDX-License-Identifier: curl
22 *
23 ***************************************************************************/
24
25#include "curl_setup.h"
26
27#include "urldata.h"
28#include "strdup.h"
29#include "strcase.h"
30#include "headers.h"
31
32/* The last 3 #include files should be in this order */
33#include "curl_printf.h"
34#include "curl_memory.h"
35#include "memdebug.h"
36
37#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_HEADERS_API)
38
39/* Generate the curl_header struct for the user. This function MUST assign all
40 struct fields in the output struct. */
41static void copy_header_external(struct Curl_header_store *hs,
42 size_t index,
43 size_t amount,
44 struct Curl_llist_element *e,
45 struct curl_header *hout)
46{
47 struct curl_header *h = hout;
48 h->name = hs->name;
49 h->value = hs->value;
50 h->amount = amount;
51 h->index = index;
52 /* this will randomly OR a reserved bit for the sole purpose of making it
53 impossible for applications to do == comparisons, as that would otherwise
54 be very tempting and then lead to the reserved bits not being reserved
55 anymore. */
56 h->origin = hs->type | (1<<27);
57 h->anchor = e;
58}
59
60/* public API */
61CURLHcode curl_easy_header(CURL *easy,
62 const char *name,
63 size_t nameindex,
64 unsigned int type,
65 int request,
66 struct curl_header **hout)
67{
68 struct Curl_llist_element *e;
69 struct Curl_llist_element *e_pick = NULL;
70 struct Curl_easy *data = easy;
71 size_t match = 0;
72 size_t amount = 0;
73 struct Curl_header_store *hs = NULL;
74 struct Curl_header_store *pick = NULL;
75 if(!name || !hout || !data ||
76 (type > (CURLH_HEADER|CURLH_TRAILER|CURLH_CONNECT|CURLH_1XX|
77 CURLH_PSEUDO)) || !type || (request < -1))
78 return CURLHE_BAD_ARGUMENT;
79 if(!Curl_llist_count(&data->state.httphdrs))
80 return CURLHE_NOHEADERS; /* no headers available */
81 if(request > data->state.requests)
82 return CURLHE_NOREQUEST;
83 if(request == -1)
84 request = data->state.requests;
85
86 /* we need a first round to count amount of this header */
87 for(e = data->state.httphdrs.head; e; e = e->next) {
88 hs = e->ptr;
89 if(strcasecompare(hs->name, name) &&
90 (hs->type & type) &&
91 (hs->request == request)) {
92 amount++;
93 pick = hs;
94 e_pick = e;
95 }
96 }
97 if(!amount)
98 return CURLHE_MISSING;
99 else if(nameindex >= amount)
100 return CURLHE_BADINDEX;
101
102 if(nameindex == amount - 1)
103 /* if the last or only occurrence is what's asked for, then we know it */
104 hs = pick;
105 else {
106 for(e = data->state.httphdrs.head; e; e = e->next) {
107 hs = e->ptr;
108 if(strcasecompare(hs->name, name) &&
109 (hs->type & type) &&
110 (hs->request == request) &&
111 (match++ == nameindex)) {
112 e_pick = e;
113 break;
114 }
115 }
116 if(!e) /* this shouldn't happen */
117 return CURLHE_MISSING;
118 }
119 /* this is the name we want */
120 copy_header_external(hs, nameindex, amount, e_pick,
121 &data->state.headerout[0]);
122 *hout = &data->state.headerout[0];
123 return CURLHE_OK;
124}
125
126/* public API */
127struct curl_header *curl_easy_nextheader(CURL *easy,
128 unsigned int type,
129 int request,
130 struct curl_header *prev)
131{
132 struct Curl_easy *data = easy;
133 struct Curl_llist_element *pick;
134 struct Curl_llist_element *e;
135 struct Curl_header_store *hs;
136 size_t amount = 0;
137 size_t index = 0;
138
139 if(request > data->state.requests)
140 return NULL;
141 if(request == -1)
142 request = data->state.requests;
143
144 if(prev) {
145 pick = prev->anchor;
146 if(!pick)
147 /* something is wrong */
148 return NULL;
149 pick = pick->next;
150 }
151 else
152 pick = data->state.httphdrs.head;
153
154 if(pick) {
155 /* make sure it is the next header of the desired type */
156 do {
157 hs = pick->ptr;
158 if((hs->type & type) && (hs->request == request))
159 break;
160 pick = pick->next;
161 } while(pick);
162 }
163
164 if(!pick)
165 /* no more headers available */
166 return NULL;
167
168 hs = pick->ptr;
169
170 /* count number of occurrences of this name within the mask and figure out
171 the index for the currently selected entry */
172 for(e = data->state.httphdrs.head; e; e = e->next) {
173 struct Curl_header_store *check = e->ptr;
174 if(strcasecompare(hs->name, check->name) &&
175 (check->request == request) &&
176 (check->type & type))
177 amount++;
178 if(e == pick)
179 index = amount - 1;
180 }
181
182 copy_header_external(hs, index, amount, pick,
183 &data->state.headerout[1]);
184 return &data->state.headerout[1];
185}
186
187static CURLcode namevalue(char *header, size_t hlen, unsigned int type,
188 char **name, char **value)
189{
190 char *end = header + hlen - 1; /* point to the last byte */
191 DEBUGASSERT(hlen);
192 *name = header;
193
194 if(type == CURLH_PSEUDO) {
195 if(*header != ':')
196 return CURLE_BAD_FUNCTION_ARGUMENT;
197 header++;
198 }
199
200 /* Find the end of the header name */
201 while(*header && (*header != ':'))
202 ++header;
203
204 if(*header)
205 /* Skip over colon, null it */
206 *header++ = 0;
207 else
208 return CURLE_BAD_FUNCTION_ARGUMENT;
209
210 /* skip all leading space letters */
211 while(*header && ISBLANK(*header))
212 header++;
213
214 *value = header;
215
216 /* skip all trailing space letters */
217 while((end > header) && ISSPACE(*end))
218 *end-- = 0; /* nul terminate */
219 return CURLE_OK;
220}
221
222static CURLcode unfold_value(struct Curl_easy *data, const char *value,
223 size_t vlen) /* length of the incoming header */
224{
225 struct Curl_header_store *hs;
226 struct Curl_header_store *newhs;
227 size_t olen; /* length of the old value */
228 size_t oalloc; /* length of the old name + value + separator */
229 size_t offset;
230 DEBUGASSERT(data->state.prevhead);
231 hs = data->state.prevhead;
232 olen = strlen(hs->value);
233 offset = hs->value - hs->buffer;
234 oalloc = olen + offset + 1;
235
236 /* skip all trailing space letters */
237 while(vlen && ISSPACE(value[vlen - 1]))
238 vlen--;
239
240 /* save only one leading space */
241 while((vlen > 1) && ISBLANK(value[0]) && ISBLANK(value[1])) {
242 vlen--;
243 value++;
244 }
245
246 /* since this header block might move in the realloc below, it needs to
247 first be unlinked from the list and then re-added again after the
248 realloc */
249 Curl_llist_remove(&data->state.httphdrs, &hs->node, NULL);
250
251 /* new size = struct + new value length + old name+value length */
252 newhs = Curl_saferealloc(hs, sizeof(*hs) + vlen + oalloc + 1);
253 if(!newhs)
254 return CURLE_OUT_OF_MEMORY;
255 /* ->name' and ->value point into ->buffer (to keep the header allocation
256 in a single memory block), which now potentially have moved. Adjust
257 them. */
258 newhs->name = newhs->buffer;
259 newhs->value = &newhs->buffer[offset];
260
261 /* put the data at the end of the previous data, not the newline */
262 memcpy(&newhs->value[olen], value, vlen);
263 newhs->value[olen + vlen] = 0; /* null-terminate at newline */
264
265 /* insert this node into the list of headers */
266 Curl_llist_insert_next(&data->state.httphdrs, data->state.httphdrs.tail,
267 newhs, &newhs->node);
268 data->state.prevhead = newhs;
269 return CURLE_OK;
270}
271
272
273/*
274 * Curl_headers_push() gets passed a full HTTP header to store. It gets called
275 * immediately before the header callback. The header is CRLF terminated.
276 */
277CURLcode Curl_headers_push(struct Curl_easy *data, const char *header,
278 unsigned char type)
279{
280 char *value = NULL;
281 char *name = NULL;
282 char *end;
283 size_t hlen; /* length of the incoming header */
284 struct Curl_header_store *hs;
285 CURLcode result = CURLE_OUT_OF_MEMORY;
286
287 if((header[0] == '\r') || (header[0] == '\n'))
288 /* ignore the body separator */
289 return CURLE_OK;
290
291 end = strchr(header, '\r');
292 if(!end) {
293 end = strchr(header, '\n');
294 if(!end)
295 return CURLE_BAD_FUNCTION_ARGUMENT;
296 }
297 hlen = end - header + 1;
298
299 if((header[0] == ' ') || (header[0] == '\t')) {
300 if(data->state.prevhead)
301 /* line folding, append value to the previous header's value */
302 return unfold_value(data, header, hlen);
303 else
304 /* can't unfold without a previous header */
305 return CURLE_BAD_FUNCTION_ARGUMENT;
306 }
307
308 hs = calloc(1, sizeof(*hs) + hlen);
309 if(!hs)
310 return CURLE_OUT_OF_MEMORY;
311 memcpy(hs->buffer, header, hlen);
312 hs->buffer[hlen] = 0; /* nul terminate */
313
314 result = namevalue(hs->buffer, hlen, type, &name, &value);
315 if(result)
316 goto fail;
317
318 hs->name = name;
319 hs->value = value;
320 hs->type = type;
321 hs->request = data->state.requests;
322
323 /* insert this node into the list of headers */
324 Curl_llist_insert_next(&data->state.httphdrs, data->state.httphdrs.tail,
325 hs, &hs->node);
326 data->state.prevhead = hs;
327 return CURLE_OK;
328 fail:
329 free(hs);
330 return result;
331}
332
333/*
334 * Curl_headers_init(). Init the headers subsystem.
335 */
336static void headers_init(struct Curl_easy *data)
337{
338 Curl_llist_init(&data->state.httphdrs, NULL);
339}
340
341/*
342 * Curl_headers_cleanup(). Free all stored headers and associated memory.
343 */
344CURLcode Curl_headers_cleanup(struct Curl_easy *data)
345{
346 struct Curl_llist_element *e;
347 struct Curl_llist_element *n;
348
349 for(e = data->state.httphdrs.head; e; e = n) {
350 struct Curl_header_store *hs = e->ptr;
351 n = e->next;
352 free(hs);
353 }
354 headers_init(data);
355 return CURLE_OK;
356}
357
358#else /* HTTP-disabled builds below */
359
360CURLHcode curl_easy_header(CURL *easy,
361 const char *name,
362 size_t index,
363 unsigned int origin,
364 int request,
365 struct curl_header **hout)
366{
367 (void)easy;
368 (void)name;
369 (void)index;
370 (void)origin;
371 (void)request;
372 (void)hout;
373 return CURLHE_NOT_BUILT_IN;
374}
375
376struct curl_header *curl_easy_nextheader(CURL *easy,
377 unsigned int type,
378 int request,
379 struct curl_header *prev)
380{
381 (void)easy;
382 (void)type;
383 (void)request;
384 (void)prev;
385 return NULL;
386}
387#endif
Note: See TracBrowser for help on using the repository browser.

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