source: bin/varnishd/cache_http.c @ 6a3a2c

Revision 6a3a2c, 18.8 KB checked in by Dag Erling Smørgrav <des@…>, 7 years ago (diff)

Improve the readability and debuggability of our tag conversion tricks.

git-svn-id:  http://www.varnish-cache.org/svn/trunk@1371 d4fa192b-c00b-0410-8231-f00ffab90ce4

  • Property mode set to 100644
Line 
1/*-
2 * Copyright (c) 2006 Verdens Gang AS
3 * Copyright (c) 2006 Linpro AS
4 * All rights reserved.
5 *
6 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * $Id$
30 *
31 * HTTP request storage and manipulation
32 */
33
34#include <stdio.h>
35#include <errno.h>
36#include <unistd.h>
37#include <stdarg.h>
38#include <stdlib.h>
39#include <string.h>
40#include <ctype.h>
41
42#include "heritage.h"
43#include "shmlog.h"
44#include "cache.h"
45
46#define HTTPH(a, b, c, d, e, f, g) char b[] = "*" a ":";
47#include "http_headers.h"
48#undef HTTPH
49
50enum httptag {
51        HTTP_T_Request,
52        HTTP_T_Response,
53        HTTP_T_Status,
54        HTTP_T_URL,
55        HTTP_T_Protocol,
56        HTTP_T_Header,
57        HTTP_T_LostHeader,
58};
59
60#define LOGMTX2(ax, bx)         \
61        [HTTP_T_##bx] = SLT_##ax##bx
62
63#define LOGMTX1(ax) {           \
64        LOGMTX2(ax, Request),   \
65        LOGMTX2(ax, Response),  \
66        LOGMTX2(ax, Status),    \
67        LOGMTX2(ax, URL),       \
68        LOGMTX2(ax, Protocol),  \
69        LOGMTX2(ax, Header),    \
70        LOGMTX2(ax, LostHeader) \
71        }
72
73static enum shmlogtag logmtx[3][7] = {
74        [HTTP_Rx] = LOGMTX1(Rx),
75        [HTTP_Tx] = LOGMTX1(Tx),
76        [HTTP_Obj] = LOGMTX1(Obj)
77};
78
79static enum shmlogtag
80http2shmlog(struct http *hp, enum httptag t)
81{
82
83        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
84        assert(hp->logtag >= HTTP_Rx && hp->logtag <= HTTP_Obj);
85        assert(t >= HTTP_T_Request && t <= HTTP_T_LostHeader);
86        return (logmtx[hp->logtag][t]);
87}
88
89static void
90WSLH(struct worker *w, enum httptag t, unsigned xid, struct http *hp, int hdr)
91{
92
93        WSLR(w, http2shmlog(hp, t), xid, hp->hd[hdr].b, hp->hd[hdr].e);
94}
95
96/*--------------------------------------------------------------------*/
97
98void
99http_Setup(struct http *hp, void *space, unsigned len)
100{
101        char *sp = space;
102
103        assert(len > 0);
104        memset(hp, 0, sizeof *hp);
105        hp->magic = HTTP_MAGIC;
106        hp->s = sp;
107        hp->t = sp;
108        hp->v = sp;
109        hp->f = sp;
110        hp->e = sp + len;
111        hp->nhd = HTTP_HDR_FIRST;
112}
113
114/*--------------------------------------------------------------------*/
115
116
117static int
118http_IsHdr(struct http_hdr *hh, char *hdr)
119{
120        unsigned l;
121
122        AN(hh->b);
123        AN(hh->e);
124        AN(hdr);
125        l = hdr[0];
126        assert(l == strlen(hdr + 1));
127        assert(hdr[l] == ':');
128        hdr++;
129        return (!strncasecmp(hdr, hh->b, l));
130}
131
132/*--------------------------------------------------------------------*/
133
134static unsigned
135http_findhdr(struct http *hp, unsigned l, const char *hdr)
136{
137        unsigned u;
138
139        for (u = HTTP_HDR_FIRST; u < hp->nhd; u++) {
140                AN(hp->hd[u].b);
141                AN(hp->hd[u].e);
142                if (hp->hd[u].e < hp->hd[u].b + l + 1)
143                        continue;
144                if (hp->hd[u].b[l] != ':')
145                        continue;
146                if (strncasecmp(hdr, hp->hd[u].b, l))
147                        continue;
148                return (u);
149        }
150        return (0);
151}
152
153int
154http_GetHdr(struct http *hp, const char *hdr, char **ptr)
155{
156        unsigned u, l;
157        char *p;
158
159        l = hdr[0];
160        assert(l == strlen(hdr + 1));
161        assert(hdr[l] == ':');
162        hdr++;
163        u = http_findhdr(hp, l - 1, hdr);
164        if (u == 0) {
165                *ptr = NULL;
166                return (0);
167        }
168        p = hp->hd[u].b + l;
169        while (isspace(*p))
170                p++;
171        *ptr = p;
172        return (1);
173}
174
175/*--------------------------------------------------------------------*/
176
177int
178http_GetHdrField(struct http *hp, const char *hdr, const char *field, char **ptr)
179{
180        char *h;
181        int fl;
182
183        if (!http_GetHdr(hp, hdr, &h))
184                return (0);
185        fl = strlen(field);
186        while (*h) {
187                if (isspace(*h)) {
188                        h++;
189                        continue;
190                }
191                if (*h == ',') {
192                        h++;
193                        continue;
194                }
195                if (memcmp(h, field, fl) ||
196                    isalpha(h[fl]) || h[fl] == '-') {
197                        while (*h && !(isspace(*h) || *h == ','))
198                                h++;
199                        continue;
200                }
201                if (h[fl] == '=')
202                        *ptr = &h[fl + 1];
203                else
204                        *ptr = NULL;
205                return (1);
206        }
207        return (0);
208}
209
210/*--------------------------------------------------------------------*/
211
212void
213http_DoConnection(struct sess *sp)
214{
215        struct http *hp = sp->http;
216        char *p, *q;
217        int i;
218        unsigned u;
219
220        if (!http_GetHdr(hp, H_Connection, &p)) {
221                if (strcmp(hp->hd[HTTP_HDR_PROTO].b, "HTTP/1.1"))
222                        sp->doclose = "not HTTP/1.1";
223                return;
224        }
225        for (; *p; p++) {
226                if (isspace(*p))
227                        continue;
228                if (*p == ',')
229                        continue;
230                for (q = p + 1; *q; q++)
231                        if (*q == ',' || isspace(*q))
232                                break;
233                i = q - p;
234                if (i == 5 && !strncasecmp(p, "close", i))
235                        sp->doclose = "Connection: close";
236                u = http_findhdr(hp, i, p);
237                if (u != 0)
238                        hp->hdf[u] |= HDF_FILTER;
239                if (!*q)
240                        break;
241                p = q;
242        }
243}
244
245/*--------------------------------------------------------------------*/
246
247int
248http_HdrIs(struct http *hp, const char *hdr, const char *val)
249{
250        char *p;
251
252        if (!http_GetHdr(hp, hdr, &p))
253                return (0);
254        AN(p);
255        if (!strcasecmp(p, val))
256                return (1);
257        return (0);
258}
259
260/*--------------------------------------------------------------------*/
261
262int
263http_GetTail(struct http *hp, unsigned len, char **b, char **e)
264{
265
266        if (hp->t >= hp->v)
267                return (0);
268
269        if (len == 0)
270                len = hp->v - hp->t;
271
272        if (hp->t + len > hp->v)
273                len = hp->v - hp->t;
274        if (len == 0)
275                return (0);
276        *b = hp->t;
277        *e = hp->t + len;
278        hp->t += len;
279        assert(hp->t <= hp->v);
280        return (1);
281}
282
283/*--------------------------------------------------------------------*/
284/* Read from fd, but soak up any tail first */
285
286int
287http_Read(struct http *hp, int fd, void *p, unsigned len)
288{
289        int i;
290        int u;
291        char *b = p;
292
293        u = 0;
294        if (hp->t < hp->v) {
295                u = hp->v - hp->t;
296                if (u > len)
297                        u = len;
298                memcpy(b, hp->t, u);
299                hp->t += u;
300                b += u;
301                len -= u;
302        }
303        if (len > 0) {
304                i = read(fd, b, len);
305                if (i < 0)
306                        return (i);
307                u += i;
308        }
309        return (u);
310}
311
312/*--------------------------------------------------------------------*/
313
314int
315http_GetStatus(struct http *hp)
316{
317
318        AN(hp->hd[HTTP_HDR_STATUS].b);
319        return (strtoul(hp->hd[HTTP_HDR_STATUS].b,
320            NULL /* XXX */, 10));
321}
322
323/*---------------------------------------------------------------------
324 * All 1xx (informational), 204 (no content), and 304 (not modified)
325 * responses MUST NOT include a message-body.
326 */
327
328int
329http_IsBodyless(struct http *hp)
330{
331        int status;
332
333        status = http_GetStatus(hp);
334        return (status >= 100 && status < 200)
335                || status == 204 || status == 304;
336}
337
338/*--------------------------------------------------------------------
339 * Dissect the headers of the HTTP protocol message.
340 * Detect conditionals (headers which start with '^[Ii][Ff]-')
341 */
342
343static int
344http_dissect_hdrs(struct worker *w, struct http *hp, int fd, char *p)
345{
346        char *q, *r;
347
348        if (*p == '\r')
349                p++;
350
351        hp->nhd = HTTP_HDR_FIRST;
352        hp->conds = 0;
353        r = NULL;               /* For FlexeLint */
354        assert(p < hp->v);      /* http_header_complete() guarantees this */
355        for (; p < hp->v; p = r) {
356                /* XXX: handle continuation lines */
357                q = strchr(p, '\n');
358                assert(q != NULL);
359                r = q + 1;
360                if (q > p && q[-1] == '\r')
361                        q--;
362                *q = '\0';
363                if (p == q)
364                        break;
365
366                if ((p[0] == 'i' || p[0] == 'I') &&
367                    (p[1] == 'f' || p[1] == 'F') &&
368                    p[2] == '-')
369                        hp->conds = 1;
370
371                if (hp->nhd < HTTP_HDR_MAX) {
372                        hp->hdf[hp->nhd] = 0;
373                        hp->hd[hp->nhd].b = p;
374                        hp->hd[hp->nhd].e = q;
375                        WSLH(w, HTTP_T_Header, fd, hp, hp->nhd);
376                        hp->nhd++;
377                } else {
378                        VSL_stats->losthdr++;
379                        WSLR(w, http2shmlog(hp, HTTP_T_LostHeader), fd, p, q);
380                }
381        }
382        assert(hp->t <= hp->v);
383        assert(hp->t == r);
384        return (0);
385}
386
387/*--------------------------------------------------------------------*/
388
389int
390http_DissectRequest(struct worker *w, struct http *hp, int fd)
391{
392        char *p;
393
394        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
395        AN(hp->t);
396        assert(hp->s < hp->t);
397        assert(hp->t <= hp->v);
398        hp->logtag = HTTP_Rx;
399
400        for (p = hp->s ; isspace(*p); p++)
401                continue;
402
403        /* First, the request type (GET/HEAD etc) */
404        hp->hd[HTTP_HDR_REQ].b = p;
405        for (; isalpha(*p); p++)
406                ;
407        hp->hd[HTTP_HDR_REQ].e = p;
408        WSLH(w, HTTP_T_Request, fd, hp, HTTP_HDR_REQ);
409        *p++ = '\0';
410
411        /* Next find the URI */
412        while (isspace(*p) && *p != '\n')
413                p++;
414        if (*p == '\n') {
415                WSLR(w, SLT_HttpGarbage, fd, hp->s, hp->v);
416                return (400);
417        }
418        hp->hd[HTTP_HDR_URL].b = p;
419        while (!isspace(*p))
420                p++;
421        hp->hd[HTTP_HDR_URL].e = p;
422        WSLH(w, HTTP_T_URL, fd, hp, HTTP_HDR_URL);
423        if (*p == '\n') {
424                WSLR(w, SLT_HttpGarbage, fd, hp->s, hp->v);
425                return (400);
426        }
427        *p++ = '\0';
428
429        /* Finally, look for protocol */
430        while (isspace(*p) && *p != '\n')
431                p++;
432        if (*p == '\n') {
433                WSLR(w, SLT_HttpGarbage, fd, hp->s, hp->v);
434                return (400);
435        }
436        hp->hd[HTTP_HDR_PROTO].b = p;
437        while (!isspace(*p))
438                p++;
439        hp->hd[HTTP_HDR_PROTO].e = p;
440        WSLH(w, HTTP_T_Protocol, fd, hp, HTTP_HDR_PROTO);
441        if (*p != '\n')
442                *p++ = '\0';
443        while (isspace(*p) && *p != '\n')
444                p++;
445        if (*p != '\n') {
446                WSLR(w, SLT_HttpGarbage, fd, hp->s, hp->v);
447                return (400);
448        }
449        *p++ = '\0';
450
451        return (http_dissect_hdrs(w, hp, fd, p));
452}
453
454/*--------------------------------------------------------------------*/
455
456int
457http_DissectResponse(struct worker *w, struct http *hp, int fd)
458{
459        char *p, *q;
460
461        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
462        AN(hp->t);
463        assert(hp->s < hp->t);
464        assert(hp->t <= hp->v);
465        hp->logtag = HTTP_Rx;
466
467        for (p = hp->s ; isspace(*p); p++)
468                continue;
469
470        if (memcmp(p, "HTTP/1.", 7)) {
471                WSLR(w, SLT_HttpGarbage, fd, hp->s, hp->v);
472                return (400);
473        }
474        /* First, protocol */
475        hp->hd[HTTP_HDR_PROTO].b = p;
476        while (!isspace(*p))
477                p++;
478        hp->hd[HTTP_HDR_PROTO].e = p;
479        WSLH(w, HTTP_T_Protocol, fd, hp, HTTP_HDR_PROTO);
480        *p++ = '\0';
481
482        /* Next find the status */
483        while (isspace(*p))
484                p++;
485        hp->hd[HTTP_HDR_STATUS].b = p;
486        while (!isspace(*p))
487                p++;
488        hp->hd[HTTP_HDR_STATUS].e = p;
489        WSLH(w, HTTP_T_Status, fd, hp, HTTP_HDR_STATUS);
490        *p++ = '\0';
491
492        /* Next find the response */
493        while (isspace(*p))
494                p++;
495        hp->hd[HTTP_HDR_RESPONSE].b = p;
496        while (*p != '\n')
497                p++;
498        for (q = p; q > hp->hd[HTTP_HDR_RESPONSE].b &&
499            isspace(q[-1]); q--)
500                continue;
501        *q = '\0';
502        hp->hd[HTTP_HDR_RESPONSE].e = q;
503        WSLH(w, HTTP_T_Response, fd, hp, HTTP_HDR_RESPONSE);
504        p++;
505
506        return (http_dissect_hdrs(w, hp, fd, p));
507}
508
509/*--------------------------------------------------------------------*/
510
511static int
512http_header_complete(struct http *hp)
513{
514        char *p;
515
516        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
517        assert(hp->v <= hp->e);
518        assert(*hp->v == '\0');
519        /* Skip any leading white space */
520        for (p = hp->s ; p < hp->v && isspace(*p); p++)
521                continue;
522        if (p >= hp->v) {
523                hp->v = hp->s;
524                return (0);
525        }
526        while (1) {
527                /* XXX: we could save location of all linebreaks for later */
528                p = strchr(p, '\n');
529                if (p == NULL)
530                        return (0);
531                p++;
532                if (*p == '\r')
533                        p++;
534                if (*p != '\n')
535                        continue;
536                break;
537        }
538        if (++p > hp->v)
539                return (0);
540        hp->t = p;
541        assert(hp->t > hp->s);
542        assert(hp->t <= hp->v);
543        return (1);
544}
545
546/*--------------------------------------------------------------------*/
547
548void
549http_RecvPrep(struct http *hp)
550{
551        unsigned l;
552
553        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
554        assert(hp->v <= hp->e);
555        assert(hp->t <= hp->v);
556        if (hp->t > hp->s && hp->t < hp->v) {
557                l = hp->v - hp->t;
558                memmove(hp->s, hp->t, l);
559                hp->v = hp->s + l;
560                hp->t = hp->s;
561                *hp->v = '\0';
562        } else  {
563                hp->v = hp->s;
564                hp->t = hp->s;
565        }
566}
567
568int
569http_RecvPrepAgain(struct http *hp)
570{
571        http_RecvPrep(hp);
572        if (hp->v == hp->s)
573                return (0);
574        return (http_header_complete(hp));
575}
576
577/*--------------------------------------------------------------------*/
578
579int
580http_RecvSome(int fd, struct http *hp)
581{
582        unsigned l;
583        int i;
584
585        l = (hp->e - hp->s) / 2;
586        if (l < hp->v - hp->s)
587                l = 0;
588        else
589                l -= hp->v - hp->s;
590        if (l <= 1) {
591                VSL(SLT_HttpError, fd, "Received too much");
592                VSLR(SLT_HttpGarbage, fd, hp->s, hp->v);
593                hp->t = NULL;
594                return (1);
595        }
596        errno = 0;
597        i = read(fd, hp->v, l - 1);
598        if (i > 0) {
599                hp->v += i;
600                *hp->v = '\0';
601                if (http_header_complete(hp))
602                        return(0);
603                return (-1);
604        }
605
606        if (hp->v != hp->s) {
607                VSL(SLT_HttpError, fd,
608                    "Received (only) %d bytes, errno %d",
609                    hp->v - hp->s, errno);
610                VSLR(SLT_Debug, fd, hp->s, hp->v);
611        } else if (errno == 0)
612                VSL(SLT_HttpError, fd, "Received nothing");
613        else
614                VSL(SLT_HttpError, fd,
615                    "Received errno %d", errno);
616        hp->t = NULL;
617        return(2);
618}
619
620/*--------------------------------------------------------------------*/
621
622int
623http_RecvHead(struct http *hp, int fd)
624{
625        int i;
626
627        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
628        http_RecvPrep(hp);
629        do
630                i = http_RecvSome(fd, hp);
631        while (i == -1);
632        return (i);
633}
634
635/*--------------------------------------------------------------------
636 * Copy HTTP headers into malloc'ed space.
637 */
638
639void
640http_CopyHttp(struct http *to, struct http *fm)
641{
642        unsigned u, l;
643
644        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
645        CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC);
646        l = 0;
647        for (u = 0; u < fm->nhd; u++) {
648                if (fm->hd[u].b == NULL)
649                        continue;
650                AN(fm->hd[u].e);
651                l += (fm->hd[u].e - fm->hd[u].b) + 1;
652        }
653        to->s = malloc(l);
654        XXXAN(to->s);
655        to->e = to->s + l;
656        to->f = to->s;
657        for (u = 0; u < fm->nhd; u++) {
658                if (fm->hd[u].b == NULL)
659                        continue;
660                AN(fm->hd[u].e);
661                assert(*fm->hd[u].e == '\0');
662                l = fm->hd[u].e - fm->hd[u].b;
663                assert(l == strlen(fm->hd[u].b));
664                memcpy(to->f, fm->hd[u].b, l);
665                to->hd[u].b = to->f;
666                to->hd[u].e = to->f + l;
667                *to->hd[u].e = '\0';
668                to->f += l + 1;
669        }
670        to->nhd = fm->nhd;
671}
672
673/*--------------------------------------------------------------------*/
674
675static void
676http_seth(struct worker *w, int fd, struct http *to, unsigned n, enum httptag tag, const char *fm)
677{
678
679        assert(n < HTTP_HDR_MAX);
680        AN(fm);
681        to->hd[n].b = (void*)(uintptr_t)fm;
682        to->hd[n].e = (void*)(uintptr_t)strchr(fm, '\0');
683        to->hdf[n] = 0;
684        WSLH(w, tag, fd, to, n);
685}
686
687static void
688http_copyh(struct worker *w, int fd, struct http *to, struct http *fm, unsigned n, enum httptag tag)
689{
690
691        assert(n < HTTP_HDR_MAX);
692        AN(fm->hd[n].b);
693        to->hd[n].b = fm->hd[n].b;
694        to->hd[n].e = fm->hd[n].e;
695        to->hdf[n] = fm->hdf[n];
696        WSLH(w, tag, fd, to, n);
697}
698
699void
700http_GetReq(struct worker *w, int fd, struct http *to, struct http *fm)
701{
702
703        CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC);
704        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
705        http_seth(w, fd, to, HTTP_HDR_REQ, HTTP_T_Request, "GET");
706        http_copyh(w, fd, to, fm, HTTP_HDR_URL, HTTP_T_URL);
707        http_seth(w, fd, to, HTTP_HDR_PROTO, HTTP_T_Protocol, "HTTP/1.1");
708}
709
710void
711http_CopyReq(struct worker *w, int fd, struct http *to, struct http *fm)
712{
713
714        CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC);
715        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
716        http_copyh(w, fd, to, fm, HTTP_HDR_REQ, HTTP_T_Request);
717        http_copyh(w, fd, to, fm, HTTP_HDR_URL, HTTP_T_URL);
718        if (params->backend_http11)
719                http_seth(w, fd, to, HTTP_HDR_PROTO, HTTP_T_Protocol, "HTTP/1.1");
720        else
721                http_copyh(w, fd, to, fm, HTTP_HDR_PROTO, HTTP_T_Protocol);
722}
723
724
725void
726http_CopyResp(struct worker *w, int fd, struct http *to, struct http *fm)
727{
728
729        CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC);
730        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
731        if (params->client_http11)
732                http_seth(w, fd, to, HTTP_HDR_PROTO, HTTP_T_Protocol, "HTTP/1.1");
733        else
734                http_copyh(w, fd, to, fm, HTTP_HDR_PROTO, HTTP_T_Protocol);
735        http_copyh(w, fd, to, fm, HTTP_HDR_STATUS, HTTP_T_Status);
736        http_copyh(w, fd, to, fm, HTTP_HDR_RESPONSE, HTTP_T_Response);
737}
738
739void
740http_SetResp(struct worker *w, int fd, struct http *to, const char *proto, const char *status, const char *response)
741{
742        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
743        http_seth(w, fd, to, HTTP_HDR_PROTO, HTTP_T_Protocol, proto);
744        http_seth(w, fd, to, HTTP_HDR_STATUS, HTTP_T_Status, status);
745        http_seth(w, fd, to, HTTP_HDR_RESPONSE, HTTP_T_Response, response);
746}
747
748static void
749http_copyheader(struct worker *w, int fd, struct http *to, struct http *fm, unsigned n)
750{
751
752        CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC);
753        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
754        assert(n < HTTP_HDR_MAX);
755        AN(fm->hd[n].b);
756        if (to->nhd < HTTP_HDR_MAX) {
757                to->hd[to->nhd].b = fm->hd[n].b;
758                to->hd[to->nhd].e = fm->hd[n].e;
759                WSLH(w, HTTP_T_Header, fd, to, to->nhd);
760                to->nhd++;
761        } else  {
762                VSL_stats->losthdr++;
763                WSLH(w, HTTP_T_LostHeader, fd, fm, n);
764        }
765}
766
767/*--------------------------------------------------------------------*/
768
769void
770http_FilterHeader(struct worker *w, int fd, struct http *to, struct http *fm, unsigned how)
771{
772        unsigned u;
773
774        CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC);
775        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
776        to->nhd = HTTP_HDR_FIRST;
777        for (u = HTTP_HDR_FIRST; u < fm->nhd; u++) {
778                if (fm->hdf[u] & HDF_FILTER)
779                        continue;
780#define HTTPH(a, b, c, d, e, f, g) \
781                if (((e) & how) && http_IsHdr(&fm->hd[u], (b))) \
782                        continue;
783#include "http_headers.h"
784#undef HTTPH
785                http_copyheader(w, fd, to, fm, u);
786        }
787}
788
789/*--------------------------------------------------------------------*/
790
791void
792http_ClrHeader(struct http *to)
793{
794
795        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
796        to->f = to->v;
797        to->nhd = HTTP_HDR_FIRST;
798        memset(to->hd, 0, sizeof to->hd);
799}
800
801/*--------------------------------------------------------------------*/
802
803void
804http_SetHeader(struct worker *w, int fd, struct http *to, const char *hdr)
805{
806
807        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
808        if (to->nhd >= HTTP_HDR_MAX) {
809                VSL_stats->losthdr++;
810                WSL(w, http2shmlog(to, HTTP_T_LostHeader), fd, "%s", hdr);
811                return;
812        }
813        http_seth(w, fd, to, to->nhd++, HTTP_T_Header, hdr);
814}
815
816/*--------------------------------------------------------------------*/
817
818void
819http_PrintfHeader(struct worker *w, int fd, struct http *to, const char *fmt, ...)
820{
821        va_list ap;
822        unsigned l, n;
823
824        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
825        va_start(ap, fmt);
826        l = to->e - to->f;
827        n = vsnprintf(to->f, l, fmt, ap);
828        if (n + 1 > l || to->nhd >= HTTP_HDR_MAX) {
829                VSL_stats->losthdr++;
830                WSL(w, http2shmlog(to, HTTP_T_LostHeader), fd, "%s", to->f);
831        } else {
832                assert(to->f < to->e);
833                to->hd[to->nhd].b = to->f;
834                to->hd[to->nhd].e = to->f + n;
835                to->f += n + 1;
836                WSLH(w, HTTP_T_Header, fd, to, to->nhd);
837                to->nhd++;
838        }
839        va_end(ap);
840}
841
842/*--------------------------------------------------------------------*/
843
844unsigned
845http_Write(struct worker *w, struct http *hp, int resp)
846{
847        unsigned u, l;
848
849        if (resp) {
850                AN(hp->hd[HTTP_HDR_STATUS].b);
851                l = WRK_WriteH(w, &hp->hd[HTTP_HDR_PROTO], " ");
852                l += WRK_WriteH(w, &hp->hd[HTTP_HDR_STATUS], " ");
853                l += WRK_WriteH(w, &hp->hd[HTTP_HDR_RESPONSE], "\r\n");
854        } else {
855                AN(hp->hd[HTTP_HDR_URL].b);
856                l = WRK_WriteH(w, &hp->hd[HTTP_HDR_REQ], " ");
857                l += WRK_WriteH(w, &hp->hd[HTTP_HDR_URL], " ");
858                l += WRK_WriteH(w, &hp->hd[HTTP_HDR_PROTO], "\r\n");
859        }
860        for (u = HTTP_HDR_FIRST; u < hp->nhd; u++) {
861                AN(hp->hd[u].b);
862                AN(hp->hd[u].e);
863                l += WRK_WriteH(w, &hp->hd[u], "\r\n");
864        }
865        l += WRK_Write(w, "\r\n", -1);
866        return (l);
867}
868
869/*--------------------------------------------------------------------*/
870
871void
872HTTP_Init(void)
873{
874#define HTTPH(a, b, c, d, e, f, g) b[0] = (char)strlen(b + 1);
875#include "http_headers.h"
876#undef HTTPH
877}
Note: See TracBrowser for help on using the repository browser.