| | varnish-cache/bin/varnishd/cache/cache_http.c |
0 |
|
/*- |
1 |
|
* Copyright (c) 2006 Verdens Gang AS |
2 |
|
* Copyright (c) 2006-2017 Varnish Software AS |
3 |
|
* All rights reserved. |
4 |
|
* |
5 |
|
* Author: Poul-Henning Kamp <phk@phk.freebsd.dk> |
6 |
|
* |
7 |
|
* SPDX-License-Identifier: BSD-2-Clause |
8 |
|
* |
9 |
|
* Redistribution and use in source and binary forms, with or without |
10 |
|
* modification, are permitted provided that the following conditions |
11 |
|
* are met: |
12 |
|
* 1. Redistributions of source code must retain the above copyright |
13 |
|
* notice, this list of conditions and the following disclaimer. |
14 |
|
* 2. Redistributions in binary form must reproduce the above copyright |
15 |
|
* notice, this list of conditions and the following disclaimer in the |
16 |
|
* documentation and/or other materials provided with the distribution. |
17 |
|
* |
18 |
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
19 |
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
20 |
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
21 |
|
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE |
22 |
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
23 |
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
24 |
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
25 |
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
26 |
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
27 |
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
28 |
|
* SUCH DAMAGE. |
29 |
|
* |
30 |
|
* HTTP request storage and manipulation |
31 |
|
*/ |
32 |
|
|
33 |
|
#include "config.h" |
34 |
|
|
35 |
|
#include "cache_varnishd.h" |
36 |
|
#include <stdio.h> |
37 |
|
#include <stdlib.h> |
38 |
|
|
39 |
|
#include "common/heritage.h" |
40 |
|
|
41 |
|
#include "vct.h" |
42 |
|
#include "vend.h" |
43 |
|
#include "vnum.h" |
44 |
|
#include "vtim.h" |
45 |
|
|
46 |
|
#define BODYSTATUS(U, l, n, a, k) \ |
47 |
|
const struct body_status BS_##U[1] = {{ \ |
48 |
|
.name = #l, \ |
49 |
|
.nbr = n, \ |
50 |
|
.avail = a, \ |
51 |
|
.length_known = k \ |
52 |
|
}}; |
53 |
|
#include "tbl/body_status.h" |
54 |
|
|
55 |
|
|
56 |
|
#define HTTPH(a, b, c) char b[] = "*" a ":"; |
57 |
|
#include "tbl/http_headers.h" |
58 |
|
|
59 |
|
const char H__Status[] = "\010:status:"; |
60 |
|
const char H__Proto[] = "\007:proto:"; |
61 |
|
const char H__Reason[] = "\010:reason:"; |
62 |
|
|
63 |
|
static char * via_hdr; |
64 |
|
|
65 |
|
/*-------------------------------------------------------------------- |
66 |
|
* Perfect hash to rapidly recognize headers from tbl/http_headers.h |
67 |
|
* which have non-zero flags. |
68 |
|
* |
69 |
|
* A suitable algorithm can be found with `gperf`: |
70 |
|
* |
71 |
|
* tr '" ,' ' ' < include/tbl/http_headers.h | |
72 |
|
* awk '$1 == "H(" {print $2}' | |
73 |
|
* gperf --ignore-case |
74 |
|
* |
75 |
|
*/ |
76 |
|
|
77 |
|
#define GPERF_MIN_WORD_LENGTH 2 |
78 |
|
#define GPERF_MAX_WORD_LENGTH 19 |
79 |
|
#define GPERF_MAX_HASH_VALUE 79 |
80 |
|
|
81 |
|
static const unsigned char http_asso_values[256] = { |
82 |
|
80, 80, 80, 80, 80, 80, 80, 80, 80, 80, |
83 |
|
80, 80, 80, 80, 80, 80, 80, 80, 80, 80, |
84 |
|
80, 80, 80, 80, 80, 80, 80, 80, 80, 80, |
85 |
|
80, 80, 80, 80, 80, 80, 80, 80, 80, 80, |
86 |
|
80, 80, 80, 80, 80, 80, 80, 80, 80, 80, |
87 |
|
80, 80, 80, 0, 80, 80, 80, 80, 80, 80, |
88 |
|
80, 80, 80, 80, 80, 5, 80, 20, 0, 0, |
89 |
|
5, 10, 5, 5, 80, 0, 15, 0, 20, 80, |
90 |
|
40, 80, 0, 35, 10, 20, 55, 45, 0, 0, |
91 |
|
80, 80, 80, 80, 80, 80, 80, 5, 80, 20, |
92 |
|
0, 0, 5, 10, 5, 5, 80, 0, 15, 0, |
93 |
|
20, 80, 40, 80, 0, 35, 10, 20, 55, 45, |
94 |
|
0, 0, 80, 80, 80, 80, 80, 80, 80, 80, |
95 |
|
80, 80, 80, 80, 80, 80, 80, 80, 80, 80, |
96 |
|
80, 80, 80, 80, 80, 80, 80, 80, 80, 80, |
97 |
|
80, 80, 80, 80, 80, 80, 80, 80, 80, 80, |
98 |
|
80, 80, 80, 80, 80, 80, 80, 80, 80, 80, |
99 |
|
80, 80, 80, 80, 80, 80, 80, 80, 80, 80, |
100 |
|
80, 80, 80, 80, 80, 80, 80, 80, 80, 80, |
101 |
|
80, 80, 80, 80, 80, 80, 80, 80, 80, 80, |
102 |
|
80, 80, 80, 80, 80, 80, 80, 80, 80, 80, |
103 |
|
80, 80, 80, 80, 80, 80, 80, 80, 80, 80, |
104 |
|
80, 80, 80, 80, 80, 80, 80, 80, 80, 80, |
105 |
|
80, 80, 80, 80, 80, 80, 80, 80, 80, 80, |
106 |
|
80, 80, 80, 80, 80, 80, 80, 80, 80, 80, |
107 |
|
80, 80, 80, 80, 80, 80 |
108 |
|
}; |
109 |
|
|
110 |
|
static struct http_hdrflg { |
111 |
|
char *hdr; |
112 |
|
unsigned flag; |
113 |
|
} http_hdrflg[GPERF_MAX_HASH_VALUE + 1] = { |
114 |
|
{ NULL }, { NULL }, { NULL }, { NULL }, |
115 |
|
{ H_Date }, |
116 |
|
{ H_Range }, |
117 |
|
{ NULL }, |
118 |
|
{ H_Referer }, |
119 |
|
{ H_Age }, |
120 |
|
{ H_From }, |
121 |
|
{ H_Keep_Alive }, |
122 |
|
{ H_Retry_After }, |
123 |
|
{ H_TE }, |
124 |
|
{ H_If_Range }, |
125 |
|
{ H_ETag }, |
126 |
|
{ H_X_Forwarded_For }, |
127 |
|
{ H_Expect }, |
128 |
|
{ H_Trailer }, |
129 |
|
{ H_If_Match }, |
130 |
|
{ H_Host }, |
131 |
|
{ H_Accept_Language }, |
132 |
|
{ H_Accept }, |
133 |
|
{ H_If_Modified_Since }, |
134 |
|
{ H_If_None_Match }, |
135 |
|
{ H_If_Unmodified_Since }, |
136 |
|
{ NULL }, |
137 |
|
{ H_Cookie }, |
138 |
|
{ H_Upgrade }, |
139 |
|
{ H_Last_Modified }, |
140 |
|
{ H_Accept_Charset }, |
141 |
|
{ H_Accept_Encoding }, |
142 |
|
{ H_Content_MD5 }, |
143 |
|
{ H_Content_Type }, |
144 |
|
{ H_Content_Range }, |
145 |
|
{ NULL }, { NULL }, |
146 |
|
{ H_Content_Language }, |
147 |
|
{ H_Transfer_Encoding }, |
148 |
|
{ H_Authorization }, |
149 |
|
{ H_Content_Length }, |
150 |
|
{ H_User_Agent }, |
151 |
|
{ H_Server }, |
152 |
|
{ H_Expires }, |
153 |
|
{ H_Location }, |
154 |
|
{ NULL }, |
155 |
|
{ H_Set_Cookie }, |
156 |
|
{ H_Content_Encoding }, |
157 |
|
{ H_Max_Forwards }, |
158 |
|
{ H_Cache_Control }, |
159 |
|
{ NULL }, |
160 |
|
{ H_Connection }, |
161 |
|
{ H_Pragma }, |
162 |
|
{ NULL }, |
163 |
|
{ H_Accept_Ranges }, |
164 |
|
{ H_HTTP2_Settings }, |
165 |
|
{ H_Allow }, |
166 |
|
{ H_Content_Location }, |
167 |
|
{ NULL }, |
168 |
|
{ H_Proxy_Authenticate }, |
169 |
|
{ H_Vary }, |
170 |
|
{ NULL }, |
171 |
|
{ H_WWW_Authenticate }, |
172 |
|
{ H_Warning }, |
173 |
|
{ H_Via }, |
174 |
|
{ NULL }, { NULL }, { NULL }, { NULL }, |
175 |
|
{ NULL }, { NULL }, { NULL }, { NULL }, |
176 |
|
{ NULL }, { NULL }, { NULL }, { NULL }, |
177 |
|
{ NULL }, { NULL }, { NULL }, |
178 |
|
{ H_Proxy_Authorization } |
179 |
|
}; |
180 |
|
|
181 |
|
static struct http_hdrflg * |
182 |
2937041 |
http_hdr_flags(const char *b, const char *e) |
183 |
|
{ |
184 |
|
unsigned u; |
185 |
|
struct http_hdrflg *retval; |
186 |
|
|
187 |
2937041 |
if (b == NULL || e == NULL) |
188 |
266 |
return (NULL); |
189 |
2937007 |
assert(b <= e); |
190 |
2937007 |
u = (unsigned)(e - b); |
191 |
2937007 |
assert(b + u == e); |
192 |
2937007 |
if (u < GPERF_MIN_WORD_LENGTH || u > GPERF_MAX_WORD_LENGTH) |
193 |
1162 |
return (NULL); |
194 |
5871690 |
u += http_asso_values[(uint8_t)(e[-1])] + |
195 |
2935845 |
http_asso_values[(uint8_t)(b[0])]; |
196 |
2935845 |
if (u > GPERF_MAX_HASH_VALUE) |
197 |
39880 |
return (NULL); |
198 |
2895965 |
retval = &http_hdrflg[u]; |
199 |
2895965 |
if (retval->hdr == NULL) |
200 |
10105 |
return (NULL); |
201 |
2885860 |
if (!http_hdr_at(retval->hdr + 1, b, e - b)) |
202 |
36240 |
return (NULL); |
203 |
2849620 |
return (retval); |
204 |
2937005 |
} |
205 |
|
|
206 |
|
/*--------------------------------------------------------------------*/ |
207 |
|
|
208 |
|
static void |
209 |
1907152 |
http_init_hdr(char *hdr, int flg) |
210 |
|
{ |
211 |
|
struct http_hdrflg *f; |
212 |
|
|
213 |
1907152 |
hdr[0] = strlen(hdr + 1); |
214 |
1907152 |
f = http_hdr_flags(hdr + 1, hdr + hdr[0]); |
215 |
1907152 |
AN(f); |
216 |
1907152 |
assert(f->hdr == hdr); |
217 |
1907152 |
f->flag = flg; |
218 |
1907152 |
} |
219 |
|
|
220 |
|
void |
221 |
36676 |
HTTP_Init(void) |
222 |
|
{ |
223 |
|
struct vsb *vsb; |
224 |
|
|
225 |
|
#define HTTPH(a, b, c) http_init_hdr(b, c); |
226 |
|
#include "tbl/http_headers.h" |
227 |
|
|
228 |
|
vsb = VSB_new_auto(); |
229 |
36676 |
AN(vsb); |
230 |
|
VSB_printf(vsb, "1.1 %s (Varnish/" PACKAGE_BRANCH ")", |
231 |
|
heritage.identity); |
232 |
36676 |
AZ(VSB_finish(vsb)); |
233 |
36676 |
REPLACE(via_hdr, VSB_data(vsb)); |
234 |
|
VSB_destroy(&vsb); |
235 |
|
} |
236 |
|
|
237 |
|
/*-------------------------------------------------------------------- |
238 |
|
* These two functions are in an incestuous relationship with the |
239 |
|
* order of macros in include/tbl/vsl_tags_http.h |
240 |
|
* |
241 |
|
* The http->logtag is the SLT_*Method enum, and we add to that, to |
242 |
|
* get the SLT_ to use. |
243 |
|
*/ |
244 |
|
|
245 |
|
static void |
246 |
4842013 |
http_VSLH(const struct http *hp, unsigned hdr) |
247 |
|
{ |
248 |
|
int i; |
249 |
|
|
250 |
4842013 |
if (hp->vsl != NULL) { |
251 |
4842127 |
assert(VXID_TAG(hp->vsl->wid)); |
252 |
4842127 |
i = hdr; |
253 |
4842127 |
if (i > HTTP_HDR_FIRST) |
254 |
2542887 |
i = HTTP_HDR_FIRST; |
255 |
4842127 |
i += hp->logtag; |
256 |
4842127 |
VSLbt(hp->vsl, (enum VSL_tag_e)i, hp->hd[hdr]); |
257 |
4842127 |
} |
258 |
4842281 |
} |
259 |
|
|
260 |
|
static void |
261 |
36920 |
http_VSLH_del(const struct http *hp, unsigned hdr) |
262 |
|
{ |
263 |
|
int i; |
264 |
|
|
265 |
36920 |
if (hp->vsl != NULL) { |
266 |
|
/* We don't support unsetting stuff in the first line */ |
267 |
36920 |
assert (hdr >= HTTP_HDR_FIRST); |
268 |
36920 |
assert(VXID_TAG(hp->vsl->wid)); |
269 |
36920 |
i = (HTTP_HDR_UNSET - HTTP_HDR_METHOD); |
270 |
36920 |
i += hp->logtag; |
271 |
36920 |
VSLbt(hp->vsl, (enum VSL_tag_e)i, hp->hd[hdr]); |
272 |
36920 |
} |
273 |
36920 |
} |
274 |
|
|
275 |
|
/*--------------------------------------------------------------------*/ |
276 |
|
|
277 |
|
void |
278 |
225821 |
http_VSL_log(const struct http *hp) |
279 |
|
{ |
280 |
|
unsigned u; |
281 |
|
|
282 |
1972809 |
for (u = 0; u < hp->nhd; u++) |
283 |
3042453 |
if (hp->hd[u].b != NULL) |
284 |
1295465 |
http_VSLH(hp, u); |
285 |
225821 |
} |
286 |
|
|
287 |
|
/*--------------------------------------------------------------------*/ |
288 |
|
|
289 |
|
static void |
290 |
4160 |
http_fail(const struct http *hp) |
291 |
|
{ |
292 |
|
char id[WS_ID_SIZE]; |
293 |
|
|
294 |
4160 |
VSC_C_main->losthdr++; |
295 |
4160 |
WS_Id(hp->ws, id); |
296 |
4160 |
VSLb(hp->vsl, SLT_Error, "out of workspace (%s)", id); |
297 |
4160 |
WS_MarkOverflow(hp->ws); |
298 |
4160 |
} |
299 |
|
|
300 |
|
/*-------------------------------------------------------------------- |
301 |
|
* List of canonical HTTP response code names from RFC2616 |
302 |
|
*/ |
303 |
|
|
304 |
|
static struct http_msg { |
305 |
|
unsigned nbr; |
306 |
|
const char *status; |
307 |
|
const char *txt; |
308 |
|
} http_msg[] = { |
309 |
|
#define HTTP_RESP(n, t) { n, #n, t}, |
310 |
|
#include "tbl/http_response.h" |
311 |
|
{ 0, "0", NULL } |
312 |
|
}; |
313 |
|
|
314 |
|
const char * |
315 |
57274 |
http_Status2Reason(unsigned status, const char **sstr) |
316 |
|
{ |
317 |
|
struct http_msg *mp; |
318 |
|
|
319 |
57274 |
status %= 1000; |
320 |
57274 |
assert(status >= 100); |
321 |
1770299 |
for (mp = http_msg; mp->nbr != 0 && mp->nbr <= status; mp++) |
322 |
1768499 |
if (mp->nbr == status) { |
323 |
55474 |
if (sstr) |
324 |
42477 |
*sstr = mp->status; |
325 |
55474 |
return (mp->txt); |
326 |
|
} |
327 |
1800 |
return ("Unknown HTTP Status"); |
328 |
57274 |
} |
329 |
|
|
330 |
|
/*--------------------------------------------------------------------*/ |
331 |
|
|
332 |
|
unsigned |
333 |
206378 |
HTTP_estimate(unsigned nhttp) |
334 |
|
{ |
335 |
|
|
336 |
|
/* XXX: We trust the structs to size-aligned as necessary */ |
337 |
206378 |
return (PRNDUP(sizeof(struct http) + sizeof(txt) * nhttp + nhttp)); |
338 |
|
} |
339 |
|
|
340 |
|
struct http * |
341 |
619147 |
HTTP_create(void *p, uint16_t nhttp, unsigned len) |
342 |
|
{ |
343 |
|
struct http *hp; |
344 |
|
|
345 |
619147 |
hp = p; |
346 |
619147 |
hp->magic = HTTP_MAGIC; |
347 |
619147 |
hp->hd = (void*)(hp + 1); |
348 |
619147 |
hp->shd = nhttp; |
349 |
619147 |
hp->hdf = (void*)(hp->hd + nhttp); |
350 |
619147 |
assert((unsigned char*)p + len == hp->hdf + PRNDUP(nhttp)); |
351 |
619147 |
return (hp); |
352 |
|
} |
353 |
|
|
354 |
|
/*--------------------------------------------------------------------*/ |
355 |
|
|
356 |
|
void |
357 |
577366 |
HTTP_Setup(struct http *hp, struct ws *ws, struct vsl_log *vsl, |
358 |
|
enum VSL_tag_e whence) |
359 |
|
{ |
360 |
577366 |
http_Teardown(hp); |
361 |
577366 |
hp->nhd = HTTP_HDR_FIRST; |
362 |
577366 |
hp->logtag = whence; |
363 |
577366 |
hp->ws = ws; |
364 |
577366 |
hp->vsl = vsl; |
365 |
577366 |
} |
366 |
|
|
367 |
|
/*-------------------------------------------------------------------- |
368 |
|
* http_Teardown() is a safety feature, we use it to zap all http |
369 |
|
* structs once we're done with them, to minimize the risk that |
370 |
|
* old stale pointers exist to no longer valid stuff. |
371 |
|
*/ |
372 |
|
|
373 |
|
void |
374 |
901508 |
http_Teardown(struct http *hp) |
375 |
|
{ |
376 |
|
|
377 |
901508 |
CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC); |
378 |
901508 |
AN(hp->shd); |
379 |
901508 |
memset(&hp->nhd, 0, sizeof *hp - offsetof(struct http, nhd)); |
380 |
901508 |
memset(hp->hd, 0, sizeof *hp->hd * hp->shd); |
381 |
901508 |
memset(hp->hdf, 0, sizeof *hp->hdf * hp->shd); |
382 |
901508 |
} |
383 |
|
|
384 |
|
/*-------------------------------------------------------------------- |
385 |
|
* Duplicate the http content into another http |
386 |
|
* We cannot just memcpy the struct because the hd & hdf are private |
387 |
|
* storage to the struct http. |
388 |
|
*/ |
389 |
|
|
390 |
|
void |
391 |
253920 |
HTTP_Dup(struct http *to, const struct http * fm) |
392 |
|
{ |
393 |
|
|
394 |
253920 |
assert(fm->nhd <= to->shd); |
395 |
253920 |
memcpy(to->hd, fm->hd, fm->nhd * sizeof *to->hd); |
396 |
253920 |
memcpy(to->hdf, fm->hdf, fm->nhd * sizeof *to->hdf); |
397 |
253920 |
to->nhd = fm->nhd; |
398 |
253920 |
to->logtag = fm->logtag; |
399 |
253920 |
to->status = fm->status; |
400 |
253920 |
to->protover = fm->protover; |
401 |
253920 |
} |
402 |
|
|
403 |
|
|
404 |
|
/*-------------------------------------------------------------------- |
405 |
|
* Clone the entire http structure, including vsl & ws |
406 |
|
*/ |
407 |
|
|
408 |
|
void |
409 |
239283 |
HTTP_Clone(struct http *to, const struct http * const fm) |
410 |
|
{ |
411 |
|
|
412 |
239283 |
HTTP_Dup(to, fm); |
413 |
239283 |
to->vsl = fm->vsl; |
414 |
239283 |
to->ws = fm->ws; |
415 |
239283 |
} |
416 |
|
|
417 |
|
/*--------------------------------------------------------------------*/ |
418 |
|
|
419 |
|
void |
420 |
258239 |
http_Proto(struct http *to) |
421 |
|
{ |
422 |
|
const char *fm; |
423 |
|
|
424 |
258239 |
fm = to->hd[HTTP_HDR_PROTO].b; |
425 |
|
|
426 |
516118 |
if (fm != NULL && |
427 |
257920 |
(fm[0] == 'H' || fm[0] == 'h') && |
428 |
257886 |
(fm[1] == 'T' || fm[1] == 't') && |
429 |
257884 |
(fm[2] == 'T' || fm[2] == 't') && |
430 |
257884 |
(fm[3] == 'P' || fm[3] == 'p') && |
431 |
257884 |
fm[4] == '/' && |
432 |
257884 |
vct_isdigit(fm[5]) && |
433 |
257882 |
fm[6] == '.' && |
434 |
257882 |
vct_isdigit(fm[7]) && |
435 |
257879 |
fm[8] == '\0') { |
436 |
257879 |
to->protover = 10 * (fm[5] - '0') + (fm[7] - '0'); |
437 |
257879 |
} else { |
438 |
360 |
to->protover = 0; |
439 |
|
} |
440 |
258239 |
} |
441 |
|
|
442 |
|
/*--------------------------------------------------------------------*/ |
443 |
|
|
444 |
|
void |
445 |
1531451 |
http_SetH(struct http *to, unsigned n, const char *header) |
446 |
|
{ |
447 |
|
|
448 |
1531451 |
assert(n < to->nhd); |
449 |
1531451 |
AN(header); |
450 |
1531451 |
to->hd[n].b = TRUST_ME(header); |
451 |
1531451 |
to->hd[n].e = strchr(to->hd[n].b, '\0'); |
452 |
1531451 |
to->hdf[n] = 0; |
453 |
1531451 |
http_VSLH(to, n); |
454 |
1531451 |
if (n == HTTP_HDR_PROTO) |
455 |
52356 |
http_Proto(to); |
456 |
1531451 |
} |
457 |
|
|
458 |
|
/*--------------------------------------------------------------------*/ |
459 |
|
|
460 |
|
static void |
461 |
1440 |
http_PutField(struct http *to, int field, const char *string) |
462 |
|
{ |
463 |
|
const char *p; |
464 |
|
|
465 |
1440 |
CHECK_OBJ_NOTNULL(to, HTTP_MAGIC); |
466 |
1440 |
p = WS_Copy(to->ws, string, -1); |
467 |
1440 |
if (p == NULL) { |
468 |
40 |
http_fail(to); |
469 |
40 |
VSLbs(to->vsl, SLT_LostHeader, TOSTRAND(string)); |
470 |
40 |
return; |
471 |
|
} |
472 |
1400 |
http_SetH(to, field, p); |
473 |
1440 |
} |
474 |
|
|
475 |
|
/*--------------------------------------------------------------------*/ |
476 |
|
|
477 |
|
int |
478 |
4567717 |
http_IsHdr(const txt *hh, hdr_t hdr) |
479 |
|
{ |
480 |
|
unsigned l; |
481 |
|
|
482 |
4567717 |
Tcheck(*hh); |
483 |
4567717 |
AN(hdr); |
484 |
4567717 |
l = hdr[0]; |
485 |
4567717 |
assert(l == strlen(hdr + 1)); |
486 |
4567717 |
assert(hdr[l] == ':'); |
487 |
4567717 |
hdr++; |
488 |
4567717 |
return (http_hdr_at(hdr, hh->b, l)); |
489 |
|
} |
490 |
|
|
491 |
|
/*--------------------------------------------------------------------*/ |
492 |
|
|
493 |
|
static unsigned |
494 |
5835819 |
http_findhdr(const struct http *hp, unsigned l, const char *hdr) |
495 |
|
{ |
496 |
|
unsigned u; |
497 |
|
|
498 |
25185552 |
for (u = HTTP_HDR_FIRST; u < hp->nhd; u++) { |
499 |
20632943 |
Tcheck(hp->hd[u]); |
500 |
20632943 |
if (hp->hd[u].e < hp->hd[u].b + l + 1) |
501 |
3772108 |
continue; |
502 |
16860835 |
if (hp->hd[u].b[l] != ':') |
503 |
14186457 |
continue; |
504 |
2674378 |
if (!http_hdr_at(hdr, hp->hd[u].b, l)) |
505 |
1391168 |
continue; |
506 |
1283210 |
return (u); |
507 |
|
} |
508 |
4552609 |
return (0); |
509 |
5835819 |
} |
510 |
|
|
511 |
|
/*-------------------------------------------------------------------- |
512 |
|
* Count how many instances we have of this header |
513 |
|
*/ |
514 |
|
|
515 |
|
unsigned |
516 |
291871 |
http_CountHdr(const struct http *hp, hdr_t hdr) |
517 |
|
{ |
518 |
291871 |
unsigned retval = 0; |
519 |
|
unsigned u; |
520 |
|
|
521 |
291871 |
CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC); |
522 |
|
|
523 |
974135 |
for (u = HTTP_HDR_FIRST; u < hp->nhd; u++) { |
524 |
682264 |
Tcheck(hp->hd[u]); |
525 |
682264 |
if (http_IsHdr(&hp->hd[u], hdr)) |
526 |
144986 |
retval++; |
527 |
682264 |
} |
528 |
291871 |
return (retval); |
529 |
|
} |
530 |
|
|
531 |
|
/*-------------------------------------------------------------------- |
532 |
|
* This function collapses multiple header lines of the same name. |
533 |
|
* The lines are joined with a comma, according to [rfc2616, 4.2bot, p32] |
534 |
|
*/ |
535 |
|
|
536 |
|
void |
537 |
941056 |
http_CollectHdr(struct http *hp, hdr_t hdr) |
538 |
|
{ |
539 |
|
|
540 |
941056 |
http_CollectHdrSep(hp, hdr, NULL); |
541 |
941056 |
} |
542 |
|
|
543 |
|
/*-------------------------------------------------------------------- |
544 |
|
* You may prefer to collapse header fields using a different separator. |
545 |
|
* For Cookie headers, the separator is "; " for example. That's probably |
546 |
|
* the only example too. |
547 |
|
*/ |
548 |
|
|
549 |
|
void |
550 |
946136 |
http_CollectHdrSep(struct http *hp, hdr_t hdr, const char *sep) |
551 |
|
{ |
552 |
|
unsigned u, l, lsep, ml, f, x, d; |
553 |
946136 |
char *b = NULL, *e = NULL; |
554 |
|
const char *v; |
555 |
|
|
556 |
946136 |
CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC); |
557 |
946136 |
if (WS_Overflowed(hp->ws)) |
558 |
800 |
return; |
559 |
|
|
560 |
945336 |
if (sep == NULL || *sep == '\0') |
561 |
940263 |
sep = ", "; |
562 |
945348 |
lsep = strlen(sep); |
563 |
|
|
564 |
945348 |
l = hdr[0]; |
565 |
945348 |
assert(l == strlen(hdr + 1)); |
566 |
945348 |
assert(hdr[l] == ':'); |
567 |
945348 |
f = http_findhdr(hp, l - 1, hdr + 1); |
568 |
945348 |
if (f == 0) |
569 |
929285 |
return; |
570 |
|
|
571 |
59021 |
for (d = u = f + 1; u < hp->nhd; u++) { |
572 |
42958 |
Tcheck(hp->hd[u]); |
573 |
42958 |
if (!http_IsHdr(&hp->hd[u], hdr)) { |
574 |
42238 |
if (d != u) { |
575 |
2840 |
hp->hd[d] = hp->hd[u]; |
576 |
2840 |
hp->hdf[d] = hp->hdf[u]; |
577 |
2840 |
} |
578 |
42238 |
d++; |
579 |
42238 |
continue; |
580 |
|
} |
581 |
720 |
if (b == NULL) { |
582 |
|
/* Found second header, start our collection */ |
583 |
640 |
ml = WS_ReserveAll(hp->ws); |
584 |
640 |
b = WS_Reservation(hp->ws); |
585 |
640 |
e = b + ml; |
586 |
640 |
x = Tlen(hp->hd[f]); |
587 |
640 |
if (b + x >= e) { |
588 |
0 |
http_fail(hp); |
589 |
0 |
VSLbs(hp->vsl, SLT_LostHeader, |
590 |
0 |
TOSTRAND(hdr + 1)); |
591 |
0 |
WS_Release(hp->ws, 0); |
592 |
0 |
return; |
593 |
|
} |
594 |
640 |
memcpy(b, hp->hd[f].b, x); |
595 |
640 |
b += x; |
596 |
640 |
} |
597 |
|
|
598 |
720 |
AN(b); |
599 |
720 |
AN(e); |
600 |
|
|
601 |
|
/* Append the Nth header we found */ |
602 |
720 |
x = Tlen(hp->hd[u]) - l; |
603 |
|
|
604 |
720 |
v = hp->hd[u].b + *hdr; |
605 |
1440 |
while (vct_issp(*v)) { |
606 |
720 |
v++; |
607 |
720 |
x--; |
608 |
|
} |
609 |
|
|
610 |
720 |
if (b + lsep + x >= e) { |
611 |
0 |
http_fail(hp); |
612 |
0 |
VSLbs(hp->vsl, SLT_LostHeader, TOSTRAND(hdr + 1)); |
613 |
0 |
WS_Release(hp->ws, 0); |
614 |
0 |
return; |
615 |
|
} |
616 |
720 |
memcpy(b, sep, lsep); |
617 |
720 |
b += lsep; |
618 |
720 |
memcpy(b, v, x); |
619 |
720 |
b += x; |
620 |
720 |
} |
621 |
16063 |
if (b == NULL) |
622 |
15423 |
return; |
623 |
640 |
hp->nhd = (uint16_t)d; |
624 |
640 |
AN(e); |
625 |
640 |
*b = '\0'; |
626 |
640 |
hp->hd[f].b = WS_Reservation(hp->ws); |
627 |
640 |
hp->hd[f].e = b; |
628 |
640 |
WS_ReleaseP(hp->ws, b + 1); |
629 |
946148 |
} |
630 |
|
|
631 |
|
/*--------------------------------------------------------------------*/ |
632 |
|
|
633 |
|
int |
634 |
4885608 |
http_GetHdr(const struct http *hp, hdr_t hdr, const char **ptr) |
635 |
|
{ |
636 |
|
unsigned u, l; |
637 |
|
const char *p; |
638 |
|
|
639 |
4885608 |
l = hdr[0]; |
640 |
4885608 |
assert(l == strlen(hdr + 1)); |
641 |
4885608 |
assert(hdr[l] == ':'); |
642 |
4885608 |
hdr++; |
643 |
4885608 |
u = http_findhdr(hp, l - 1, hdr); |
644 |
4885608 |
if (u == 0) { |
645 |
3621556 |
if (ptr != NULL) |
646 |
3256608 |
*ptr = NULL; |
647 |
3621556 |
return (0); |
648 |
|
} |
649 |
1264052 |
if (ptr != NULL) { |
650 |
1033749 |
p = hp->hd[u].b + l; |
651 |
2065750 |
while (vct_issp(*p)) |
652 |
1032001 |
p++; |
653 |
1033749 |
*ptr = p; |
654 |
1033749 |
} |
655 |
1264052 |
return (1); |
656 |
4885608 |
} |
657 |
|
|
658 |
|
/*----------------------------------------------------------------------------- |
659 |
|
* Split source string at any of the separators, return pointer to first |
660 |
|
* and last+1 char of substrings, with whitespace trimmed at both ends. |
661 |
|
* If sep being an empty string is shorthand for VCT::SP |
662 |
|
* If stop is NULL, src is NUL terminated. |
663 |
|
*/ |
664 |
|
|
665 |
|
static int |
666 |
90930 |
http_split(const char **src, const char *stop, const char *sep, |
667 |
|
const char **b, const char **e) |
668 |
|
{ |
669 |
|
const char *p, *q; |
670 |
|
|
671 |
90930 |
AN(src); |
672 |
90930 |
AN(*src); |
673 |
90930 |
AN(sep); |
674 |
90930 |
AN(b); |
675 |
90930 |
AN(e); |
676 |
|
|
677 |
90930 |
if (stop == NULL) |
678 |
90649 |
stop = strchr(*src, '\0'); |
679 |
|
|
680 |
156275 |
for (p = *src; p < stop && (vct_issp(*p) || strchr(sep, *p)); p++) |
681 |
3480 |
continue; |
682 |
|
|
683 |
90930 |
if (p >= stop) { |
684 |
32545 |
*b = NULL; |
685 |
32545 |
*e = NULL; |
686 |
32545 |
return (0); |
687 |
|
} |
688 |
|
|
689 |
58385 |
*b = p; |
690 |
58385 |
if (*sep == '\0') { |
691 |
0 |
for (q = p + 1; q < stop && !vct_issp(*q); q++) |
692 |
0 |
continue; |
693 |
0 |
*e = q; |
694 |
0 |
*src = q; |
695 |
0 |
return (1); |
696 |
|
} |
697 |
287282 |
for (q = p + 1; q < stop && !strchr(sep, *q); q++) |
698 |
228897 |
continue; |
699 |
58385 |
*src = q; |
700 |
58385 |
while (q > p && vct_issp(q[-1])) |
701 |
0 |
q--; |
702 |
58383 |
*e = q; |
703 |
58383 |
return (1); |
704 |
90928 |
} |
705 |
|
|
706 |
|
/*----------------------------------------------------------------------------- |
707 |
|
* Comparison rule for tokens: |
708 |
|
* if target string starts with '"', we use memcmp() and expect closing |
709 |
|
* double quote as well |
710 |
|
* otherwise we use http_tok_at() |
711 |
|
* |
712 |
|
* On match we increment *bp past the token name. |
713 |
|
*/ |
714 |
|
|
715 |
|
static int |
716 |
50919 |
http_istoken(const char **bp, const char *e, const char *token) |
717 |
|
{ |
718 |
50919 |
int fl = strlen(token); |
719 |
|
const char *b; |
720 |
|
|
721 |
50919 |
AN(bp); |
722 |
50919 |
AN(e); |
723 |
50919 |
AN(token); |
724 |
|
|
725 |
50919 |
b = *bp; |
726 |
|
|
727 |
50919 |
if (b + fl + 2 <= e && *b == '"' && |
728 |
0 |
!memcmp(b + 1, token, fl) && b[fl + 1] == '"') { |
729 |
0 |
*bp += fl + 2; |
730 |
0 |
return (1); |
731 |
|
} |
732 |
52519 |
if (b + fl <= e && http_tok_at(b, token, fl) && |
733 |
23840 |
(b + fl == e || !vct_istchar(b[fl]))) { |
734 |
23840 |
*bp += fl; |
735 |
23840 |
return (1); |
736 |
|
} |
737 |
27079 |
return (0); |
738 |
50919 |
} |
739 |
|
|
740 |
|
/*----------------------------------------------------------------------------- |
741 |
|
* Find a given data element (token) in a header according to RFC2616's #rule |
742 |
|
* (section 2.1, p15) |
743 |
|
* |
744 |
|
* On case sensitivity: |
745 |
|
* |
746 |
|
* Section 4.2 (Messages Headers) defines field (header) name as case |
747 |
|
* insensitive, but the field (header) value/content may be case-sensitive. |
748 |
|
* |
749 |
|
* http_GetHdrToken looks up a token in a header value and the rfc does not say |
750 |
|
* explicitly if tokens are to be compared with or without respect to case. |
751 |
|
* |
752 |
|
* But all examples and specific statements regarding tokens follow the rule |
753 |
|
* that unquoted tokens are to be matched case-insensitively and quoted tokens |
754 |
|
* case-sensitively. |
755 |
|
* |
756 |
|
* The optional pb and pe arguments will point to the token content start and |
757 |
|
* end+1, white space trimmed on both sides. |
758 |
|
*/ |
759 |
|
|
760 |
|
int |
761 |
569855 |
http_GetHdrToken(const struct http *hp, hdr_t hdr, |
762 |
|
const char *token, const char **pb, const char **pe) |
763 |
|
{ |
764 |
|
const char *h, *b, *e; |
765 |
|
|
766 |
569855 |
if (pb != NULL) |
767 |
432914 |
*pb = NULL; |
768 |
569855 |
if (pe != NULL) |
769 |
132009 |
*pe = NULL; |
770 |
569855 |
if (!http_GetHdr(hp, hdr, &h)) |
771 |
520415 |
return (0); |
772 |
49440 |
AN(h); |
773 |
|
|
774 |
76520 |
while (http_split(&h, NULL, ",", &b, &e)) |
775 |
50920 |
if (http_istoken(&b, e, token)) |
776 |
23840 |
break; |
777 |
49440 |
if (b == NULL) |
778 |
25600 |
return (0); |
779 |
23840 |
if (pb != NULL) { |
780 |
23680 |
for (; vct_islws(*b); b++) |
781 |
200 |
continue; |
782 |
23480 |
if (b == e) { |
783 |
21920 |
b = NULL; |
784 |
21920 |
e = NULL; |
785 |
21920 |
} |
786 |
23480 |
*pb = b; |
787 |
23480 |
if (pe != NULL) |
788 |
21640 |
*pe = e; |
789 |
23480 |
} |
790 |
23840 |
return (1); |
791 |
569855 |
} |
792 |
|
|
793 |
|
/*-------------------------------------------------------------------- |
794 |
|
* Find a given header field's quality value (qvalue). |
795 |
|
*/ |
796 |
|
|
797 |
|
double |
798 |
132010 |
http_GetHdrQ(const struct http *hp, hdr_t hdr, const char *field) |
799 |
|
{ |
800 |
|
const char *hb, *he, *b, *e; |
801 |
|
int i; |
802 |
|
double a, f; |
803 |
|
|
804 |
132010 |
i = http_GetHdrToken(hp, hdr, field, &hb, &he); |
805 |
132010 |
if (!i) |
806 |
110370 |
return (0.); |
807 |
|
|
808 |
21640 |
if (hb == NULL) |
809 |
21360 |
return (1.); |
810 |
280 |
while (http_split(&hb, he, ";", &b, &e)) { |
811 |
280 |
if (*b != 'q') |
812 |
0 |
continue; |
813 |
280 |
for (b++; b < e && vct_issp(*b); b++) |
814 |
0 |
continue; |
815 |
280 |
if (b == e || *b != '=') |
816 |
0 |
continue; |
817 |
280 |
break; |
818 |
|
} |
819 |
280 |
if (b == NULL) |
820 |
0 |
return (1.); |
821 |
280 |
for (b++; b < e && vct_issp(*b); b++) |
822 |
0 |
continue; |
823 |
280 |
if (b == e || (*b != '.' && !vct_isdigit(*b))) |
824 |
40 |
return (0.); |
825 |
240 |
a = 0; |
826 |
480 |
while (b < e && vct_isdigit(*b)) { |
827 |
240 |
a *= 10.; |
828 |
240 |
a += *b - '0'; |
829 |
240 |
b++; |
830 |
|
} |
831 |
240 |
if (b == e || *b++ != '.') |
832 |
40 |
return (a); |
833 |
200 |
f = .1; |
834 |
640 |
while (b < e && vct_isdigit(*b)) { |
835 |
440 |
a += f * (*b - '0'); |
836 |
440 |
f *= .1; |
837 |
440 |
b++; |
838 |
|
} |
839 |
200 |
return (a); |
840 |
132010 |
} |
841 |
|
|
842 |
|
/*-------------------------------------------------------------------- |
843 |
|
* Find a given header field's value. |
844 |
|
*/ |
845 |
|
|
846 |
|
int |
847 |
300920 |
http_GetHdrField(const struct http *hp, hdr_t hdr, |
848 |
|
const char *field, const char **ptr) |
849 |
|
{ |
850 |
|
const char *h; |
851 |
|
int i; |
852 |
|
|
853 |
300920 |
if (ptr != NULL) |
854 |
152716 |
*ptr = NULL; |
855 |
|
|
856 |
300920 |
h = NULL; |
857 |
300920 |
i = http_GetHdrToken(hp, hdr, field, &h, NULL); |
858 |
300920 |
if (!i) |
859 |
299080 |
return (i); |
860 |
|
|
861 |
1840 |
if (ptr != NULL && h != NULL) { |
862 |
|
/* Skip whitespace, looking for '=' */ |
863 |
1280 |
while (*h && vct_issp(*h)) |
864 |
0 |
h++; |
865 |
1280 |
if (*h == '=') { |
866 |
1280 |
h++; |
867 |
1440 |
while (*h && vct_issp(*h)) |
868 |
160 |
h++; |
869 |
1280 |
*ptr = h; |
870 |
1280 |
} |
871 |
1280 |
} |
872 |
1840 |
return (i); |
873 |
300920 |
} |
874 |
|
|
875 |
|
/*--------------------------------------------------------------------*/ |
876 |
|
|
877 |
|
ssize_t |
878 |
431573 |
http_GetContentLength(const struct http *hp) |
879 |
|
{ |
880 |
|
ssize_t cl; |
881 |
|
const char *b; |
882 |
|
|
883 |
431573 |
CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC); |
884 |
|
|
885 |
431573 |
if (!http_GetHdr(hp, H_Content_Length, &b)) |
886 |
169249 |
return (-1); |
887 |
262324 |
cl = VNUM_uint(b, NULL, &b); |
888 |
262324 |
if (cl < 0) |
889 |
160 |
return (-2); |
890 |
262164 |
while (vct_islws(*b)) |
891 |
0 |
b++; |
892 |
262164 |
if (*b != '\0') |
893 |
0 |
return (-2); |
894 |
262164 |
return (cl); |
895 |
431573 |
} |
896 |
|
|
897 |
|
ssize_t |
898 |
78000 |
http_GetContentRange(const struct http *hp, ssize_t *lo, ssize_t *hi) |
899 |
|
{ |
900 |
|
ssize_t tmp, cl; |
901 |
|
const char *b, *t; |
902 |
|
|
903 |
78000 |
CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC); |
904 |
|
|
905 |
78000 |
if (lo == NULL) |
906 |
0 |
lo = &tmp; |
907 |
78000 |
if (hi == NULL) |
908 |
0 |
hi = &tmp; |
909 |
|
|
910 |
78000 |
*lo = *hi = -1; |
911 |
|
|
912 |
78000 |
if (!http_GetHdr(hp, H_Content_Range, &b)) |
913 |
77680 |
return (-1); |
914 |
|
|
915 |
320 |
t = strchr(b, ' '); |
916 |
320 |
if (t == NULL) |
917 |
40 |
return (-2); // Missing space after range unit |
918 |
|
|
919 |
280 |
if (!http_range_at(b, bytes, t - b)) |
920 |
0 |
return (-1); // Unknown range unit, ignore |
921 |
280 |
b = t + 1; |
922 |
|
|
923 |
280 |
if (*b == '*') { // Content-Range: bytes */123 |
924 |
120 |
*lo = *hi = -1; |
925 |
120 |
b++; |
926 |
120 |
} else { // Content-Range: bytes 1-2/3 |
927 |
160 |
*lo = VNUM_uint(b, NULL, &b); |
928 |
160 |
if (*lo < 0) |
929 |
0 |
return (-2); |
930 |
160 |
if (*b != '-') |
931 |
0 |
return (-2); |
932 |
160 |
*hi = VNUM_uint(b + 1, NULL, &b); |
933 |
160 |
if (*hi < 0) |
934 |
0 |
return (-2); |
935 |
|
} |
936 |
280 |
if (*b != '/') |
937 |
0 |
return (-2); |
938 |
280 |
if (b[1] == '*') { // Content-Range: bytes 1-2/* |
939 |
40 |
cl = -1; |
940 |
40 |
b += 2; |
941 |
40 |
} else { |
942 |
240 |
cl = VNUM_uint(b + 1, NULL, &b); |
943 |
240 |
if (cl <= 0) |
944 |
0 |
return (-2); |
945 |
|
} |
946 |
280 |
while (vct_islws(*b)) |
947 |
0 |
b++; |
948 |
280 |
if (*b != '\0') |
949 |
0 |
return (-2); |
950 |
280 |
if (*lo > *hi) |
951 |
0 |
return (-2); |
952 |
280 |
assert(cl >= -1); |
953 |
280 |
if (*lo >= cl || *hi >= cl) |
954 |
40 |
return (-2); |
955 |
240 |
AN(cl); |
956 |
240 |
return (cl); |
957 |
78000 |
} |
958 |
|
|
959 |
|
const char * |
960 |
79879 |
http_GetRange(const struct http *hp, ssize_t *lo, ssize_t *hi, ssize_t len) |
961 |
|
{ |
962 |
|
ssize_t tmp_lo, tmp_hi; |
963 |
|
const char *b, *t; |
964 |
|
|
965 |
79879 |
CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC); |
966 |
|
|
967 |
79879 |
if (lo == NULL) |
968 |
0 |
lo = &tmp_lo; |
969 |
79879 |
if (hi == NULL) |
970 |
0 |
hi = &tmp_hi; |
971 |
|
|
972 |
79879 |
*lo = *hi = -1; |
973 |
|
|
974 |
79879 |
if (!http_GetHdr(hp, H_Range, &b)) |
975 |
77799 |
return (NULL); |
976 |
|
|
977 |
2080 |
t = strchr(b, '='); |
978 |
2080 |
if (t == NULL) |
979 |
80 |
return ("Missing '='"); |
980 |
|
|
981 |
2000 |
if (!http_range_at(b, bytes, t - b)) |
982 |
120 |
return ("Not Bytes"); |
983 |
1880 |
b = t + 1; |
984 |
|
|
985 |
1880 |
*lo = VNUM_uint(b, NULL, &b); |
986 |
1880 |
if (*lo == -2) |
987 |
0 |
return ("Low number too big"); |
988 |
1880 |
if (*b++ != '-') |
989 |
0 |
return ("Missing hyphen"); |
990 |
|
|
991 |
1880 |
*hi = VNUM_uint(b, NULL, &b); |
992 |
1880 |
if (*hi == -2) |
993 |
0 |
return ("High number too big"); |
994 |
1880 |
if (*lo == -1 && *hi == -1) |
995 |
40 |
return ("Neither high nor low"); |
996 |
1840 |
if (*lo == -1 && *hi == 0) |
997 |
40 |
return ("No low, high is zero"); |
998 |
1800 |
if (*hi >= 0 && *hi < *lo) |
999 |
40 |
return ("high smaller than low"); |
1000 |
|
|
1001 |
1800 |
while (vct_islws(*b)) |
1002 |
40 |
b++; |
1003 |
1760 |
if (*b != '\0') |
1004 |
40 |
return ("Trailing stuff"); |
1005 |
|
|
1006 |
1720 |
assert(*lo >= -1); |
1007 |
1720 |
assert(*hi >= -1); |
1008 |
|
|
1009 |
1720 |
if (len <= 0) |
1010 |
640 |
return (NULL); // Allow 200 response |
1011 |
|
|
1012 |
1080 |
if (*lo < 0) { |
1013 |
120 |
assert(*hi > 0); |
1014 |
120 |
*lo = len - *hi; |
1015 |
120 |
if (*lo < 0) |
1016 |
40 |
*lo = 0; |
1017 |
120 |
*hi = len - 1; |
1018 |
1080 |
} else if (len >= 0 && (*hi >= len || *hi < 0)) { |
1019 |
320 |
*hi = len - 1; |
1020 |
320 |
} |
1021 |
|
|
1022 |
1080 |
if (*lo >= len) |
1023 |
40 |
return ("low range beyond object"); |
1024 |
|
|
1025 |
1040 |
return (NULL); |
1026 |
79879 |
} |
1027 |
|
|
1028 |
|
/*-------------------------------------------------------------------- |
1029 |
|
*/ |
1030 |
|
|
1031 |
|
stream_close_t |
1032 |
226448 |
http_DoConnection(struct http *hp, stream_close_t sc_close) |
1033 |
|
{ |
1034 |
|
const char *h, *b, *e; |
1035 |
|
stream_close_t retval; |
1036 |
|
unsigned u, v; |
1037 |
|
struct http_hdrflg *f; |
1038 |
|
|
1039 |
226448 |
CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC); |
1040 |
226448 |
assert(sc_close == SC_REQ_CLOSE || sc_close == SC_RESP_CLOSE); |
1041 |
|
|
1042 |
226448 |
if (hp->protover == 10) |
1043 |
1545 |
retval = SC_REQ_HTTP10; |
1044 |
|
else |
1045 |
224903 |
retval = SC_NULL; |
1046 |
|
|
1047 |
226448 |
http_CollectHdr(hp, H_Connection); |
1048 |
226448 |
if (!http_GetHdr(hp, H_Connection, &h)) |
1049 |
219383 |
return (retval); |
1050 |
7065 |
AN(h); |
1051 |
14129 |
while (http_split(&h, NULL, ",", &b, &e)) { |
1052 |
7184 |
u = pdiff(b, e); |
1053 |
7184 |
if (u == 5 && http_hdr_at(b, "close", u)) |
1054 |
5785 |
retval = sc_close; |
1055 |
7184 |
if (u == 10 && http_hdr_at(b, "keep-alive", u)) |
1056 |
920 |
retval = SC_NULL; |
1057 |
|
|
1058 |
|
/* Refuse removal of well-known-headers if they would pass. */ |
1059 |
7184 |
f = http_hdr_flags(b, e); |
1060 |
7184 |
if (f != NULL && !(f->flag & HTTPH_R_PASS)) |
1061 |
120 |
return (SC_RX_BAD); |
1062 |
|
|
1063 |
34307 |
for (v = HTTP_HDR_FIRST; v < hp->nhd; v++) { |
1064 |
27243 |
Tcheck(hp->hd[v]); |
1065 |
27243 |
if (hp->hd[v].e < hp->hd[v].b + u + 1) |
1066 |
1240 |
continue; |
1067 |
26003 |
if (hp->hd[v].b[u] != ':') |
1068 |
24003 |
continue; |
1069 |
2000 |
if (!http_hdr_at(b, hp->hd[v].b, u)) |
1070 |
1520 |
continue; |
1071 |
480 |
hp->hdf[v] |= HDF_FILTER; |
1072 |
480 |
} |
1073 |
|
} |
1074 |
6945 |
CHECK_OBJ_NOTNULL(retval, STREAM_CLOSE_MAGIC); |
1075 |
6945 |
return (retval); |
1076 |
226448 |
} |
1077 |
|
|
1078 |
|
/*--------------------------------------------------------------------*/ |
1079 |
|
|
1080 |
|
int |
1081 |
430359 |
http_HdrIs(const struct http *hp, hdr_t hdr, const char *val) |
1082 |
|
{ |
1083 |
|
const char *p; |
1084 |
|
|
1085 |
430359 |
if (!http_GetHdr(hp, hdr, &p)) |
1086 |
407359 |
return (0); |
1087 |
23000 |
AN(p); |
1088 |
23000 |
if (http_tok_eq(p, val)) |
1089 |
21960 |
return (1); |
1090 |
1040 |
return (0); |
1091 |
430359 |
} |
1092 |
|
|
1093 |
|
/*--------------------------------------------------------------------*/ |
1094 |
|
|
1095 |
|
uint16_t |
1096 |
557127 |
http_GetStatus(const struct http *hp) |
1097 |
|
{ |
1098 |
|
|
1099 |
557127 |
CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC); |
1100 |
557127 |
return (hp->status); |
1101 |
|
} |
1102 |
|
|
1103 |
|
int |
1104 |
389114 |
http_IsStatus(const struct http *hp, int val) |
1105 |
|
{ |
1106 |
|
|
1107 |
389114 |
CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC); |
1108 |
389114 |
assert(val >= 100 && val <= 999); |
1109 |
389114 |
return (val == (hp->status % 1000)); |
1110 |
|
} |
1111 |
|
|
1112 |
|
/*-------------------------------------------------------------------- |
1113 |
|
* Setting the status will also set the Reason appropriately |
1114 |
|
*/ |
1115 |
|
|
1116 |
|
void |
1117 |
43918 |
http_SetStatus(struct http *to, uint16_t status, const char *reason) |
1118 |
|
{ |
1119 |
|
char buf[4]; |
1120 |
43918 |
const char *sstr = NULL; |
1121 |
|
|
1122 |
43918 |
CHECK_OBJ_NOTNULL(to, HTTP_MAGIC); |
1123 |
|
/* |
1124 |
|
* We allow people to use top digits for internal VCL |
1125 |
|
* signalling, but strip them from the ASCII version. |
1126 |
|
*/ |
1127 |
43918 |
to->status = status; |
1128 |
43918 |
status %= 1000; |
1129 |
43918 |
assert(status >= 100); |
1130 |
|
|
1131 |
43918 |
if (reason == NULL) |
1132 |
8160 |
reason = http_Status2Reason(status, &sstr); |
1133 |
|
else |
1134 |
35758 |
(void)http_Status2Reason(status, &sstr); |
1135 |
|
|
1136 |
43918 |
if (sstr) { |
1137 |
42478 |
http_SetH(to, HTTP_HDR_STATUS, sstr); |
1138 |
42478 |
} else { |
1139 |
1440 |
bprintf(buf, "%03d", status); |
1140 |
1440 |
http_PutField(to, HTTP_HDR_STATUS, buf); |
1141 |
|
} |
1142 |
43918 |
http_SetH(to, HTTP_HDR_REASON, reason); |
1143 |
43918 |
} |
1144 |
|
|
1145 |
|
/*--------------------------------------------------------------------*/ |
1146 |
|
|
1147 |
|
const char * |
1148 |
204168 |
http_GetMethod(const struct http *hp) |
1149 |
|
{ |
1150 |
|
|
1151 |
204168 |
CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC); |
1152 |
204168 |
Tcheck(hp->hd[HTTP_HDR_METHOD]); |
1153 |
204168 |
return (hp->hd[HTTP_HDR_METHOD].b); |
1154 |
|
} |
1155 |
|
|
1156 |
|
/*-------------------------------------------------------------------- |
1157 |
|
* Force a particular header field to a particular value |
1158 |
|
*/ |
1159 |
|
|
1160 |
|
void |
1161 |
300456 |
http_ForceField(struct http *to, unsigned n, const char *t) |
1162 |
|
{ |
1163 |
|
int i; |
1164 |
|
|
1165 |
300456 |
CHECK_OBJ_NOTNULL(to, HTTP_MAGIC); |
1166 |
300456 |
assert(n < HTTP_HDR_FIRST); |
1167 |
300456 |
assert(n == HTTP_HDR_METHOD || n == HTTP_HDR_PROTO); |
1168 |
300456 |
AN(t); |
1169 |
|
|
1170 |
|
/* NB: method names and protocol versions are case-sensitive. */ |
1171 |
300456 |
if (to->hd[n].b == NULL || strcmp(to->hd[n].b, t)) { |
1172 |
4480 |
i = (HTTP_HDR_UNSET - HTTP_HDR_METHOD); |
1173 |
4480 |
i += to->logtag; |
1174 |
|
/* XXX: this is a dead branch */ |
1175 |
4480 |
if (n >= HTTP_HDR_FIRST) |
1176 |
0 |
VSLbt(to->vsl, (enum VSL_tag_e)i, to->hd[n]); |
1177 |
4480 |
http_SetH(to, n, t); |
1178 |
4480 |
} |
1179 |
300456 |
} |
1180 |
|
|
1181 |
|
/*--------------------------------------------------------------------*/ |
1182 |
|
|
1183 |
|
void |
1184 |
40399 |
http_PutResponse(struct http *to, const char *proto, uint16_t status, |
1185 |
|
const char *reason) |
1186 |
|
{ |
1187 |
|
|
1188 |
40399 |
CHECK_OBJ_NOTNULL(to, HTTP_MAGIC); |
1189 |
40399 |
if (proto != NULL) |
1190 |
40399 |
http_SetH(to, HTTP_HDR_PROTO, proto); |
1191 |
40399 |
http_SetStatus(to, status, reason); |
1192 |
40399 |
} |
1193 |
|
|
1194 |
|
/*-------------------------------------------------------------------- |
1195 |
|
* check if header is filtered by the dynamic marker or the static |
1196 |
|
* definitions in http_headers.h |
1197 |
|
*/ |
1198 |
|
|
1199 |
|
static inline int |
1200 |
1544439 |
http_isfiltered(const struct http *fm, unsigned u, unsigned how) |
1201 |
|
{ |
1202 |
|
const char *e; |
1203 |
|
const struct http_hdrflg *f; |
1204 |
|
|
1205 |
1544439 |
if (fm->hdf[u] & HDF_FILTER) |
1206 |
680 |
return (1); |
1207 |
1543759 |
if (u < HTTP_HDR_FIRST) |
1208 |
521110 |
return (0); |
1209 |
1022649 |
e = strchr(fm->hd[u].b, ':'); |
1210 |
1022649 |
if (e == NULL) |
1211 |
0 |
return (0); |
1212 |
1022649 |
f = http_hdr_flags(fm->hd[u].b, e); |
1213 |
1022649 |
return (f != NULL && f->flag & how); |
1214 |
1544439 |
} |
1215 |
|
|
1216 |
|
int |
1217 |
24631 |
http_IsFiltered(const struct http *fm, unsigned u, unsigned how) |
1218 |
|
{ |
1219 |
|
|
1220 |
24631 |
return (http_isfiltered(fm, u, how)); |
1221 |
|
} |
1222 |
|
|
1223 |
|
/*-------------------------------------------------------------------- |
1224 |
|
* Estimate how much workspace we need to Filter this header according |
1225 |
|
* to 'how'. |
1226 |
|
*/ |
1227 |
|
|
1228 |
|
unsigned |
1229 |
86992 |
http_EstimateWS(const struct http *fm, unsigned how) |
1230 |
|
{ |
1231 |
|
unsigned u, l; |
1232 |
|
|
1233 |
86992 |
l = 4; |
1234 |
86992 |
CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC); |
1235 |
830719 |
for (u = 0; u < fm->nhd; u++) { |
1236 |
743727 |
if (u == HTTP_HDR_METHOD || u == HTTP_HDR_URL) |
1237 |
173984 |
continue; |
1238 |
569743 |
Tcheck(fm->hd[u]); |
1239 |
569743 |
if (http_isfiltered(fm, u, how)) |
1240 |
10360 |
continue; |
1241 |
559383 |
l += Tlen(fm->hd[u]) + 1L; |
1242 |
559383 |
} |
1243 |
86992 |
return (PRNDUP(l + 1L)); |
1244 |
|
} |
1245 |
|
|
1246 |
|
/*-------------------------------------------------------------------- |
1247 |
|
* Encode http struct as byte string. |
1248 |
|
* |
1249 |
|
* XXX: We could save considerable special-casing below by encoding also |
1250 |
|
* XXX: H__Status, H__Reason and H__Proto into the string, but it would |
1251 |
|
* XXX: add 26-30 bytes to all encoded objects to save a little code. |
1252 |
|
* XXX: It could possibly be a good idea for later HTTP versions. |
1253 |
|
*/ |
1254 |
|
|
1255 |
|
void |
1256 |
86758 |
HTTP_Encode(const struct http *fm, uint8_t *p0, unsigned l, unsigned how) |
1257 |
|
{ |
1258 |
|
unsigned u, w; |
1259 |
|
uint16_t n; |
1260 |
|
uint8_t *p, *e; |
1261 |
|
|
1262 |
86758 |
AN(p0); |
1263 |
86758 |
AN(l); |
1264 |
86758 |
p = p0; |
1265 |
86758 |
e = p + l; |
1266 |
86758 |
assert(p + 5 <= e); |
1267 |
86758 |
assert(fm->nhd <= fm->shd); |
1268 |
86758 |
n = HTTP_HDR_FIRST - 3; |
1269 |
86758 |
vbe16enc(p + 2, fm->status); |
1270 |
86758 |
p += 4; |
1271 |
86758 |
CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC); |
1272 |
828197 |
for (u = 0; u < fm->nhd; u++) { |
1273 |
741439 |
if (u == HTTP_HDR_METHOD || u == HTTP_HDR_URL) |
1274 |
173516 |
continue; |
1275 |
567923 |
Tcheck(fm->hd[u]); |
1276 |
567923 |
if (http_isfiltered(fm, u, how)) |
1277 |
10357 |
continue; |
1278 |
557566 |
http_VSLH(fm, u); |
1279 |
557566 |
w = Tlen(fm->hd[u]) + 1L; |
1280 |
557566 |
assert(p + w + 1 <= e); |
1281 |
557566 |
memcpy(p, fm->hd[u].b, w); |
1282 |
557566 |
p += w; |
1283 |
557566 |
n++; |
1284 |
557566 |
} |
1285 |
86758 |
*p++ = '\0'; |
1286 |
86758 |
assert(p <= e); |
1287 |
86758 |
vbe16enc(p0, n + 1); |
1288 |
86758 |
} |
1289 |
|
|
1290 |
|
/*-------------------------------------------------------------------- |
1291 |
|
* Decode byte string into http struct |
1292 |
|
*/ |
1293 |
|
|
1294 |
|
int |
1295 |
126144 |
HTTP_Decode(struct http *to, const uint8_t *fm) |
1296 |
|
{ |
1297 |
|
|
1298 |
126144 |
CHECK_OBJ_NOTNULL(to, HTTP_MAGIC); |
1299 |
126144 |
AN(to->vsl); |
1300 |
126144 |
AN(fm); |
1301 |
126144 |
if (vbe16dec(fm) <= to->shd) { |
1302 |
126058 |
to->status = vbe16dec(fm + 2); |
1303 |
126058 |
fm += 4; |
1304 |
1191630 |
for (to->nhd = 0; to->nhd < to->shd; to->nhd++) { |
1305 |
1191630 |
if (to->nhd == HTTP_HDR_METHOD || |
1306 |
1065432 |
to->nhd == HTTP_HDR_URL) { |
1307 |
252100 |
to->hd[to->nhd].b = NULL; |
1308 |
252100 |
to->hd[to->nhd].e = NULL; |
1309 |
252100 |
continue; |
1310 |
|
} |
1311 |
939530 |
if (*fm == '\0') |
1312 |
126058 |
return (0); |
1313 |
813472 |
to->hd[to->nhd].b = (const void*)fm; |
1314 |
813472 |
fm = (const void*)strchr((const void*)fm, '\0'); |
1315 |
813472 |
to->hd[to->nhd].e = (const void*)fm; |
1316 |
813472 |
fm++; |
1317 |
813472 |
http_VSLH(to, to->nhd); |
1318 |
813472 |
} |
1319 |
0 |
} |
1320 |
172 |
VSLb(to->vsl, SLT_Error, |
1321 |
|
"Too many headers to Decode object (%u vs. %u)", |
1322 |
86 |
vbe16dec(fm), to->shd); |
1323 |
86 |
return (-1); |
1324 |
126144 |
} |
1325 |
|
|
1326 |
|
/*--------------------------------------------------------------------*/ |
1327 |
|
|
1328 |
|
uint16_t |
1329 |
40 |
HTTP_GetStatusPack(struct worker *wrk, struct objcore *oc) |
1330 |
|
{ |
1331 |
|
const char *ptr; |
1332 |
40 |
ptr = ObjGetAttr(wrk, oc, OA_HEADERS, NULL); |
1333 |
40 |
AN(ptr); |
1334 |
|
|
1335 |
40 |
return (vbe16dec(ptr + 2)); |
1336 |
|
} |
1337 |
|
|
1338 |
|
/*--------------------------------------------------------------------*/ |
1339 |
|
|
1340 |
|
/* Get the first packed header */ |
1341 |
|
int |
1342 |
28910 |
HTTP_IterHdrPack(struct worker *wrk, struct objcore *oc, const char **p) |
1343 |
|
{ |
1344 |
|
const char *ptr; |
1345 |
|
|
1346 |
28910 |
CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); |
1347 |
28910 |
CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC); |
1348 |
28910 |
AN(p); |
1349 |
|
|
1350 |
28910 |
if (*p == NULL) { |
1351 |
9184 |
ptr = ObjGetAttr(wrk, oc, OA_HEADERS, NULL); |
1352 |
9184 |
AN(ptr); |
1353 |
9184 |
ptr += 4; /* Skip nhd and status */ |
1354 |
9184 |
ptr = strchr(ptr, '\0') + 1; /* Skip :proto: */ |
1355 |
9184 |
ptr = strchr(ptr, '\0') + 1; /* Skip :status: */ |
1356 |
9184 |
ptr = strchr(ptr, '\0') + 1; /* Skip :reason: */ |
1357 |
9184 |
*p = ptr; |
1358 |
9184 |
} else { |
1359 |
19726 |
*p = strchr(*p, '\0') + 1; /* Skip to next header */ |
1360 |
|
} |
1361 |
28910 |
if (**p == '\0') |
1362 |
1760 |
return (0); |
1363 |
27150 |
return (1); |
1364 |
28910 |
} |
1365 |
|
|
1366 |
|
const char * |
1367 |
9425 |
HTTP_GetHdrPack(struct worker *wrk, struct objcore *oc, hdr_t hdr) |
1368 |
|
{ |
1369 |
|
const char *ptr; |
1370 |
|
unsigned l; |
1371 |
|
|
1372 |
9425 |
CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); |
1373 |
9425 |
CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC); |
1374 |
9425 |
AN(hdr); |
1375 |
|
|
1376 |
9425 |
l = hdr[0]; |
1377 |
9425 |
assert(l > 0); |
1378 |
9425 |
assert(l == strlen(hdr + 1)); |
1379 |
9425 |
assert(hdr[l] == ':'); |
1380 |
9425 |
hdr++; |
1381 |
|
|
1382 |
9425 |
if (hdr[0] == ':') { |
1383 |
|
/* Special cases */ |
1384 |
240 |
ptr = ObjGetAttr(wrk, oc, OA_HEADERS, NULL); |
1385 |
240 |
AN(ptr); |
1386 |
240 |
ptr += 4; /* Skip nhd and status */ |
1387 |
|
|
1388 |
|
/* XXX: should we also have h2_hdr_eq() ? */ |
1389 |
240 |
if (!strcmp(hdr, ":proto:")) |
1390 |
40 |
return (ptr); |
1391 |
200 |
ptr = strchr(ptr, '\0') + 1; |
1392 |
200 |
if (!strcmp(hdr, ":status:")) |
1393 |
160 |
return (ptr); |
1394 |
40 |
ptr = strchr(ptr, '\0') + 1; |
1395 |
40 |
if (!strcmp(hdr, ":reason:")) |
1396 |
40 |
return (ptr); |
1397 |
0 |
WRONG("Unknown magic packed header"); |
1398 |
0 |
} |
1399 |
|
|
1400 |
28910 |
HTTP_FOREACH_PACK(wrk, oc, ptr) { |
1401 |
27150 |
if (http_hdr_at(ptr, hdr, l)) { |
1402 |
7425 |
ptr += l; |
1403 |
14810 |
while (vct_islws(*ptr)) |
1404 |
7385 |
ptr++; |
1405 |
7425 |
return (ptr); |
1406 |
|
} |
1407 |
|
} |
1408 |
|
|
1409 |
1760 |
return (NULL); |
1410 |
9425 |
} |
1411 |
|
|
1412 |
|
/*-------------------------------------------------------------------- |
1413 |
|
* Merge any headers in the oc->OA_HEADER into the struct http if they |
1414 |
|
* are not there already. |
1415 |
|
*/ |
1416 |
|
|
1417 |
|
void |
1418 |
1120 |
HTTP_Merge(struct worker *wrk, struct objcore *oc, struct http *to) |
1419 |
|
{ |
1420 |
|
const char *ptr; |
1421 |
|
unsigned u; |
1422 |
|
const char *p; |
1423 |
|
unsigned nhd_before_merge; |
1424 |
|
|
1425 |
1120 |
CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); |
1426 |
1120 |
CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC); |
1427 |
1120 |
CHECK_OBJ_NOTNULL(to, HTTP_MAGIC); |
1428 |
|
|
1429 |
1120 |
ptr = ObjGetAttr(wrk, oc, OA_HEADERS, NULL); |
1430 |
1120 |
AN(ptr); |
1431 |
|
|
1432 |
1120 |
to->status = vbe16dec(ptr + 2); |
1433 |
1120 |
ptr += 4; |
1434 |
|
|
1435 |
6720 |
for (u = 0; u < HTTP_HDR_FIRST; u++) { |
1436 |
5600 |
if (u == HTTP_HDR_METHOD || u == HTTP_HDR_URL) |
1437 |
2240 |
continue; |
1438 |
3360 |
http_SetH(to, u, ptr); |
1439 |
3360 |
ptr = strchr(ptr, '\0') + 1; |
1440 |
3360 |
} |
1441 |
1120 |
nhd_before_merge = to->nhd; |
1442 |
6600 |
while (*ptr != '\0') { |
1443 |
5480 |
p = strchr(ptr, ':'); |
1444 |
5480 |
AN(p); |
1445 |
5480 |
u = http_findhdr(to, p - ptr, ptr); |
1446 |
5480 |
if (u == 0 || u >= nhd_before_merge) |
1447 |
2440 |
http_SetHeader(to, ptr); |
1448 |
5480 |
ptr = strchr(ptr, '\0') + 1; |
1449 |
|
} |
1450 |
1120 |
} |
1451 |
|
|
1452 |
|
/*--------------------------------------------------------------------*/ |
1453 |
|
|
1454 |
|
static void |
1455 |
267463 |
http_linkh(const struct http *to, const struct http *fm, unsigned n) |
1456 |
|
{ |
1457 |
|
|
1458 |
267463 |
assert(n < HTTP_HDR_FIRST); |
1459 |
267463 |
Tcheck(fm->hd[n]); |
1460 |
267463 |
to->hd[n] = fm->hd[n]; |
1461 |
267463 |
to->hdf[n] = fm->hdf[n]; |
1462 |
267463 |
http_VSLH(to, n); |
1463 |
267463 |
} |
1464 |
|
|
1465 |
|
/*--------------------------------------------------------------------*/ |
1466 |
|
|
1467 |
|
void |
1468 |
89158 |
http_FilterReq(struct http *to, const struct http *fm, unsigned how) |
1469 |
|
{ |
1470 |
|
unsigned u; |
1471 |
|
|
1472 |
89158 |
CHECK_OBJ_NOTNULL(to, HTTP_MAGIC); |
1473 |
89158 |
CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC); |
1474 |
|
|
1475 |
89158 |
http_linkh(to, fm, HTTP_HDR_METHOD); |
1476 |
89158 |
http_linkh(to, fm, HTTP_HDR_URL); |
1477 |
89158 |
http_linkh(to, fm, HTTP_HDR_PROTO); |
1478 |
89158 |
to->protover = fm->protover; |
1479 |
89158 |
to->status = fm->status; |
1480 |
|
|
1481 |
89158 |
to->nhd = HTTP_HDR_FIRST; |
1482 |
471252 |
for (u = HTTP_HDR_FIRST; u < fm->nhd; u++) { |
1483 |
382094 |
Tcheck(fm->hd[u]); |
1484 |
382094 |
if (http_isfiltered(fm, u, how)) |
1485 |
4360 |
continue; |
1486 |
377734 |
assert (to->nhd < to->shd); |
1487 |
377734 |
to->hd[to->nhd] = fm->hd[u]; |
1488 |
377734 |
to->hdf[to->nhd] = 0; |
1489 |
377734 |
http_VSLH(to, to->nhd); |
1490 |
377734 |
to->nhd++; |
1491 |
377734 |
} |
1492 |
89158 |
} |
1493 |
|
|
1494 |
|
/*-------------------------------------------------------------------- |
1495 |
|
* This function copies any header fields which reference foreign |
1496 |
|
* storage into our own WS. |
1497 |
|
*/ |
1498 |
|
|
1499 |
|
void |
1500 |
87916 |
http_CopyHome(const struct http *hp) |
1501 |
|
{ |
1502 |
|
unsigned u, l; |
1503 |
|
const char *p; |
1504 |
|
|
1505 |
954638 |
for (u = 0; u < hp->nhd; u++) { |
1506 |
866722 |
if (hp->hd[u].b == NULL) { |
1507 |
175832 |
assert(u < HTTP_HDR_FIRST); |
1508 |
175832 |
continue; |
1509 |
|
} |
1510 |
|
|
1511 |
690890 |
l = Tlen(hp->hd[u]); |
1512 |
690890 |
if (WS_Allocated(hp->ws, hp->hd[u].b, l)) |
1513 |
55079 |
continue; |
1514 |
|
|
1515 |
635811 |
p = WS_Copy(hp->ws, hp->hd[u].b, l + 1L); |
1516 |
635811 |
if (p == NULL) { |
1517 |
0 |
http_fail(hp); |
1518 |
0 |
VSLbs(hp->vsl, SLT_LostHeader, TOSTRAND(hp->hd[u].b)); |
1519 |
0 |
return; |
1520 |
|
} |
1521 |
635811 |
hp->hd[u].b = p; |
1522 |
635811 |
hp->hd[u].e = p + l; |
1523 |
635811 |
} |
1524 |
87916 |
} |
1525 |
|
|
1526 |
|
/*--------------------------------------------------------------------*/ |
1527 |
|
|
1528 |
|
void |
1529 |
362237 |
http_SetHeader(struct http *to, const char *header) |
1530 |
|
{ |
1531 |
|
|
1532 |
362237 |
CHECK_OBJ_NOTNULL(to, HTTP_MAGIC); |
1533 |
362237 |
if (to->nhd >= to->shd) { |
1534 |
40 |
VSLbs(to->vsl, SLT_LostHeader, TOSTRAND(header)); |
1535 |
40 |
http_fail(to); |
1536 |
40 |
return; |
1537 |
|
} |
1538 |
362197 |
http_SetH(to, to->nhd++, header); |
1539 |
362237 |
} |
1540 |
|
|
1541 |
|
/*--------------------------------------------------------------------*/ |
1542 |
|
|
1543 |
|
void |
1544 |
161590 |
http_ForceHeader(struct http *to, hdr_t hdr, const char *val) |
1545 |
|
{ |
1546 |
|
|
1547 |
161590 |
CHECK_OBJ_NOTNULL(to, HTTP_MAGIC); |
1548 |
161590 |
if (http_HdrIs(to, hdr, val)) |
1549 |
14800 |
return; |
1550 |
146790 |
http_Unset(to, hdr); |
1551 |
146790 |
http_PrintfHeader(to, "%s %s", hdr + 1, val); |
1552 |
161590 |
} |
1553 |
|
|
1554 |
|
void |
1555 |
414156 |
http_AppendHeader(struct http *to, hdr_t hdr, const char *val) |
1556 |
|
{ |
1557 |
|
const char *old; |
1558 |
|
|
1559 |
414156 |
http_CollectHdr(to, hdr); |
1560 |
414156 |
if (http_GetHdr(to, hdr, &old)) { |
1561 |
1920 |
http_Unset(to, hdr); |
1562 |
1920 |
http_PrintfHeader(to, "%s %s, %s", hdr + 1, old, val); |
1563 |
1920 |
} else { |
1564 |
412236 |
http_PrintfHeader(to, "%s %s", hdr + 1, val); |
1565 |
|
} |
1566 |
414156 |
} |
1567 |
|
|
1568 |
|
void |
1569 |
973318 |
http_PrintfHeader(struct http *to, const char *fmt, ...) |
1570 |
|
{ |
1571 |
|
va_list ap, ap2; |
1572 |
|
struct vsb vsb[1]; |
1573 |
|
size_t sz; |
1574 |
|
char *p; |
1575 |
|
|
1576 |
973318 |
CHECK_OBJ_NOTNULL(to, HTTP_MAGIC); |
1577 |
|
|
1578 |
973318 |
va_start(ap, fmt); |
1579 |
973318 |
va_copy(ap2, ap); |
1580 |
|
|
1581 |
973318 |
WS_VSB_new(vsb, to->ws); |
1582 |
973318 |
VSB_vprintf(vsb, fmt, ap); |
1583 |
973318 |
p = WS_VSB_finish(vsb, to->ws, &sz); |
1584 |
|
|
1585 |
973318 |
if (p == NULL || to->nhd >= to->shd) { |
1586 |
1116 |
http_fail(to); |
1587 |
1116 |
VSLbv(to->vsl, SLT_LostHeader, fmt, ap2); |
1588 |
1116 |
} else { |
1589 |
972224 |
http_SetH(to, to->nhd++, p); |
1590 |
|
} |
1591 |
973340 |
va_end(ap); |
1592 |
973340 |
va_end(ap2); |
1593 |
973340 |
} |
1594 |
|
|
1595 |
|
void |
1596 |
40755 |
http_TimeHeader(struct http *to, const char *fmt, vtim_real now) |
1597 |
|
{ |
1598 |
|
char *p; |
1599 |
|
|
1600 |
40755 |
CHECK_OBJ_NOTNULL(to, HTTP_MAGIC); |
1601 |
40755 |
if (to->nhd >= to->shd) { |
1602 |
0 |
VSLbs(to->vsl, SLT_LostHeader, TOSTRAND(fmt)); |
1603 |
0 |
http_fail(to); |
1604 |
0 |
return; |
1605 |
|
} |
1606 |
40755 |
p = WS_Alloc(to->ws, strlen(fmt) + VTIM_FORMAT_SIZE); |
1607 |
40755 |
if (p == NULL) { |
1608 |
3080 |
http_fail(to); |
1609 |
3080 |
VSLbs(to->vsl, SLT_LostHeader, TOSTRAND(fmt)); |
1610 |
3080 |
return; |
1611 |
|
} |
1612 |
37675 |
strcpy(p, fmt); |
1613 |
37675 |
VTIM_format(now, strchr(p, '\0')); |
1614 |
37675 |
http_SetH(to, to->nhd++, p); |
1615 |
40755 |
} |
1616 |
|
|
1617 |
|
const char * |
1618 |
270121 |
http_ViaHeader(void) |
1619 |
|
{ |
1620 |
|
|
1621 |
270121 |
return (via_hdr); |
1622 |
|
} |
1623 |
|
|
1624 |
|
/*--------------------------------------------------------------------*/ |
1625 |
|
|
1626 |
|
void |
1627 |
718859 |
http_Unset(struct http *hp, hdr_t hdr) |
1628 |
|
{ |
1629 |
|
uint16_t u, v; |
1630 |
|
|
1631 |
4561347 |
for (v = u = HTTP_HDR_FIRST; u < hp->nhd; u++) { |
1632 |
3842488 |
Tcheck(hp->hd[u]); |
1633 |
3842488 |
if (http_IsHdr(&hp->hd[u], hdr)) { |
1634 |
36920 |
http_VSLH_del(hp, u); |
1635 |
36920 |
continue; |
1636 |
|
} |
1637 |
3805568 |
if (v != u) { |
1638 |
93600 |
memcpy(&hp->hd[v], &hp->hd[u], sizeof *hp->hd); |
1639 |
93600 |
memcpy(&hp->hdf[v], &hp->hdf[u], sizeof *hp->hdf); |
1640 |
93600 |
} |
1641 |
3805568 |
v++; |
1642 |
3805568 |
} |
1643 |
718859 |
hp->nhd = v; |
1644 |
718859 |
} |