| | 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) hdr_t b = HDR(a); |
57 |
|
#include "tbl/http_headers.h" |
58 |
|
|
59 |
|
hdr_t H__Status = HDR(":status"); |
60 |
|
hdr_t H__Proto = HDR(":proto"); |
61 |
|
hdr_t H__Reason = HDR(":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 |
|
hdr_t *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 |
3003474 |
http_hdr_flags(const char *b, const char *e) |
183 |
|
{ |
184 |
|
unsigned u; |
185 |
|
struct http_hdrflg *retval; |
186 |
|
|
187 |
3003474 |
if (b == NULL || e == NULL) |
188 |
228 |
return (NULL); |
189 |
3003462 |
u = pdiff(b, e); |
190 |
3003462 |
if (u < GPERF_MIN_WORD_LENGTH || u > GPERF_MAX_WORD_LENGTH) |
191 |
1160 |
return (NULL); |
192 |
6004604 |
u += http_asso_values[(uint8_t)(e[-1])] + |
193 |
3002302 |
http_asso_values[(uint8_t)(b[0])]; |
194 |
3002302 |
if (u > GPERF_MAX_HASH_VALUE) |
195 |
40120 |
return (NULL); |
196 |
2962182 |
retval = &http_hdrflg[u]; |
197 |
2962182 |
if (retval->hdr == NULL) |
198 |
11078 |
return (NULL); |
199 |
2951104 |
AN(*retval->hdr); |
200 |
2951104 |
if (!http_hdr_at(*retval->hdr + 1, b, e - b)) |
201 |
41240 |
return (NULL); |
202 |
2909864 |
return (retval); |
203 |
3003462 |
} |
204 |
|
|
205 |
|
/*--------------------------------------------------------------------*/ |
206 |
|
|
207 |
|
static void |
208 |
1944384 |
http_init_hdr(hdr_t hdr, int flg) |
209 |
|
{ |
210 |
|
struct http_hdrflg *f; |
211 |
|
|
212 |
1944384 |
f = http_hdr_flags(hdr->str, hdr->str + hdr->len - 1); |
213 |
1944384 |
AN(f); |
214 |
1944384 |
assert(*f->hdr == hdr); |
215 |
1944384 |
f->flag = flg; |
216 |
1944384 |
} |
217 |
|
|
218 |
|
void |
219 |
37392 |
HTTP_Init(void) |
220 |
|
{ |
221 |
|
struct vsb *vsb; |
222 |
|
|
223 |
|
#define HTTPH(a, b, c) http_init_hdr(b, c); |
224 |
|
#include "tbl/http_headers.h" |
225 |
|
|
226 |
|
vsb = VSB_new_auto(); |
227 |
37392 |
AN(vsb); |
228 |
|
VSB_printf(vsb, "1.1 %s (Varnish/" PACKAGE_BRANCH ")", |
229 |
|
heritage.identity); |
230 |
37392 |
AZ(VSB_finish(vsb)); |
231 |
37392 |
REPLACE(via_hdr, VSB_data(vsb)); |
232 |
|
VSB_destroy(&vsb); |
233 |
|
} |
234 |
|
|
235 |
|
/*-------------------------------------------------------------------- |
236 |
|
* These two functions are in an incestuous relationship with the |
237 |
|
* order of macros in include/tbl/vsl_tags_http.h |
238 |
|
* |
239 |
|
* The http->logtag is the SLT_*Method enum, and we add to that, to |
240 |
|
* get the SLT_ to use. |
241 |
|
*/ |
242 |
|
|
243 |
|
static void |
244 |
4945485 |
http_VSLH(const struct http *hp, unsigned hdr) |
245 |
|
{ |
246 |
|
int i; |
247 |
|
|
248 |
4945485 |
if (hp->vsl != NULL) { |
249 |
4945615 |
assert(VXID_TAG(hp->vsl->wid)); |
250 |
4945615 |
i = hdr; |
251 |
4945615 |
if (i > HTTP_HDR_FIRST) |
252 |
2596922 |
i = HTTP_HDR_FIRST; |
253 |
4945615 |
i += hp->logtag; |
254 |
4945615 |
VSLbt(hp->vsl, (enum VSL_tag_e)i, hp->hd[hdr]); |
255 |
4945615 |
} |
256 |
4945759 |
} |
257 |
|
|
258 |
|
static void |
259 |
37920 |
http_VSLH_del(const struct http *hp, unsigned hdr) |
260 |
|
{ |
261 |
|
int i; |
262 |
|
|
263 |
37920 |
if (hp->vsl != NULL) { |
264 |
|
/* We don't support unsetting stuff in the first line */ |
265 |
37920 |
assert (hdr >= HTTP_HDR_FIRST); |
266 |
37920 |
assert(VXID_TAG(hp->vsl->wid)); |
267 |
37920 |
i = (HTTP_HDR_UNSET - HTTP_HDR_METHOD); |
268 |
37920 |
i += hp->logtag; |
269 |
37920 |
VSLbt(hp->vsl, (enum VSL_tag_e)i, hp->hd[hdr]); |
270 |
37920 |
} |
271 |
37920 |
} |
272 |
|
|
273 |
|
/*--------------------------------------------------------------------*/ |
274 |
|
|
275 |
|
void |
276 |
230542 |
http_VSL_log(const struct http *hp) |
277 |
|
{ |
278 |
|
unsigned u; |
279 |
|
|
280 |
2013237 |
for (u = 0; u < hp->nhd; u++) |
281 |
3104393 |
if (hp->hd[u].b != NULL) |
282 |
1321698 |
http_VSLH(hp, u); |
283 |
230542 |
} |
284 |
|
|
285 |
|
/*--------------------------------------------------------------------*/ |
286 |
|
|
287 |
|
static void |
288 |
4160 |
http_fail(const struct http *hp) |
289 |
|
{ |
290 |
|
char id[WS_ID_SIZE]; |
291 |
|
|
292 |
4160 |
VSC_C_main->losthdr++; |
293 |
4160 |
WS_Id(hp->ws, id); |
294 |
4160 |
VSLb(hp->vsl, SLT_Error, "out of workspace (%s)", id); |
295 |
4160 |
WS_MarkOverflow(hp->ws); |
296 |
4160 |
} |
297 |
|
|
298 |
|
/*-------------------------------------------------------------------- |
299 |
|
* List of canonical HTTP response code names from RFC2616 |
300 |
|
*/ |
301 |
|
|
302 |
|
static struct http_msg { |
303 |
|
unsigned nbr; |
304 |
|
const char *status; |
305 |
|
const char *txt; |
306 |
|
} http_msg[] = { |
307 |
|
#define HTTP_RESP(n, t) { n, #n, t}, |
308 |
|
#include "tbl/http_response.h" |
309 |
|
{ 0, "0", NULL } |
310 |
|
}; |
311 |
|
|
312 |
|
const char * |
313 |
58356 |
http_Status2Reason(unsigned status, const char **sstr) |
314 |
|
{ |
315 |
|
struct http_msg *mp; |
316 |
|
|
317 |
58356 |
status %= 1000; |
318 |
58356 |
assert(status >= 100); |
319 |
1795683 |
for (mp = http_msg; mp->nbr != 0 && mp->nbr <= status; mp++) |
320 |
1793883 |
if (mp->nbr == status) { |
321 |
56556 |
if (sstr) |
322 |
43358 |
*sstr = mp->status; |
323 |
56556 |
return (mp->txt); |
324 |
|
} |
325 |
1800 |
return ("Unknown HTTP Status"); |
326 |
58356 |
} |
327 |
|
|
328 |
|
/*--------------------------------------------------------------------*/ |
329 |
|
|
330 |
|
unsigned |
331 |
211553 |
HTTP_estimate(unsigned nhttp) |
332 |
|
{ |
333 |
|
|
334 |
|
/* XXX: We trust the structs to size-aligned as necessary */ |
335 |
211553 |
return (PRNDUP(sizeof(struct http) + sizeof(txt) * nhttp + nhttp)); |
336 |
|
} |
337 |
|
|
338 |
|
struct http * |
339 |
634657 |
HTTP_create(void *p, uint16_t nhttp, unsigned len) |
340 |
|
{ |
341 |
|
struct http *hp; |
342 |
|
|
343 |
634657 |
hp = p; |
344 |
634657 |
hp->magic = HTTP_MAGIC; |
345 |
634657 |
hp->hd = (void*)(hp + 1); |
346 |
634657 |
hp->shd = nhttp; |
347 |
634657 |
hp->hdf = (void*)(hp->hd + nhttp); |
348 |
634657 |
assert((unsigned char*)p + len == hp->hdf + PRNDUP(nhttp)); |
349 |
634657 |
return (hp); |
350 |
|
} |
351 |
|
|
352 |
|
/*--------------------------------------------------------------------*/ |
353 |
|
|
354 |
|
void |
355 |
589374 |
HTTP_Setup(struct http *hp, struct ws *ws, struct vsl_log *vsl, |
356 |
|
enum VSL_tag_e whence) |
357 |
|
{ |
358 |
589374 |
http_Teardown(hp); |
359 |
589374 |
hp->nhd = HTTP_HDR_FIRST; |
360 |
589374 |
hp->logtag = whence; |
361 |
589374 |
hp->ws = ws; |
362 |
589374 |
hp->vsl = vsl; |
363 |
589374 |
} |
364 |
|
|
365 |
|
/*-------------------------------------------------------------------- |
366 |
|
* http_Teardown() is a safety feature, we use it to zap all http |
367 |
|
* structs once we're done with them, to minimize the risk that |
368 |
|
* old stale pointers exist to no longer valid stuff. |
369 |
|
*/ |
370 |
|
|
371 |
|
void |
372 |
920345 |
http_Teardown(struct http *hp) |
373 |
|
{ |
374 |
|
|
375 |
920345 |
CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC); |
376 |
920345 |
AN(hp->shd); |
377 |
920345 |
memset(&hp->nhd, 0, sizeof *hp - offsetof(struct http, nhd)); |
378 |
920345 |
memset(hp->hd, 0, sizeof *hp->hd * hp->shd); |
379 |
920345 |
memset(hp->hdf, 0, sizeof *hp->hdf * hp->shd); |
380 |
920345 |
} |
381 |
|
|
382 |
|
/*-------------------------------------------------------------------- |
383 |
|
* Duplicate the http content into another http |
384 |
|
* We cannot just memcpy the struct because the hd & hdf are private |
385 |
|
* storage to the struct http. |
386 |
|
*/ |
387 |
|
|
388 |
|
void |
389 |
258798 |
HTTP_Dup(struct http *to, const struct http * fm) |
390 |
|
{ |
391 |
|
|
392 |
258798 |
assert(fm->nhd <= to->shd); |
393 |
258798 |
memcpy(to->hd, fm->hd, fm->nhd * sizeof *to->hd); |
394 |
258798 |
memcpy(to->hdf, fm->hdf, fm->nhd * sizeof *to->hdf); |
395 |
258798 |
to->nhd = fm->nhd; |
396 |
258798 |
to->logtag = fm->logtag; |
397 |
258798 |
to->status = fm->status; |
398 |
258798 |
to->protover = fm->protover; |
399 |
258798 |
} |
400 |
|
|
401 |
|
|
402 |
|
/*-------------------------------------------------------------------- |
403 |
|
* Clone the entire http structure, including vsl & ws |
404 |
|
*/ |
405 |
|
|
406 |
|
void |
407 |
244156 |
HTTP_Clone(struct http *to, const struct http * const fm) |
408 |
|
{ |
409 |
|
|
410 |
244156 |
HTTP_Dup(to, fm); |
411 |
244156 |
to->vsl = fm->vsl; |
412 |
244156 |
to->ws = fm->ws; |
413 |
244156 |
} |
414 |
|
|
415 |
|
/*--------------------------------------------------------------------*/ |
416 |
|
|
417 |
|
void |
418 |
263605 |
http_Proto(struct http *to) |
419 |
|
{ |
420 |
|
const char *fm; |
421 |
|
|
422 |
263605 |
fm = to->hd[HTTP_HDR_PROTO].b; |
423 |
|
|
424 |
526854 |
if (fm != NULL && |
425 |
263293 |
(fm[0] == 'H' || fm[0] == 'h') && |
426 |
263258 |
(fm[1] == 'T' || fm[1] == 't') && |
427 |
263254 |
(fm[2] == 'T' || fm[2] == 't') && |
428 |
263254 |
(fm[3] == 'P' || fm[3] == 'p') && |
429 |
263254 |
fm[4] == '/' && |
430 |
263254 |
vct_isdigit(fm[5]) && |
431 |
263249 |
fm[6] == '.' && |
432 |
263249 |
vct_isdigit(fm[7]) && |
433 |
263249 |
fm[8] == '\0') { |
434 |
263249 |
to->protover = 10 * (fm[5] - '0') + (fm[7] - '0'); |
435 |
263249 |
} else { |
436 |
360 |
to->protover = 0; |
437 |
|
} |
438 |
263609 |
} |
439 |
|
|
440 |
|
/*--------------------------------------------------------------------*/ |
441 |
|
|
442 |
|
void |
443 |
1565130 |
http_SetH(struct http *to, unsigned n, const char *header) |
444 |
|
{ |
445 |
|
|
446 |
1565130 |
assert(n < to->nhd); |
447 |
1565130 |
AN(header); |
448 |
1565130 |
to->hd[n].b = TRUST_ME(header); |
449 |
1565130 |
to->hd[n].e = strchr(to->hd[n].b, '\0'); |
450 |
1565130 |
to->hdf[n] = 0; |
451 |
1565130 |
http_VSLH(to, n); |
452 |
1565130 |
if (n == HTTP_HDR_PROTO) |
453 |
53998 |
http_Proto(to); |
454 |
1565130 |
} |
455 |
|
|
456 |
|
/*--------------------------------------------------------------------*/ |
457 |
|
|
458 |
|
static void |
459 |
1440 |
http_PutField(struct http *to, int field, const char *string) |
460 |
|
{ |
461 |
|
const char *p; |
462 |
|
|
463 |
1440 |
CHECK_OBJ_NOTNULL(to, HTTP_MAGIC); |
464 |
1440 |
p = WS_Copy(to->ws, string, -1); |
465 |
1440 |
if (p == NULL) { |
466 |
40 |
http_fail(to); |
467 |
40 |
VSLbs(to->vsl, SLT_LostHeader, TOSTRAND(string)); |
468 |
40 |
return; |
469 |
|
} |
470 |
1400 |
http_SetH(to, field, p); |
471 |
1440 |
} |
472 |
|
|
473 |
|
/*--------------------------------------------------------------------*/ |
474 |
|
|
475 |
|
int |
476 |
5703715 |
http_IsHdr(const txt *hh, hdr_t hdr) |
477 |
|
{ |
478 |
|
|
479 |
5703715 |
Tcheck(*hh); |
480 |
5703715 |
CHECK_HDR(hdr); |
481 |
5703715 |
return (http_hdr_at(hdr->str, hh->b, hdr->len)); |
482 |
|
} |
483 |
|
|
484 |
|
/*--------------------------------------------------------------------*/ |
485 |
|
|
486 |
|
static unsigned |
487 |
5879877 |
http_findhdr(const struct http *hp, unsigned l, const char *hdr) |
488 |
|
{ |
489 |
|
unsigned u; |
490 |
|
|
491 |
25343961 |
for (u = HTTP_HDR_FIRST; u < hp->nhd; u++) { |
492 |
20769903 |
Tcheck(hp->hd[u]); |
493 |
20769903 |
if (hp->hd[u].e < hp->hd[u].b + l + 1) |
494 |
3767397 |
continue; |
495 |
17002506 |
if (hp->hd[u].b[l] != ':') |
496 |
14281821 |
continue; |
497 |
2720685 |
if (!http_hdr_at(hdr, hp->hd[u].b, l)) |
498 |
1414866 |
continue; |
499 |
1305819 |
return (u); |
500 |
|
} |
501 |
4574058 |
return (0); |
502 |
5879877 |
} |
503 |
|
|
504 |
|
/*-------------------------------------------------------------------- |
505 |
|
* Count how many instances we have of this header |
506 |
|
*/ |
507 |
|
|
508 |
|
unsigned |
509 |
298197 |
http_CountHdr(const struct http *hp, hdr_t hdr) |
510 |
|
{ |
511 |
298197 |
unsigned retval = 0; |
512 |
|
unsigned u; |
513 |
|
|
514 |
298197 |
CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC); |
515 |
|
|
516 |
993102 |
for (u = HTTP_HDR_FIRST; u < hp->nhd; u++) { |
517 |
694905 |
Tcheck(hp->hd[u]); |
518 |
694905 |
if (http_IsHdr(&hp->hd[u], hdr)) |
519 |
147385 |
retval++; |
520 |
694905 |
} |
521 |
298197 |
return (retval); |
522 |
|
} |
523 |
|
|
524 |
|
/*-------------------------------------------------------------------- |
525 |
|
* This function collapses multiple header lines of the same name. |
526 |
|
* The lines are joined with a comma, according to [rfc2616, 4.2bot, p32] |
527 |
|
*/ |
528 |
|
|
529 |
|
void |
530 |
961562 |
http_CollectHdr(struct http *hp, hdr_t hdr) |
531 |
|
{ |
532 |
|
|
533 |
961562 |
http_CollectHdrSep(hp, hdr, NULL); |
534 |
961562 |
} |
535 |
|
|
536 |
|
/*-------------------------------------------------------------------- |
537 |
|
* You may prefer to collapse header fields using a different separator. |
538 |
|
* For Cookie headers, the separator is "; " for example. That's probably |
539 |
|
* the only example too. |
540 |
|
*/ |
541 |
|
|
542 |
|
void |
543 |
967437 |
http_CollectHdrSep(struct http *hp, hdr_t hdr, const char *sep) |
544 |
|
{ |
545 |
|
unsigned u, lsep, ml, f, x, d; |
546 |
967437 |
char *b = NULL, *e = NULL; |
547 |
|
const char *v; |
548 |
|
|
549 |
967437 |
CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC); |
550 |
967437 |
CHECK_HDR(hdr); |
551 |
|
|
552 |
967437 |
if (WS_Overflowed(hp->ws)) |
553 |
800 |
return; |
554 |
|
|
555 |
966637 |
if (sep == NULL || *sep == '\0') |
556 |
960764 |
sep = ", "; |
557 |
966639 |
lsep = strlen(sep); |
558 |
|
|
559 |
966639 |
f = http_findhdr(hp, hdr->len - 1, hdr->str); |
560 |
966639 |
if (f == 0) |
561 |
950281 |
return; |
562 |
|
|
563 |
60190 |
for (d = u = f + 1; u < hp->nhd; u++) { |
564 |
43832 |
Tcheck(hp->hd[u]); |
565 |
43832 |
if (!http_IsHdr(&hp->hd[u], hdr)) { |
566 |
43112 |
if (d != u) { |
567 |
2840 |
hp->hd[d] = hp->hd[u]; |
568 |
2840 |
hp->hdf[d] = hp->hdf[u]; |
569 |
2840 |
} |
570 |
43112 |
d++; |
571 |
43112 |
continue; |
572 |
|
} |
573 |
720 |
if (b == NULL) { |
574 |
|
/* Found second header, start our collection */ |
575 |
640 |
ml = WS_ReserveAll(hp->ws); |
576 |
640 |
b = WS_Reservation(hp->ws); |
577 |
640 |
e = b + ml; |
578 |
640 |
x = Tlen(hp->hd[f]); |
579 |
640 |
if (b + x >= e) { |
580 |
0 |
http_fail(hp); |
581 |
0 |
VSLbs(hp->vsl, SLT_LostHeader, |
582 |
0 |
TOSTRAND(hdr->str)); |
583 |
0 |
WS_Release(hp->ws, 0); |
584 |
0 |
return; |
585 |
|
} |
586 |
640 |
memcpy(b, hp->hd[f].b, x); |
587 |
640 |
b += x; |
588 |
640 |
} |
589 |
|
|
590 |
720 |
AN(b); |
591 |
720 |
AN(e); |
592 |
|
|
593 |
|
/* Append the Nth header we found */ |
594 |
720 |
x = Tlen(hp->hd[u]) - hdr->len; |
595 |
|
|
596 |
720 |
v = hp->hd[u].b + hdr->len; |
597 |
1440 |
while (vct_issp(*v)) { |
598 |
720 |
v++; |
599 |
720 |
x--; |
600 |
|
} |
601 |
|
|
602 |
720 |
if (b + lsep + x >= e) { |
603 |
0 |
http_fail(hp); |
604 |
0 |
VSLbs(hp->vsl, SLT_LostHeader, TOSTRAND(hdr->str)); |
605 |
0 |
WS_Release(hp->ws, 0); |
606 |
0 |
return; |
607 |
|
} |
608 |
720 |
memcpy(b, sep, lsep); |
609 |
720 |
b += lsep; |
610 |
720 |
memcpy(b, v, x); |
611 |
720 |
b += x; |
612 |
720 |
} |
613 |
16358 |
if (b == NULL) |
614 |
15718 |
return; |
615 |
640 |
hp->nhd = (uint16_t)d; |
616 |
640 |
AN(e); |
617 |
640 |
*b = '\0'; |
618 |
640 |
hp->hd[f].b = WS_Reservation(hp->ws); |
619 |
640 |
hp->hd[f].e = b; |
620 |
640 |
WS_ReleaseP(hp->ws, b + 1); |
621 |
967439 |
} |
622 |
|
|
623 |
|
/*--------------------------------------------------------------------*/ |
624 |
|
|
625 |
|
int |
626 |
4908165 |
http_GetHdr(const struct http *hp, hdr_t hdr, const char **ptr) |
627 |
|
{ |
628 |
|
unsigned u; |
629 |
|
const char *p; |
630 |
|
|
631 |
4908165 |
CHECK_HDR(hdr); |
632 |
4908165 |
u = http_findhdr(hp, hdr->len - 1, hdr->str); |
633 |
4908165 |
if (u == 0) { |
634 |
3621824 |
if (ptr != NULL) |
635 |
3328410 |
*ptr = NULL; |
636 |
3621824 |
return (0); |
637 |
|
} |
638 |
1286341 |
if (ptr != NULL) { |
639 |
1052176 |
p = hp->hd[u].b + hdr->len; |
640 |
2102578 |
while (vct_issp(*p)) |
641 |
1050402 |
p++; |
642 |
1052176 |
*ptr = p; |
643 |
1052176 |
} |
644 |
1286341 |
return (1); |
645 |
4908165 |
} |
646 |
|
|
647 |
|
/*----------------------------------------------------------------------------- |
648 |
|
* Split source string at any of the separators, return pointer to first |
649 |
|
* and last+1 char of substrings, with whitespace trimmed at both ends. |
650 |
|
* If sep being an empty string is shorthand for VCT::SP |
651 |
|
* If stop is NULL, src is NUL terminated. |
652 |
|
*/ |
653 |
|
|
654 |
|
static int |
655 |
90956 |
http_split(const char **src, const char *stop, const char *sep, |
656 |
|
const char **b, const char **e) |
657 |
|
{ |
658 |
|
const char *p, *q; |
659 |
|
|
660 |
90956 |
AN(src); |
661 |
90956 |
AN(*src); |
662 |
90956 |
AN(sep); |
663 |
90956 |
AN(b); |
664 |
90956 |
AN(e); |
665 |
|
|
666 |
90956 |
if (stop == NULL) |
667 |
90673 |
stop = strchr(*src, '\0'); |
668 |
|
|
669 |
156313 |
for (p = *src; p < stop && (vct_issp(*p) || strchr(sep, *p)); p++) |
670 |
3480 |
continue; |
671 |
|
|
672 |
90956 |
if (p >= stop) { |
673 |
32556 |
*b = NULL; |
674 |
32556 |
*e = NULL; |
675 |
32556 |
return (0); |
676 |
|
} |
677 |
|
|
678 |
58400 |
*b = p; |
679 |
58400 |
if (*sep == '\0') { |
680 |
0 |
for (q = p + 1; q < stop && !vct_issp(*q); q++) |
681 |
0 |
continue; |
682 |
0 |
*e = q; |
683 |
0 |
*src = q; |
684 |
0 |
return (1); |
685 |
|
} |
686 |
287349 |
for (q = p + 1; q < stop && !strchr(sep, *q); q++) |
687 |
228949 |
continue; |
688 |
58400 |
*src = q; |
689 |
58400 |
while (q > p && vct_issp(q[-1])) |
690 |
0 |
q--; |
691 |
58396 |
*e = q; |
692 |
58396 |
return (1); |
693 |
90952 |
} |
694 |
|
|
695 |
|
/*----------------------------------------------------------------------------- |
696 |
|
* Comparison rule for tokens: |
697 |
|
* if target string starts with '"', we use memcmp() and expect closing |
698 |
|
* double quote as well |
699 |
|
* otherwise we use http_tok_at() |
700 |
|
* |
701 |
|
* On match we increment *bp past the token name. |
702 |
|
*/ |
703 |
|
|
704 |
|
static int |
705 |
50920 |
http_istoken(const char **bp, const char *e, const char *token) |
706 |
|
{ |
707 |
50920 |
int fl = strlen(token); |
708 |
|
const char *b; |
709 |
|
|
710 |
50920 |
AN(bp); |
711 |
50920 |
AN(e); |
712 |
50920 |
AN(token); |
713 |
|
|
714 |
50920 |
b = *bp; |
715 |
|
|
716 |
50920 |
if (b + fl + 2 <= e && *b == '"' && |
717 |
0 |
!memcmp(b + 1, token, fl) && b[fl + 1] == '"') { |
718 |
0 |
*bp += fl + 2; |
719 |
0 |
return (1); |
720 |
|
} |
721 |
52520 |
if (b + fl <= e && http_tok_at(b, token, fl) && |
722 |
23840 |
(b + fl == e || !vct_istchar(b[fl]))) { |
723 |
23840 |
*bp += fl; |
724 |
23840 |
return (1); |
725 |
|
} |
726 |
27080 |
return (0); |
727 |
50920 |
} |
728 |
|
|
729 |
|
/*----------------------------------------------------------------------------- |
730 |
|
* Find a given data element (token) in a header according to RFC2616's #rule |
731 |
|
* (section 2.1, p15) |
732 |
|
* |
733 |
|
* On case sensitivity: |
734 |
|
* |
735 |
|
* Section 4.2 (Messages Headers) defines field (header) name as case |
736 |
|
* insensitive, but the field (header) value/content may be case-sensitive. |
737 |
|
* |
738 |
|
* http_GetHdrToken looks up a token in a header value and the rfc does not say |
739 |
|
* explicitly if tokens are to be compared with or without respect to case. |
740 |
|
* |
741 |
|
* But all examples and specific statements regarding tokens follow the rule |
742 |
|
* that unquoted tokens are to be matched case-insensitively and quoted tokens |
743 |
|
* case-sensitively. |
744 |
|
* |
745 |
|
* The optional pb and pe arguments will point to the token content start and |
746 |
|
* end+1, white space trimmed on both sides. |
747 |
|
*/ |
748 |
|
|
749 |
|
int |
750 |
581798 |
http_GetHdrToken(const struct http *hp, hdr_t hdr, |
751 |
|
const char *token, const char **pb, const char **pe) |
752 |
|
{ |
753 |
|
const char *h, *b, *e; |
754 |
|
|
755 |
581798 |
if (pb != NULL) |
756 |
442120 |
*pb = NULL; |
757 |
581798 |
if (pe != NULL) |
758 |
134732 |
*pe = NULL; |
759 |
581798 |
if (!http_GetHdr(hp, hdr, &h)) |
760 |
532358 |
return (0); |
761 |
49440 |
AN(h); |
762 |
|
|
763 |
76520 |
while (http_split(&h, NULL, ",", &b, &e)) |
764 |
50920 |
if (http_istoken(&b, e, token)) |
765 |
23840 |
break; |
766 |
49440 |
if (b == NULL) |
767 |
25600 |
return (0); |
768 |
23840 |
if (pb != NULL) { |
769 |
23680 |
for (; vct_islws(*b); b++) |
770 |
200 |
continue; |
771 |
23480 |
if (b == e) { |
772 |
21920 |
b = NULL; |
773 |
21920 |
e = NULL; |
774 |
21920 |
} |
775 |
23480 |
*pb = b; |
776 |
23480 |
if (pe != NULL) |
777 |
21640 |
*pe = e; |
778 |
23480 |
} |
779 |
23840 |
return (1); |
780 |
581798 |
} |
781 |
|
|
782 |
|
/*-------------------------------------------------------------------- |
783 |
|
* Find a given header field's quality value (qvalue). |
784 |
|
*/ |
785 |
|
|
786 |
|
double |
787 |
134732 |
http_GetHdrQ(const struct http *hp, hdr_t hdr, const char *field) |
788 |
|
{ |
789 |
|
const char *hb, *he, *b, *e; |
790 |
|
int i; |
791 |
|
double a, f; |
792 |
|
|
793 |
134732 |
i = http_GetHdrToken(hp, hdr, field, &hb, &he); |
794 |
134732 |
if (!i) |
795 |
113092 |
return (0.); |
796 |
|
|
797 |
21640 |
if (hb == NULL) |
798 |
21360 |
return (1.); |
799 |
280 |
while (http_split(&hb, he, ";", &b, &e)) { |
800 |
280 |
if (*b != 'q') |
801 |
0 |
continue; |
802 |
280 |
for (b++; b < e && vct_issp(*b); b++) |
803 |
0 |
continue; |
804 |
280 |
if (b == e || *b != '=') |
805 |
0 |
continue; |
806 |
280 |
break; |
807 |
|
} |
808 |
280 |
if (b == NULL) |
809 |
0 |
return (1.); |
810 |
280 |
for (b++; b < e && vct_issp(*b); b++) |
811 |
0 |
continue; |
812 |
280 |
if (b == e || (*b != '.' && !vct_isdigit(*b))) |
813 |
40 |
return (0.); |
814 |
240 |
a = 0; |
815 |
480 |
while (b < e && vct_isdigit(*b)) { |
816 |
240 |
a *= 10.; |
817 |
240 |
a += *b - '0'; |
818 |
240 |
b++; |
819 |
|
} |
820 |
240 |
if (b == e || *b++ != '.') |
821 |
40 |
return (a); |
822 |
200 |
f = .1; |
823 |
640 |
while (b < e && vct_isdigit(*b)) { |
824 |
440 |
a += f * (*b - '0'); |
825 |
440 |
f *= .1; |
826 |
440 |
b++; |
827 |
|
} |
828 |
200 |
return (a); |
829 |
134732 |
} |
830 |
|
|
831 |
|
/*-------------------------------------------------------------------- |
832 |
|
* Find a given header field's value. |
833 |
|
*/ |
834 |
|
|
835 |
|
int |
836 |
307392 |
http_GetHdrField(const struct http *hp, hdr_t hdr, |
837 |
|
const char *field, const char **ptr) |
838 |
|
{ |
839 |
|
const char *h; |
840 |
|
int i; |
841 |
|
|
842 |
307392 |
if (ptr != NULL) |
843 |
156080 |
*ptr = NULL; |
844 |
|
|
845 |
307392 |
h = NULL; |
846 |
307392 |
i = http_GetHdrToken(hp, hdr, field, &h, NULL); |
847 |
307392 |
if (!i) |
848 |
305552 |
return (i); |
849 |
|
|
850 |
1840 |
if (ptr != NULL && h != NULL) { |
851 |
|
/* Skip whitespace, looking for '=' */ |
852 |
1280 |
while (*h && vct_issp(*h)) |
853 |
0 |
h++; |
854 |
1280 |
if (*h == '=') { |
855 |
1280 |
h++; |
856 |
1440 |
while (*h && vct_issp(*h)) |
857 |
160 |
h++; |
858 |
1280 |
*ptr = h; |
859 |
1280 |
} |
860 |
1280 |
} |
861 |
1840 |
return (i); |
862 |
307392 |
} |
863 |
|
|
864 |
|
/*--------------------------------------------------------------------*/ |
865 |
|
|
866 |
|
ssize_t |
867 |
440627 |
http_GetContentLength(const struct http *hp) |
868 |
|
{ |
869 |
|
ssize_t cl; |
870 |
|
const char *b; |
871 |
|
|
872 |
440627 |
CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC); |
873 |
|
|
874 |
440627 |
if (!http_GetHdr(hp, H_Content_Length, &b)) |
875 |
172470 |
return (-1); |
876 |
268157 |
cl = VNUM_uint(b, NULL, &b); |
877 |
268157 |
if (cl < 0) |
878 |
160 |
return (-2); |
879 |
267997 |
while (vct_islws(*b)) |
880 |
0 |
b++; |
881 |
267997 |
if (*b != '\0') |
882 |
0 |
return (-2); |
883 |
267997 |
return (cl); |
884 |
440627 |
} |
885 |
|
|
886 |
|
ssize_t |
887 |
79557 |
http_GetContentRange(const struct http *hp, ssize_t *lo, ssize_t *hi) |
888 |
|
{ |
889 |
|
ssize_t tmp, cl; |
890 |
|
const char *b, *t; |
891 |
|
|
892 |
79557 |
CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC); |
893 |
|
|
894 |
79557 |
if (lo == NULL) |
895 |
0 |
lo = &tmp; |
896 |
79557 |
if (hi == NULL) |
897 |
0 |
hi = &tmp; |
898 |
|
|
899 |
79557 |
*lo = *hi = -1; |
900 |
|
|
901 |
79557 |
if (!http_GetHdr(hp, H_Content_Range, &b)) |
902 |
79197 |
return (-1); |
903 |
|
|
904 |
360 |
t = strchr(b, ' '); |
905 |
360 |
if (t == NULL) |
906 |
40 |
return (-2); // Missing space after range unit |
907 |
|
|
908 |
320 |
if (!http_range_at(b, bytes, t - b)) |
909 |
40 |
return (-1); // Unknown range unit, ignore |
910 |
280 |
b = t + 1; |
911 |
|
|
912 |
280 |
if (*b == '*') { // Content-Range: bytes */123 |
913 |
120 |
*lo = *hi = -1; |
914 |
120 |
b++; |
915 |
120 |
} else { // Content-Range: bytes 1-2/3 |
916 |
160 |
*lo = VNUM_uint(b, NULL, &b); |
917 |
160 |
if (*lo < 0) |
918 |
0 |
return (-2); |
919 |
160 |
if (*b != '-') |
920 |
0 |
return (-2); |
921 |
160 |
*hi = VNUM_uint(b + 1, NULL, &b); |
922 |
160 |
if (*hi < 0) |
923 |
0 |
return (-2); |
924 |
|
} |
925 |
280 |
if (*b != '/') |
926 |
0 |
return (-2); |
927 |
280 |
if (b[1] == '*') { // Content-Range: bytes 1-2/* |
928 |
40 |
cl = -1; |
929 |
40 |
b += 2; |
930 |
40 |
} else { |
931 |
240 |
cl = VNUM_uint(b + 1, NULL, &b); |
932 |
240 |
if (cl <= 0) |
933 |
0 |
return (-2); |
934 |
|
} |
935 |
280 |
while (vct_islws(*b)) |
936 |
0 |
b++; |
937 |
280 |
if (*b != '\0') |
938 |
0 |
return (-2); |
939 |
280 |
if (*lo > *hi) |
940 |
0 |
return (-2); |
941 |
280 |
assert(cl >= -1); |
942 |
280 |
if (*lo >= cl || *hi >= cl) |
943 |
40 |
return (-2); |
944 |
240 |
AN(cl); |
945 |
240 |
return (cl); |
946 |
79557 |
} |
947 |
|
|
948 |
|
const char * |
949 |
81480 |
http_GetRange(const struct http *hp, ssize_t *lo, ssize_t *hi, ssize_t len) |
950 |
|
{ |
951 |
|
ssize_t tmp_lo, tmp_hi; |
952 |
|
const char *b, *t; |
953 |
|
|
954 |
81480 |
CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC); |
955 |
|
|
956 |
81480 |
if (lo == NULL) |
957 |
0 |
lo = &tmp_lo; |
958 |
81480 |
if (hi == NULL) |
959 |
0 |
hi = &tmp_hi; |
960 |
|
|
961 |
81480 |
*lo = *hi = -1; |
962 |
|
|
963 |
81480 |
if (!http_GetHdr(hp, H_Range, &b)) |
964 |
79360 |
return (NULL); |
965 |
|
|
966 |
2120 |
t = strchr(b, '='); |
967 |
2120 |
if (t == NULL) |
968 |
80 |
return ("Missing '='"); |
969 |
|
|
970 |
2040 |
if (!http_range_at(b, bytes, t - b)) |
971 |
120 |
return ("Not Bytes"); |
972 |
1920 |
b = t + 1; |
973 |
|
|
974 |
1920 |
*lo = VNUM_uint(b, NULL, &b); |
975 |
1920 |
if (*lo == -2) |
976 |
0 |
return ("Low number too big"); |
977 |
1920 |
if (*b++ != '-') |
978 |
0 |
return ("Missing hyphen"); |
979 |
|
|
980 |
1920 |
*hi = VNUM_uint(b, NULL, &b); |
981 |
1920 |
if (*hi == -2) |
982 |
0 |
return ("High number too big"); |
983 |
1920 |
if (*lo == -1 && *hi == -1) |
984 |
40 |
return ("Neither high nor low"); |
985 |
1880 |
if (*lo == -1 && *hi == 0) |
986 |
40 |
return ("No low, high is zero"); |
987 |
1840 |
if (*hi >= 0 && *hi < *lo) |
988 |
40 |
return ("high smaller than low"); |
989 |
|
|
990 |
1840 |
while (vct_islws(*b)) |
991 |
40 |
b++; |
992 |
1800 |
if (*b != '\0') |
993 |
40 |
return ("Trailing stuff"); |
994 |
|
|
995 |
1760 |
assert(*lo >= -1); |
996 |
1760 |
assert(*hi >= -1); |
997 |
|
|
998 |
1760 |
if (*lo < 0) { |
999 |
160 |
assert(*hi > 0); |
1000 |
160 |
*lo = len - *hi; |
1001 |
160 |
if (*lo < 0) |
1002 |
80 |
*lo = 0; |
1003 |
160 |
*hi = len - 1; |
1004 |
1760 |
} else if (len >= 0 && (*hi >= len || *hi < 0)) { |
1005 |
360 |
*hi = len - 1; |
1006 |
360 |
} |
1007 |
|
|
1008 |
1760 |
if (len <= 0) |
1009 |
680 |
return (NULL); // Allow 200 response |
1010 |
|
|
1011 |
1080 |
if (*lo >= len) |
1012 |
40 |
return ("low range beyond object"); |
1013 |
|
|
1014 |
1040 |
return (NULL); |
1015 |
81480 |
} |
1016 |
|
|
1017 |
|
/*-------------------------------------------------------------------- |
1018 |
|
*/ |
1019 |
|
|
1020 |
|
stream_close_t |
1021 |
231799 |
http_DoConnection(struct http *hp, stream_close_t sc_close) |
1022 |
|
{ |
1023 |
|
const char *h, *b, *e; |
1024 |
|
stream_close_t retval; |
1025 |
|
unsigned u, v; |
1026 |
|
struct http_hdrflg *f; |
1027 |
|
|
1028 |
231799 |
CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC); |
1029 |
231799 |
assert(sc_close == SC_REQ_CLOSE || sc_close == SC_RESP_CLOSE); |
1030 |
|
|
1031 |
231799 |
if (hp->protover == 10) |
1032 |
1537 |
retval = SC_REQ_HTTP10; |
1033 |
|
else |
1034 |
230262 |
retval = SC_NULL; |
1035 |
|
|
1036 |
231799 |
http_CollectHdr(hp, H_Connection); |
1037 |
231799 |
if (!http_GetHdr(hp, H_Connection, &h)) |
1038 |
224723 |
return (retval); |
1039 |
7076 |
AN(h); |
1040 |
14152 |
while (http_split(&h, NULL, ",", &b, &e)) { |
1041 |
7196 |
u = pdiff(b, e); |
1042 |
7196 |
if (u == 5 && http_hdr_at(b, "close", u)) |
1043 |
5797 |
retval = sc_close; |
1044 |
7196 |
if (u == 10 && http_hdr_at(b, "keep-alive", u)) |
1045 |
920 |
retval = SC_NULL; |
1046 |
|
|
1047 |
|
/* Refuse removal of well-known-headers if they would pass. */ |
1048 |
7196 |
f = http_hdr_flags(b, e); |
1049 |
7196 |
if (f != NULL && !(f->flag & HTTPH_R_PASS)) |
1050 |
120 |
return (SC_RX_BAD); |
1051 |
|
|
1052 |
34374 |
for (v = HTTP_HDR_FIRST; v < hp->nhd; v++) { |
1053 |
27298 |
Tcheck(hp->hd[v]); |
1054 |
27298 |
if (hp->hd[v].e < hp->hd[v].b + u + 1) |
1055 |
1240 |
continue; |
1056 |
26058 |
if (hp->hd[v].b[u] != ':') |
1057 |
24058 |
continue; |
1058 |
2000 |
if (!http_hdr_at(b, hp->hd[v].b, u)) |
1059 |
1520 |
continue; |
1060 |
480 |
hp->hdf[v] |= HDF_FILTER; |
1061 |
480 |
} |
1062 |
|
} |
1063 |
6956 |
CHECK_OBJ_NOTNULL(retval, STREAM_CLOSE_MAGIC); |
1064 |
6956 |
return (retval); |
1065 |
231799 |
} |
1066 |
|
|
1067 |
|
/*--------------------------------------------------------------------*/ |
1068 |
|
|
1069 |
|
int |
1070 |
438593 |
http_HdrIs(const struct http *hp, hdr_t hdr, const char *val) |
1071 |
|
{ |
1072 |
|
const char *p; |
1073 |
|
|
1074 |
438593 |
if (!http_GetHdr(hp, hdr, &p)) |
1075 |
415593 |
return (0); |
1076 |
23000 |
AN(p); |
1077 |
23000 |
if (http_tok_eq(p, val)) |
1078 |
21960 |
return (1); |
1079 |
1040 |
return (0); |
1080 |
438593 |
} |
1081 |
|
|
1082 |
|
/*--------------------------------------------------------------------*/ |
1083 |
|
|
1084 |
|
uint16_t |
1085 |
568704 |
http_GetStatus(const struct http *hp) |
1086 |
|
{ |
1087 |
|
|
1088 |
568704 |
CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC); |
1089 |
568704 |
return (hp->status); |
1090 |
|
} |
1091 |
|
|
1092 |
|
int |
1093 |
397258 |
http_IsStatus(const struct http *hp, int val) |
1094 |
|
{ |
1095 |
|
|
1096 |
397258 |
CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC); |
1097 |
397258 |
assert(val >= 100 && val <= 999); |
1098 |
397258 |
return (val == (hp->status % 1000)); |
1099 |
|
} |
1100 |
|
|
1101 |
|
/*-------------------------------------------------------------------- |
1102 |
|
* Setting the status will also set the Reason appropriately |
1103 |
|
*/ |
1104 |
|
|
1105 |
|
void |
1106 |
44798 |
http_SetStatus(struct http *to, uint16_t status, const char *reason) |
1107 |
|
{ |
1108 |
|
char buf[4]; |
1109 |
44798 |
const char *sstr = NULL; |
1110 |
|
|
1111 |
44798 |
CHECK_OBJ_NOTNULL(to, HTTP_MAGIC); |
1112 |
|
/* |
1113 |
|
* We allow people to use top digits for internal VCL |
1114 |
|
* signalling, but strip them from the ASCII version. |
1115 |
|
*/ |
1116 |
44798 |
to->status = status; |
1117 |
44798 |
status %= 1000; |
1118 |
44798 |
assert(status >= 100); |
1119 |
|
|
1120 |
44798 |
if (reason == NULL) |
1121 |
8600 |
reason = http_Status2Reason(status, &sstr); |
1122 |
|
else |
1123 |
36198 |
(void)http_Status2Reason(status, &sstr); |
1124 |
|
|
1125 |
44798 |
if (sstr) { |
1126 |
43358 |
http_SetH(to, HTTP_HDR_STATUS, sstr); |
1127 |
43358 |
} else { |
1128 |
1440 |
bprintf(buf, "%03d", status); |
1129 |
1440 |
http_PutField(to, HTTP_HDR_STATUS, buf); |
1130 |
|
} |
1131 |
44798 |
http_SetH(to, HTTP_HDR_REASON, reason); |
1132 |
44798 |
} |
1133 |
|
|
1134 |
|
/*--------------------------------------------------------------------*/ |
1135 |
|
|
1136 |
|
const char * |
1137 |
207890 |
http_GetMethod(const struct http *hp) |
1138 |
|
{ |
1139 |
|
|
1140 |
207890 |
CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC); |
1141 |
207890 |
Tcheck(hp->hd[HTTP_HDR_METHOD]); |
1142 |
207890 |
return (hp->hd[HTTP_HDR_METHOD].b); |
1143 |
|
} |
1144 |
|
|
1145 |
|
/*-------------------------------------------------------------------- |
1146 |
|
* Force a particular header field to a particular value |
1147 |
|
*/ |
1148 |
|
|
1149 |
|
void |
1150 |
306629 |
http_ForceField(struct http *to, unsigned n, const char *t) |
1151 |
|
{ |
1152 |
|
int i; |
1153 |
|
|
1154 |
306629 |
CHECK_OBJ_NOTNULL(to, HTTP_MAGIC); |
1155 |
306629 |
assert(n < HTTP_HDR_FIRST); |
1156 |
306629 |
assert(n == HTTP_HDR_METHOD || n == HTTP_HDR_PROTO); |
1157 |
306629 |
AN(t); |
1158 |
|
|
1159 |
|
/* NB: method names and protocol versions are case-sensitive. */ |
1160 |
306629 |
if (to->hd[n].b == NULL || strcmp(to->hd[n].b, t)) { |
1161 |
4760 |
i = (HTTP_HDR_UNSET - HTTP_HDR_METHOD); |
1162 |
4760 |
i += to->logtag; |
1163 |
|
/* XXX: this is a dead branch */ |
1164 |
4760 |
if (n >= HTTP_HDR_FIRST) |
1165 |
0 |
VSLbt(to->vsl, (enum VSL_tag_e)i, to->hd[n]); |
1166 |
4760 |
http_SetH(to, n, t); |
1167 |
4760 |
} |
1168 |
306629 |
} |
1169 |
|
|
1170 |
|
/*--------------------------------------------------------------------*/ |
1171 |
|
|
1172 |
|
void |
1173 |
40880 |
http_PutResponse(struct http *to, const char *proto, uint16_t status, |
1174 |
|
const char *reason) |
1175 |
|
{ |
1176 |
|
|
1177 |
40880 |
CHECK_OBJ_NOTNULL(to, HTTP_MAGIC); |
1178 |
40880 |
if (proto != NULL) |
1179 |
40880 |
http_SetH(to, HTTP_HDR_PROTO, proto); |
1180 |
40880 |
http_SetStatus(to, status, reason); |
1181 |
40880 |
} |
1182 |
|
|
1183 |
|
/*-------------------------------------------------------------------- |
1184 |
|
* check if header is filtered by the dynamic marker or the static |
1185 |
|
* definitions in http_headers.h |
1186 |
|
*/ |
1187 |
|
|
1188 |
|
static inline int |
1189 |
1584740 |
http_isfiltered(const struct http *fm, unsigned u, unsigned how) |
1190 |
|
{ |
1191 |
|
const char *e; |
1192 |
|
const struct http_hdrflg *f; |
1193 |
|
|
1194 |
1584740 |
if (fm->hdf[u] & HDF_FILTER) |
1195 |
680 |
return (1); |
1196 |
1584060 |
if (u < HTTP_HDR_FIRST) |
1197 |
532230 |
return (0); |
1198 |
1051830 |
e = strchr(fm->hd[u].b, ':'); |
1199 |
1051830 |
if (e == NULL) |
1200 |
0 |
return (0); |
1201 |
1051830 |
f = http_hdr_flags(fm->hd[u].b, e); |
1202 |
1051830 |
return (f != NULL && f->flag & how); |
1203 |
1584740 |
} |
1204 |
|
|
1205 |
|
int |
1206 |
33586 |
http_IsFiltered(const struct http *fm, unsigned u, unsigned how) |
1207 |
|
{ |
1208 |
|
|
1209 |
33586 |
return (http_isfiltered(fm, u, how)); |
1210 |
|
} |
1211 |
|
|
1212 |
|
/*-------------------------------------------------------------------- |
1213 |
|
* Estimate how much workspace we need to Filter this header according |
1214 |
|
* to 'how'. |
1215 |
|
*/ |
1216 |
|
|
1217 |
|
unsigned |
1218 |
88838 |
http_EstimateWS(const struct http *fm, unsigned how) |
1219 |
|
{ |
1220 |
|
unsigned u, l; |
1221 |
|
|
1222 |
88838 |
l = 4; |
1223 |
88838 |
CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC); |
1224 |
847857 |
for (u = 0; u < fm->nhd; u++) { |
1225 |
759019 |
if (u == HTTP_HDR_METHOD || u == HTTP_HDR_URL) |
1226 |
177678 |
continue; |
1227 |
581341 |
Tcheck(fm->hd[u]); |
1228 |
581341 |
if (http_isfiltered(fm, u, how)) |
1229 |
10372 |
continue; |
1230 |
570969 |
l += Tlen(fm->hd[u]) + 1L; |
1231 |
570969 |
} |
1232 |
88838 |
return (PRNDUP(l + 1L)); |
1233 |
|
} |
1234 |
|
|
1235 |
|
/*-------------------------------------------------------------------- |
1236 |
|
* Encode http struct as byte string. |
1237 |
|
* |
1238 |
|
* XXX: We could save considerable special-casing below by encoding also |
1239 |
|
* XXX: H__Status, H__Reason and H__Proto into the string, but it would |
1240 |
|
* XXX: add 26-30 bytes to all encoded objects to save a little code. |
1241 |
|
* XXX: It could possibly be a good idea for later HTTP versions. |
1242 |
|
*/ |
1243 |
|
|
1244 |
|
void |
1245 |
88598 |
HTTP_Encode(const struct http *fm, uint8_t *p0, unsigned l, unsigned how) |
1246 |
|
{ |
1247 |
|
unsigned u, w; |
1248 |
|
uint16_t n; |
1249 |
|
uint8_t *p, *e; |
1250 |
|
|
1251 |
88598 |
AN(p0); |
1252 |
88598 |
AN(l); |
1253 |
88598 |
p = p0; |
1254 |
88598 |
e = p + l; |
1255 |
88598 |
assert(p + 5 <= e); |
1256 |
88598 |
assert(fm->nhd <= fm->shd); |
1257 |
88598 |
n = HTTP_HDR_FIRST - 3; |
1258 |
88598 |
vbe16enc(p + 2, fm->status); |
1259 |
88598 |
p += 4; |
1260 |
88598 |
CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC); |
1261 |
845369 |
for (u = 0; u < fm->nhd; u++) { |
1262 |
756771 |
if (u == HTTP_HDR_METHOD || u == HTTP_HDR_URL) |
1263 |
177192 |
continue; |
1264 |
579579 |
Tcheck(fm->hd[u]); |
1265 |
579579 |
if (http_isfiltered(fm, u, how)) |
1266 |
10370 |
continue; |
1267 |
569209 |
http_VSLH(fm, u); |
1268 |
569209 |
w = Tlen(fm->hd[u]) + 1L; |
1269 |
569209 |
assert(p + w + 1 <= e); |
1270 |
569209 |
memcpy(p, fm->hd[u].b, w); |
1271 |
569209 |
p += w; |
1272 |
569209 |
n++; |
1273 |
569209 |
} |
1274 |
88598 |
*p++ = '\0'; |
1275 |
88598 |
assert(p <= e); |
1276 |
88598 |
vbe16enc(p0, n + 1); |
1277 |
88598 |
} |
1278 |
|
|
1279 |
|
/*-------------------------------------------------------------------- |
1280 |
|
* Decode byte string into http struct |
1281 |
|
*/ |
1282 |
|
|
1283 |
|
int |
1284 |
129100 |
HTTP_Decode(struct http *to, const uint8_t *fm) |
1285 |
|
{ |
1286 |
|
|
1287 |
129100 |
CHECK_OBJ_NOTNULL(to, HTTP_MAGIC); |
1288 |
129100 |
AN(to->vsl); |
1289 |
129100 |
AN(fm); |
1290 |
129100 |
if (vbe16dec(fm) <= to->shd) { |
1291 |
129031 |
to->status = vbe16dec(fm + 2); |
1292 |
129031 |
fm += 4; |
1293 |
1219046 |
for (to->nhd = 0; to->nhd < to->shd; to->nhd++) { |
1294 |
1219046 |
if (to->nhd == HTTP_HDR_METHOD || |
1295 |
1089953 |
to->nhd == HTTP_HDR_URL) { |
1296 |
258026 |
to->hd[to->nhd].b = NULL; |
1297 |
258026 |
to->hd[to->nhd].e = NULL; |
1298 |
258026 |
continue; |
1299 |
|
} |
1300 |
961020 |
if (*fm == '\0') |
1301 |
129031 |
return (0); |
1302 |
831989 |
to->hd[to->nhd].b = (const void*)fm; |
1303 |
831989 |
fm = (const void*)strchr((const void*)fm, '\0'); |
1304 |
831989 |
to->hd[to->nhd].e = (const void*)fm; |
1305 |
831989 |
fm++; |
1306 |
831989 |
http_VSLH(to, to->nhd); |
1307 |
831989 |
} |
1308 |
0 |
} |
1309 |
138 |
VSLb(to->vsl, SLT_Error, |
1310 |
|
"Too many headers to Decode object (%u vs. %u)", |
1311 |
69 |
vbe16dec(fm), to->shd); |
1312 |
69 |
return (-1); |
1313 |
129100 |
} |
1314 |
|
|
1315 |
|
/*--------------------------------------------------------------------*/ |
1316 |
|
|
1317 |
|
uint16_t |
1318 |
40 |
HTTP_GetStatusPack(struct worker *wrk, struct objcore *oc) |
1319 |
|
{ |
1320 |
|
const char *ptr; |
1321 |
40 |
ptr = ObjGetAttr(wrk, oc, OA_HEADERS, NULL); |
1322 |
40 |
AN(ptr); |
1323 |
|
|
1324 |
40 |
return (vbe16dec(ptr + 2)); |
1325 |
|
} |
1326 |
|
|
1327 |
|
/*--------------------------------------------------------------------*/ |
1328 |
|
|
1329 |
|
/* Get the first packed header */ |
1330 |
|
int |
1331 |
29506 |
HTTP_IterHdrPack(struct worker *wrk, struct objcore *oc, const char **p) |
1332 |
|
{ |
1333 |
|
const char *ptr; |
1334 |
|
|
1335 |
29506 |
CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); |
1336 |
29506 |
CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC); |
1337 |
29506 |
AN(p); |
1338 |
|
|
1339 |
29506 |
if (*p == NULL) { |
1340 |
9299 |
ptr = ObjGetAttr(wrk, oc, OA_HEADERS, NULL); |
1341 |
9299 |
AN(ptr); |
1342 |
9299 |
ptr += 4; /* Skip nhd and status */ |
1343 |
9299 |
ptr = strchr(ptr, '\0') + 1; /* Skip :proto: */ |
1344 |
9299 |
ptr = strchr(ptr, '\0') + 1; /* Skip :status: */ |
1345 |
9299 |
ptr = strchr(ptr, '\0') + 1; /* Skip :reason: */ |
1346 |
9299 |
*p = ptr; |
1347 |
9299 |
} else { |
1348 |
20207 |
*p = strchr(*p, '\0') + 1; /* Skip to next header */ |
1349 |
|
} |
1350 |
29506 |
if (**p == '\0') |
1351 |
1777 |
return (0); |
1352 |
27729 |
return (1); |
1353 |
29506 |
} |
1354 |
|
|
1355 |
|
const char * |
1356 |
9938 |
HTTP_GetHdrPack(struct worker *wrk, struct objcore *oc, hdr_t hdr) |
1357 |
|
{ |
1358 |
|
const char *ptr; |
1359 |
|
|
1360 |
9938 |
CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); |
1361 |
9938 |
CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC); |
1362 |
9938 |
CHECK_HDR(hdr); |
1363 |
|
|
1364 |
9938 |
if (hdr->str[0] == ':') { |
1365 |
|
/* Special cases */ |
1366 |
640 |
ptr = ObjGetAttr(wrk, oc, OA_HEADERS, NULL); |
1367 |
640 |
AN(ptr); |
1368 |
640 |
ptr += 4; /* Skip nhd and status */ |
1369 |
|
|
1370 |
|
/* XXX: should we also have h2_hdr_eq() ? */ |
1371 |
640 |
if (!strcmp(hdr->str, ":proto:")) |
1372 |
40 |
return (ptr); |
1373 |
600 |
ptr = strchr(ptr, '\0') + 1; |
1374 |
600 |
if (!strcmp(hdr->str, ":status:")) |
1375 |
560 |
return (ptr); |
1376 |
40 |
ptr = strchr(ptr, '\0') + 1; |
1377 |
40 |
if (!strcmp(hdr->str, ":reason:")) |
1378 |
40 |
return (ptr); |
1379 |
0 |
WRONG("Unknown magic packed header"); |
1380 |
0 |
} |
1381 |
|
|
1382 |
29507 |
HTTP_FOREACH_PACK(wrk, oc, ptr) { |
1383 |
27730 |
if (http_hdr_at(ptr, hdr->str, hdr->len)) { |
1384 |
7521 |
ptr += hdr->len; |
1385 |
15002 |
while (vct_islws(*ptr)) |
1386 |
7481 |
ptr++; |
1387 |
7521 |
return (ptr); |
1388 |
|
} |
1389 |
|
} |
1390 |
|
|
1391 |
1777 |
return (NULL); |
1392 |
9938 |
} |
1393 |
|
|
1394 |
|
/*-------------------------------------------------------------------- |
1395 |
|
* Merge any headers in the oc->OA_HEADER into the struct http if they |
1396 |
|
* are not there already. |
1397 |
|
*/ |
1398 |
|
|
1399 |
|
void |
1400 |
1120 |
HTTP_Merge(struct worker *wrk, struct objcore *oc, struct http *to) |
1401 |
|
{ |
1402 |
|
const char *ptr; |
1403 |
|
unsigned u; |
1404 |
|
const char *p; |
1405 |
|
unsigned nhd_before_merge; |
1406 |
|
|
1407 |
1120 |
CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); |
1408 |
1120 |
CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC); |
1409 |
1120 |
CHECK_OBJ_NOTNULL(to, HTTP_MAGIC); |
1410 |
|
|
1411 |
1120 |
ptr = ObjGetAttr(wrk, oc, OA_HEADERS, NULL); |
1412 |
1120 |
AN(ptr); |
1413 |
|
|
1414 |
1120 |
to->status = vbe16dec(ptr + 2); |
1415 |
1120 |
ptr += 4; |
1416 |
|
|
1417 |
6720 |
for (u = 0; u < HTTP_HDR_FIRST; u++) { |
1418 |
5600 |
if (u == HTTP_HDR_METHOD || u == HTTP_HDR_URL) |
1419 |
2240 |
continue; |
1420 |
3360 |
http_SetH(to, u, ptr); |
1421 |
3360 |
ptr = strchr(ptr, '\0') + 1; |
1422 |
3360 |
} |
1423 |
1120 |
nhd_before_merge = to->nhd; |
1424 |
6600 |
while (*ptr != '\0') { |
1425 |
5480 |
p = strchr(ptr, ':'); |
1426 |
5480 |
AN(p); |
1427 |
5480 |
u = http_findhdr(to, p - ptr, ptr); |
1428 |
5480 |
if (u == 0 || u >= nhd_before_merge) |
1429 |
2440 |
http_SetHeader(to, ptr); |
1430 |
5480 |
ptr = strchr(ptr, '\0') + 1; |
1431 |
|
} |
1432 |
1120 |
} |
1433 |
|
|
1434 |
|
/*--------------------------------------------------------------------*/ |
1435 |
|
|
1436 |
|
static void |
1437 |
272978 |
http_linkh(const struct http *to, const struct http *fm, unsigned n) |
1438 |
|
{ |
1439 |
|
|
1440 |
272978 |
assert(n < HTTP_HDR_FIRST); |
1441 |
272978 |
Tcheck(fm->hd[n]); |
1442 |
272978 |
to->hd[n] = fm->hd[n]; |
1443 |
272978 |
to->hdf[n] = fm->hdf[n]; |
1444 |
272978 |
http_VSLH(to, n); |
1445 |
272978 |
} |
1446 |
|
|
1447 |
|
/*--------------------------------------------------------------------*/ |
1448 |
|
|
1449 |
|
void |
1450 |
91000 |
http_FilterReq(struct http *to, const struct http *fm, unsigned how) |
1451 |
|
{ |
1452 |
|
unsigned u; |
1453 |
|
|
1454 |
91000 |
CHECK_OBJ_NOTNULL(to, HTTP_MAGIC); |
1455 |
91000 |
CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC); |
1456 |
|
|
1457 |
91000 |
http_linkh(to, fm, HTTP_HDR_METHOD); |
1458 |
91000 |
http_linkh(to, fm, HTTP_HDR_URL); |
1459 |
91000 |
http_linkh(to, fm, HTTP_HDR_PROTO); |
1460 |
91000 |
to->protover = fm->protover; |
1461 |
91000 |
to->status = fm->status; |
1462 |
|
|
1463 |
91000 |
to->nhd = HTTP_HDR_FIRST; |
1464 |
481211 |
for (u = HTTP_HDR_FIRST; u < fm->nhd; u++) { |
1465 |
390211 |
Tcheck(fm->hd[u]); |
1466 |
390211 |
if (http_isfiltered(fm, u, how)) |
1467 |
4440 |
continue; |
1468 |
385771 |
assert (to->nhd < to->shd); |
1469 |
385771 |
to->hd[to->nhd] = fm->hd[u]; |
1470 |
385771 |
to->hdf[to->nhd] = 0; |
1471 |
385771 |
http_VSLH(to, to->nhd); |
1472 |
385771 |
to->nhd++; |
1473 |
385771 |
} |
1474 |
91000 |
} |
1475 |
|
|
1476 |
|
/*-------------------------------------------------------------------- |
1477 |
|
* This function copies any header fields which reference foreign |
1478 |
|
* storage into our own WS. |
1479 |
|
*/ |
1480 |
|
|
1481 |
|
void |
1482 |
89753 |
http_CopyHome(const struct http *hp) |
1483 |
|
{ |
1484 |
|
unsigned u, l; |
1485 |
|
const char *p; |
1486 |
|
|
1487 |
975074 |
for (u = 0; u < hp->nhd; u++) { |
1488 |
885321 |
if (hp->hd[u].b == NULL) { |
1489 |
179509 |
assert(u < HTTP_HDR_FIRST); |
1490 |
179509 |
continue; |
1491 |
|
} |
1492 |
|
|
1493 |
705812 |
l = Tlen(hp->hd[u]); |
1494 |
705812 |
if (WS_Allocated(hp->ws, hp->hd[u].b, l)) |
1495 |
56438 |
continue; |
1496 |
|
|
1497 |
649374 |
p = WS_Copy(hp->ws, hp->hd[u].b, l + 1L); |
1498 |
649374 |
if (p == NULL) { |
1499 |
0 |
http_fail(hp); |
1500 |
0 |
VSLbs(hp->vsl, SLT_LostHeader, TOSTRAND(hp->hd[u].b)); |
1501 |
0 |
return; |
1502 |
|
} |
1503 |
649374 |
hp->hd[u].b = p; |
1504 |
649374 |
hp->hd[u].e = p + l; |
1505 |
649374 |
} |
1506 |
89753 |
} |
1507 |
|
|
1508 |
|
/*--------------------------------------------------------------------*/ |
1509 |
|
|
1510 |
|
void |
1511 |
370417 |
http_SetHeader(struct http *to, const char *header) |
1512 |
|
{ |
1513 |
|
|
1514 |
370417 |
CHECK_OBJ_NOTNULL(to, HTTP_MAGIC); |
1515 |
370417 |
if (to->nhd >= to->shd) { |
1516 |
40 |
VSLbs(to->vsl, SLT_LostHeader, TOSTRAND(header)); |
1517 |
40 |
http_fail(to); |
1518 |
40 |
return; |
1519 |
|
} |
1520 |
370377 |
http_SetH(to, to->nhd++, header); |
1521 |
370417 |
} |
1522 |
|
|
1523 |
|
/*--------------------------------------------------------------------*/ |
1524 |
|
|
1525 |
|
void |
1526 |
165353 |
http_ForceHeader(struct http *to, hdr_t hdr, const char *val) |
1527 |
|
{ |
1528 |
|
|
1529 |
165353 |
CHECK_OBJ_NOTNULL(to, HTTP_MAGIC); |
1530 |
165353 |
if (http_HdrIs(to, hdr, val)) |
1531 |
14800 |
return; |
1532 |
150553 |
http_Unset(to, hdr); |
1533 |
150553 |
http_PrintfHeader(to, "%s %s", hdr->str, val); |
1534 |
165353 |
} |
1535 |
|
|
1536 |
|
void |
1537 |
423139 |
http_AppendHeader(struct http *to, hdr_t hdr, const char *val) |
1538 |
|
{ |
1539 |
|
const char *old; |
1540 |
|
|
1541 |
423139 |
http_CollectHdr(to, hdr); |
1542 |
423139 |
if (http_GetHdr(to, hdr, &old)) { |
1543 |
1920 |
http_Unset(to, hdr); |
1544 |
1920 |
http_PrintfHeader(to, "%s %s, %s", hdr->str, old, val); |
1545 |
1920 |
} else { |
1546 |
421219 |
http_PrintfHeader(to, "%s %s", hdr->str, val); |
1547 |
|
} |
1548 |
423139 |
} |
1549 |
|
|
1550 |
|
void |
1551 |
994749 |
http_PrintfHeader(struct http *to, const char *fmt, ...) |
1552 |
|
{ |
1553 |
|
va_list ap, ap2; |
1554 |
|
struct vsb vsb[1]; |
1555 |
|
size_t sz; |
1556 |
|
char *p; |
1557 |
|
|
1558 |
994749 |
CHECK_OBJ_NOTNULL(to, HTTP_MAGIC); |
1559 |
|
|
1560 |
994749 |
va_start(ap, fmt); |
1561 |
994749 |
va_copy(ap2, ap); |
1562 |
|
|
1563 |
994749 |
WS_VSB_new(vsb, to->ws); |
1564 |
994749 |
VSB_vprintf(vsb, fmt, ap); |
1565 |
994749 |
p = WS_VSB_finish(vsb, to->ws, &sz); |
1566 |
|
|
1567 |
994749 |
if (p == NULL || to->nhd >= to->shd) { |
1568 |
1101 |
http_fail(to); |
1569 |
1101 |
VSLbv(to->vsl, SLT_LostHeader, fmt, ap2); |
1570 |
1101 |
} else { |
1571 |
993662 |
http_SetH(to, to->nhd++, p); |
1572 |
|
} |
1573 |
994763 |
va_end(ap); |
1574 |
994763 |
va_end(ap2); |
1575 |
994763 |
} |
1576 |
|
|
1577 |
|
void |
1578 |
41239 |
http_TimeHeader(struct http *to, const char *fmt, vtim_real now) |
1579 |
|
{ |
1580 |
|
char *p; |
1581 |
|
|
1582 |
41239 |
CHECK_OBJ_NOTNULL(to, HTTP_MAGIC); |
1583 |
41239 |
if (to->nhd >= to->shd) { |
1584 |
0 |
VSLbs(to->vsl, SLT_LostHeader, TOSTRAND(fmt)); |
1585 |
0 |
http_fail(to); |
1586 |
0 |
return; |
1587 |
|
} |
1588 |
41239 |
p = WS_Alloc(to->ws, strlen(fmt) + VTIM_FORMAT_SIZE); |
1589 |
41239 |
if (p == NULL) { |
1590 |
3080 |
http_fail(to); |
1591 |
3080 |
VSLbs(to->vsl, SLT_LostHeader, TOSTRAND(fmt)); |
1592 |
3080 |
return; |
1593 |
|
} |
1594 |
38159 |
strcpy(p, fmt); |
1595 |
38159 |
VTIM_format(now, strchr(p, '\0')); |
1596 |
38159 |
http_SetH(to, to->nhd++, p); |
1597 |
41239 |
} |
1598 |
|
|
1599 |
|
const char * |
1600 |
276087 |
http_ViaHeader(void) |
1601 |
|
{ |
1602 |
|
|
1603 |
276087 |
return (via_hdr); |
1604 |
|
} |
1605 |
|
|
1606 |
|
/*--------------------------------------------------------------------*/ |
1607 |
|
|
1608 |
|
void |
1609 |
907823 |
http_Unset(struct http *hp, hdr_t hdr) |
1610 |
|
{ |
1611 |
|
uint16_t u, v; |
1612 |
|
|
1613 |
5872785 |
for (v = u = HTTP_HDR_FIRST; u < hp->nhd; u++) { |
1614 |
4964962 |
Tcheck(hp->hd[u]); |
1615 |
4964962 |
if (http_IsHdr(&hp->hd[u], hdr)) { |
1616 |
37920 |
http_VSLH_del(hp, u); |
1617 |
37920 |
continue; |
1618 |
|
} |
1619 |
4927042 |
if (v != u) { |
1620 |
97680 |
memcpy(&hp->hd[v], &hp->hd[u], sizeof *hp->hd); |
1621 |
97680 |
memcpy(&hp->hdf[v], &hp->hdf[u], sizeof *hp->hdf); |
1622 |
97680 |
} |
1623 |
4927042 |
v++; |
1624 |
4927042 |
} |
1625 |
907823 |
hp->nhd = v; |
1626 |
907823 |
} |