source: bin/varnishd/cache_http.c @ b74e4b

Revision b74e4b, 19.2 KB checked in by Poul-Henning Kamp <phk@…>, 6 years ago (diff)

If the backend does not transmit a respose string, use the default
string for the status code as found in RFC2616.

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

  • Property mode set to 100644
Line 
1/*-
2 * Copyright (c) 2006 Verdens Gang AS
3 * Copyright (c) 2006-2008 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 THE 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 "config.h"
35
36#include <ctype.h>
37#include <errno.h>
38#include <unistd.h>
39#include <stdarg.h>
40#include <stdio.h>
41#include <stdlib.h>
42#include <string.h>
43#include <strings.h>
44
45#include "shmlog.h"
46#include "cache.h"
47
48#ifndef HAVE_STRLCPY
49#include <compat/strlcpy.h>
50#endif
51
52#define HTTPH(a, b, c, d, e, f, g) char b[] = "*" a ":";
53#include "http_headers.h"
54#undef HTTPH
55
56#define C_SP    (1<<0)
57#define C_CRLF  (1<<1)
58#define C_LWS   (C_CRLF | C_SP)
59#define C_CTL   (1<<2)
60
61static unsigned char vctyptab[256] = {
62        ['\t']  =       C_SP,
63        ['\n']  =       C_CRLF,
64        ['\r']  =       C_CRLF,
65        [' ']   =       C_SP,
66};
67
68static int
69vctyp(unsigned char x, unsigned char y)
70{
71
72        return (vctyptab[x] & (y));
73}
74
75#define LOGMTX2(ax, bx, cx)     [bx] = SLT_##ax##cx
76
77#define LOGMTX1(ax) {           \
78        LOGMTX2(ax, HTTP_HDR_REQ,       Request),       \
79        LOGMTX2(ax, HTTP_HDR_RESPONSE,  Response),      \
80        LOGMTX2(ax, HTTP_HDR_STATUS,    Status),        \
81        LOGMTX2(ax, HTTP_HDR_URL,       URL),           \
82        LOGMTX2(ax, HTTP_HDR_PROTO,     Protocol),      \
83        LOGMTX2(ax, HTTP_HDR_FIRST,     Header),        \
84        }
85
86static enum shmlogtag logmtx[][HTTP_HDR_FIRST + 1] = {
87        [HTTP_Rx] = LOGMTX1(Rx),
88        [HTTP_Tx] = LOGMTX1(Tx),
89        [HTTP_Obj] = LOGMTX1(Obj)
90};
91
92static enum shmlogtag
93http2shmlog(const struct http *hp, int t)
94{
95
96        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
97        if (t > HTTP_HDR_FIRST)
98                t = HTTP_HDR_FIRST;
99        assert(hp->logtag >= HTTP_Rx && hp->logtag <= HTTP_Obj); /*lint !e685*/
100        assert(t >= HTTP_HDR_REQ && t <= HTTP_HDR_FIRST);
101        return (logmtx[hp->logtag][t]);
102}
103
104static void
105WSLH(struct worker *w, int fd, const struct http *hp, unsigned hdr)
106{
107
108        WSLR(w, http2shmlog(hp, hdr), fd, hp->hd[hdr]);
109}
110
111/*--------------------------------------------------------------------*/
112/* List of canonical HTTP response code names from RFC2616 */
113
114static struct http_msg {
115        unsigned        nbr;
116        const char      *txt;
117} http_msg[] = {
118        { 101, "Switching Protocols" },
119        { 200, "OK" },
120        { 201, "Created" },
121        { 202, "Accepted" },
122        { 203, "Non-Authoritative Information" },
123        { 204, "No Content" },
124        { 205, "Reset Content" },
125        { 206, "Partial Content" },
126        { 300, "Multiple Choices" },
127        { 301, "Moved Permanently" },
128        { 302, "Found" },
129        { 303, "See Other" },
130        { 304, "Not Modified" },
131        { 305, "Use Proxy" },
132        { 306, "(Unused)" },
133        { 307, "Temporary Redirect" },
134        { 400, "Bad Request" },
135        { 401, "Unauthorized" },
136        { 402, "Payment Required" },
137        { 403, "Forbidden" },
138        { 404, "Not Found" },
139        { 405, "Method Not Allowed" },
140        { 406, "Not Acceptable" },
141        { 407, "Proxy Authentication Required" },
142        { 408, "Request Timeout" },
143        { 409, "Conflict" },
144        { 410, "Gone" },
145        { 411, "Length Required" },
146        { 412, "Precondition Failed" },
147        { 413, "Request Entity Too Large" },
148        { 414, "Request-URI Too Long" },
149        { 415, "Unsupported Media Type" },
150        { 416, "Requested Range Not Satisfiable" },
151        { 417, "Expectation Failed" },
152        { 500, "Internal Server Error" },
153        { 501, "Not Implemented" },
154        { 502, "Bad Gateway" },
155        { 503, "Service Unavailable" },
156        { 504, "Gateway Timeout" },
157        { 505, "HTTP Version Not Supported" },
158        { 0, NULL }
159};
160
161const char *
162http_StatusMessage(unsigned status)
163{
164        struct http_msg *mp;
165
166        assert(status >= 100 && status <= 999);
167        for (mp = http_msg; mp->nbr != 0 && mp->nbr <= status; mp++)
168                if (mp->nbr == status)
169                        return (mp->txt);
170        return ("Unknown Error");
171}
172
173/*--------------------------------------------------------------------*/
174
175void
176http_Setup(struct http *hp, struct ws *ws)
177{
178
179        memset(hp, 0, sizeof *hp);
180        hp->magic = HTTP_MAGIC;
181        hp->ws = ws;
182        hp->nhd = HTTP_HDR_FIRST;
183}
184
185/*--------------------------------------------------------------------*/
186
187
188static int
189http_IsHdr(const txt *hh, const char *hdr)
190{
191        unsigned l;
192
193        Tcheck(*hh);
194        AN(hdr);
195        l = hdr[0];
196        assert(l == strlen(hdr + 1));
197        assert(hdr[l] == ':');
198        hdr++;
199        return (!strncasecmp(hdr, hh->b, l));
200}
201
202/*--------------------------------------------------------------------*/
203
204static unsigned
205http_findhdr(const struct http *hp, unsigned l, const char *hdr)
206{
207        unsigned u;
208
209        for (u = HTTP_HDR_FIRST; u < hp->nhd; u++) {
210                Tcheck(hp->hd[u]);
211                if (hp->hd[u].e < hp->hd[u].b + l + 1)
212                        continue;
213                if (hp->hd[u].b[l] != ':')
214                        continue;
215                if (strncasecmp(hdr, hp->hd[u].b, l))
216                        continue;
217                return (u);
218        }
219        return (0);
220}
221
222int
223http_GetHdr(const struct http *hp, const char *hdr, char **ptr)
224{
225        unsigned u, l;
226        char *p;
227
228        l = hdr[0];
229        assert(l == strlen(hdr + 1));
230        assert(hdr[l] == ':');
231        hdr++;
232        u = http_findhdr(hp, l - 1, hdr);
233        if (u == 0) {
234                if (ptr != NULL)
235                        *ptr = NULL;
236                return (0);
237        }
238        if (ptr != NULL) {
239                p = hp->hd[u].b + l;
240                while (isspace(*p))
241                        p++;
242                *ptr = p;
243        }
244        return (1);
245}
246
247/*--------------------------------------------------------------------*/
248
249int
250http_GetHdrField(const struct http *hp, const char *hdr, const char *field, char **ptr)
251{
252        char *h;
253        unsigned fl;
254
255        if (!http_GetHdr(hp, hdr, &h))
256                return (0);
257        fl = strlen(field);
258        while (*h) {
259                if (isspace(*h)) {
260                        h++;
261                        continue;
262                }
263                if (*h == ',') {
264                        h++;
265                        continue;
266                }
267                if (memcmp(h, field, fl) ||
268                    isalpha(h[fl]) || h[fl] == '-') {
269                        while (*h && !(isspace(*h) || *h == ','))
270                                h++;
271                        continue;
272                }
273                if (h[fl] == '=')
274                        *ptr = &h[fl + 1];
275                else
276                        *ptr = NULL;
277                return (1);
278        }
279        return (0);
280}
281
282/*--------------------------------------------------------------------*/
283
284const char *
285http_DoConnection(struct http *hp)
286{
287        char *p, *q;
288        const char *ret;
289        unsigned u;
290
291        if (!http_GetHdr(hp, H_Connection, &p)) {
292                if (strcmp(hp->hd[HTTP_HDR_PROTO].b, "HTTP/1.1"))
293                        return ("not HTTP/1.1");
294                return (NULL);
295        }
296        ret = NULL;
297        for (; *p; p++) {
298                if (isspace(*p))
299                        continue;
300                if (*p == ',')
301                        continue;
302                for (q = p + 1; *q; q++)
303                        if (*q == ',' || isspace(*q))
304                                break;
305                u = pdiff(p, q);
306                if (u == 5 && !strncasecmp(p, "close", u))
307                        ret = "Connection: close";
308                u = http_findhdr(hp, u, p);
309                if (u != 0)
310                        hp->hdf[u] |= HDF_FILTER;
311                if (!*q)
312                        break;
313                p = q;
314        }
315        return (ret);
316}
317
318/*--------------------------------------------------------------------*/
319
320int
321http_HdrIs(const struct http *hp, const char *hdr, const char *val)
322{
323        char *p;
324
325        if (!http_GetHdr(hp, hdr, &p))
326                return (0);
327        AN(p);
328        if (!strcasecmp(p, val))
329                return (1);
330        return (0);
331}
332
333/*--------------------------------------------------------------------*/
334
335int
336http_GetStatus(const struct http *hp)
337{
338
339        Tcheck(hp->hd[HTTP_HDR_STATUS]);
340        return (hp->status);
341}
342
343const char *
344http_GetProto(const struct http *hp)
345{
346
347        Tcheck(hp->hd[HTTP_HDR_PROTO]);
348        return (hp->hd[HTTP_HDR_PROTO].b);
349}
350
351const char *
352http_GetReq(const struct http *hp)
353{
354
355        Tcheck(hp->hd[HTTP_HDR_REQ]);
356        return (hp->hd[HTTP_HDR_REQ].b);
357}
358
359/*--------------------------------------------------------------------
360 * Dissect the headers of the HTTP protocol message.
361 * Detect conditionals (headers which start with '^[Ii][Ff]-')
362 */
363
364static int
365http_dissect_hdrs(struct worker *w, struct http *hp, int fd, char *p, txt t)
366{
367        char *q, *r;
368
369        if (*p == '\r')
370                p++;
371
372        hp->nhd = HTTP_HDR_FIRST;
373        hp->conds = 0;
374        r = NULL;               /* For FlexeLint */
375        assert(p <= t.e);       /* http_header_complete() guarantees this */
376        for (; p < t.e; p = r) {
377                /* XXX: handle continuation lines */
378                q = strchr(p, '\n');
379                assert(q != NULL);
380                r = q + 1;
381                if (q > p && q[-1] == '\r')
382                        q--;
383                *q = '\0';
384                if (p == q)
385                        break;
386
387                if ((p[0] == 'i' || p[0] == 'I') &&
388                    (p[1] == 'f' || p[1] == 'F') &&
389                    p[2] == '-')
390                        hp->conds = 1;
391
392                if (hp->nhd < HTTP_HDR_MAX) {
393                        hp->hdf[hp->nhd] = 0;
394                        hp->hd[hp->nhd].b = p;
395                        hp->hd[hp->nhd].e = q;
396                        WSLH(w, fd, hp, hp->nhd);
397                        hp->nhd++;
398                } else {
399                        VSL_stats->losthdr++;
400                        WSL(w, SLT_LostHeader, fd, "%.*s", q - p, p);
401                }
402        }
403        return (0);
404}
405
406/*--------------------------------------------------------------------
407 * Deal with first line of HTTP protocol message.
408 */
409
410static int
411http_splitline(struct worker *w, int fd, struct http *hp, const struct http_conn *htc, int h1, int h2, int h3)
412{
413        char *p;
414
415        CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
416        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
417
418        /* XXX: Assert a NUL at rx.e ? */
419        Tcheck(htc->rxbuf);
420
421        /* Skip leading LWS */
422        for (p = htc->rxbuf.b ; vctyp(*p, C_LWS); p++)
423                continue;
424
425        /* First field cannot contain SP, CRLF or CTL */
426        hp->hd[h1].b = p;
427        for (; !vctyp(*p, C_SP); p++)
428                if (vctyp(*p, C_CRLF | C_CTL))
429                        return (400);
430        hp->hd[h1].e = p;
431
432        /* Skip SP */
433        for (; vctyp(*p, C_SP); p++)
434                ;
435
436        /* Second field cannot contain SP, CRLF or CTL */
437        hp->hd[h2].b = p;
438        for (; !vctyp(*p, C_SP); p++)
439                if (vctyp(*p, C_CRLF | C_CTL))
440                        return (400);
441        hp->hd[h2].e = p;
442
443        /* Skip SP */
444        for (; vctyp(*p, C_SP); p++)
445                ;
446
447        /* Third field is optional and cannot contain CTL */
448        if (!vctyp(*p, C_CRLF)) {
449                hp->hd[h3].b = p;
450                for (; !vctyp(*p, C_CRLF); p++)
451                        if (vctyp(*p, C_CTL))
452                                return (400);
453                hp->hd[h3].e = p;
454        } else {
455                hp->hd[h3].b = p;
456                hp->hd[h3].e = p;
457        }
458
459        /* Skip CRLF */
460        for (; vctyp(*p, C_CRLF); p++)
461                if (vctyp(*p, C_CTL))
462                        return (400);
463
464        *hp->hd[h1].e = '\0';
465        WSLH(w, fd, hp, h1);
466
467        *hp->hd[h2].e = '\0';
468        WSLH(w, fd, hp, h2);
469
470        if (hp->hd[h3].e != NULL) {
471                *hp->hd[h3].e = '\0';
472                WSLH(w, fd, hp, h3);
473        }
474
475        return (http_dissect_hdrs(w, hp, fd, p, htc->rxbuf));
476}
477
478/*--------------------------------------------------------------------*/
479
480int
481http_DissectRequest(struct sess *sp)
482{
483        struct http_conn *htc;
484        struct http *hp;
485        int i;
486
487        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
488        htc = sp->htc;
489        CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
490        hp = sp->http;
491        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
492
493        hp->logtag = HTTP_Rx;
494
495        i = http_splitline(sp->wrk, sp->fd, hp, htc,
496            HTTP_HDR_REQ, HTTP_HDR_URL, HTTP_HDR_PROTO);
497
498        if (i != 0)
499                WSPR(sp, SLT_HttpGarbage, htc->rxbuf);
500        return (i);
501}
502
503/*--------------------------------------------------------------------*/
504
505int
506http_DissectResponse(struct worker *w, const struct http_conn *htc, struct http *hp)
507{
508        int i;
509
510        CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
511        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
512        hp->logtag = HTTP_Rx;
513
514        i = http_splitline(w, htc->fd, hp, htc,
515            HTTP_HDR_PROTO, HTTP_HDR_STATUS, HTTP_HDR_RESPONSE);
516
517        if (i != 0 || memcmp(hp->hd[HTTP_HDR_PROTO].b, "HTTP/1.", 7))
518                WSLR(w, SLT_HttpGarbage, htc->fd, htc->rxbuf);
519        if (i != 0) {
520                if (hp->status == 0)
521                        hp->status = i;
522        } else {
523                hp->status = 
524                    strtoul(hp->hd[HTTP_HDR_STATUS].b, NULL /* XXX */, 10);
525        }
526        if (!Tlen(hp->hd[HTTP_HDR_RESPONSE])) {
527                /* Backend didn't send a response string, use the standard */
528                hp->hd[HTTP_HDR_RESPONSE].b = 
529                    TRUST_ME(http_StatusMessage(hp->status));
530                hp->hd[HTTP_HDR_RESPONSE].e =
531                    strchr(hp->hd[HTTP_HDR_RESPONSE].b, '\0');
532        }
533        return (i);
534}
535
536/*--------------------------------------------------------------------*/
537
538void
539http_SetH(struct http *to, unsigned n, const char *fm)
540{
541
542        assert(n < HTTP_HDR_MAX);
543        AN(fm);
544        to->hd[n].b = TRUST_ME(fm);
545        to->hd[n].e = strchr(to->hd[n].b, '\0');
546        to->hdf[n] = 0;
547}
548
549static void
550http_copyh(struct http *to, const struct http *fm, unsigned n)
551{
552
553        assert(n < HTTP_HDR_MAX);
554        Tcheck(fm->hd[n]);
555        to->hd[n] = fm->hd[n];
556        to->hdf[n] = fm->hdf[n];
557}
558
559static void
560http_copyreq(struct http *to, const struct http *fm, int transparent)
561{
562
563        CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC);
564        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
565        if (transparent)
566                http_copyh(to, fm, HTTP_HDR_REQ);
567        else
568                http_SetH(to, HTTP_HDR_REQ, "GET");
569        http_copyh(to, fm, HTTP_HDR_URL);
570        if (transparent)
571                http_copyh(to, fm, HTTP_HDR_PROTO);
572        else
573                http_SetH(to, HTTP_HDR_PROTO, "HTTP/1.1");
574}
575
576void
577http_CopyResp(struct http *to, const struct http *fm)
578{
579
580        CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC);
581        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
582        if (params->client_http11)
583                http_SetH(to, HTTP_HDR_PROTO, "HTTP/1.1");
584        else
585                http_copyh(to, fm, HTTP_HDR_PROTO);
586        http_copyh(to, fm, HTTP_HDR_STATUS);
587        http_copyh(to, fm, HTTP_HDR_RESPONSE);
588}
589
590void
591http_SetResp(struct http *to, const char *proto, const char *status, const char *response)
592{
593
594        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
595        http_SetH(to, HTTP_HDR_PROTO, proto);
596        http_SetH(to, HTTP_HDR_STATUS, status);
597        http_SetH(to, HTTP_HDR_RESPONSE, response);
598}
599
600static void
601http_copyheader(struct worker *w, int fd, struct http *to, const struct http *fm, unsigned n)
602{
603
604        CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC);
605        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
606        assert(n < HTTP_HDR_MAX);
607        Tcheck(fm->hd[n]);
608        if (to->nhd < HTTP_HDR_MAX) {
609                to->hd[to->nhd] = fm->hd[n];
610                to->nhd++;
611        } else  {
612                VSL_stats->losthdr++;
613                WSLR(w, SLT_LostHeader, fd, fm->hd[n]);
614        }
615}
616
617/*--------------------------------------------------------------------*/
618
619void
620http_FilterFields(struct worker *w, int fd, struct http *to, const struct http *fm, unsigned how)
621{
622        unsigned u;
623
624        CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC);
625        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
626        to->nhd = HTTP_HDR_FIRST;
627        to->status = fm->status;
628        for (u = HTTP_HDR_FIRST; u < fm->nhd; u++) {
629                if (fm->hdf[u] & HDF_FILTER)
630                        continue;
631#define HTTPH(a, b, c, d, e, f, g) \
632                if (((e) & how) && http_IsHdr(&fm->hd[u], (b))) \
633                        continue;
634#include "http_headers.h"
635#undef HTTPH
636                http_copyheader(w, fd, to, fm, u);
637        }
638}
639
640/*--------------------------------------------------------------------*/
641
642void
643http_FilterHeader(struct sess *sp, unsigned how)
644{
645        struct bereq *bereq;
646        struct http *hp;
647        char *b;
648
649        bereq = VBE_new_bereq();
650        AN(bereq);
651        hp = bereq->http;
652        hp->logtag = HTTP_Tx;
653
654        http_copyreq(hp, sp->http,
655            (how == HTTPH_R_PIPE) || (how == HTTPH_R_PASS));
656        http_FilterFields(sp->wrk, sp->fd, hp, sp->http, how);
657        http_PrintfHeader(sp->wrk, sp->fd, hp, "X-Varnish: %u", sp->xid);
658        http_PrintfHeader(sp->wrk, sp->fd, hp,
659            "X-Forwarded-for: %s", sp->addr);
660
661        sp->bereq = bereq;
662
663        /* XXX: This possibly ought to go into the default VCL */
664        if (!http_GetHdr(hp, H_Host, &b)) 
665                VBE_AddHostHeader(sp);
666}
667
668/*--------------------------------------------------------------------
669 * This function copies any header fields which reference foreign
670 * storage into our own WS.
671 */
672
673void
674http_CopyHome(struct worker *w, int fd, struct http *hp)
675{
676        unsigned u, l;
677        char *p;
678
679        for (u = 0; u < hp->nhd; u++) {
680                if (hp->hd[u].b == NULL)
681                        continue;
682                if (hp->hd[u].b >= hp->ws->s && hp->hd[u].e <= hp->ws->e) {
683                        WSLH(w, fd, hp, u);
684                        continue;
685                }
686                l = Tlen(hp->hd[u]);
687                p = WS_Alloc(hp->ws, l + 1);
688                if (p != NULL) {
689                        WSLH(w, fd, hp, u);
690                        memcpy(p, hp->hd[u].b, l + 1);
691                        hp->hd[u].b = p;
692                        hp->hd[u].e = p + l;
693                } else {
694                        WSLR(w, SLT_LostHeader, fd, hp->hd[u]);
695                        hp->hd[u].b = NULL;
696                        hp->hd[u].e = NULL;
697                }
698        }
699}
700
701/*--------------------------------------------------------------------*/
702
703void
704http_ClrHeader(struct http *to)
705{
706
707        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
708        /* XXX: don't to->f = to->v;  it would kill pipelining */
709        to->nhd = HTTP_HDR_FIRST;
710        memset(to->hd, 0, sizeof to->hd);
711}
712
713/*--------------------------------------------------------------------*/
714
715void
716http_SetHeader(struct worker *w, int fd, struct http *to, const char *hdr)
717{
718
719        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
720        if (to->nhd >= HTTP_HDR_MAX) {
721                VSL_stats->losthdr++;
722                WSL(w, SLT_LostHeader, fd, "%s", hdr);
723                return;
724        }
725        http_SetH(to, to->nhd++, hdr);
726}
727
728/*--------------------------------------------------------------------*/
729
730static void
731http_PutField(struct worker *w, int fd, struct http *to, int field, const char *string)
732{
733        char *p;
734        unsigned l;
735
736        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
737        l = strlen(string);
738        p = WS_Alloc(to->ws, l + 1);
739        if (p == NULL) {
740                WSL(w, SLT_LostHeader, fd, "%s", string);
741                to->hd[field].b = NULL;
742                to->hd[field].e = NULL;
743        } else {
744                memcpy(p, string, l + 1);
745                to->hd[field].b = p;
746                to->hd[field].e = p + l;
747        }
748}
749
750void
751http_PutProtocol(struct worker *w, int fd, struct http *to, const char *protocol)
752{
753
754        http_PutField(w, fd, to, HTTP_HDR_PROTO, protocol);
755}
756
757void
758http_PutStatus(struct worker *w, int fd, struct http *to, int status)
759{
760        char stat[4];
761
762        assert(status >= 0 && status <= 999);
763        sprintf(stat, "%d", status);
764        http_PutField(w, fd, to, HTTP_HDR_STATUS, stat);
765        to->status = status;
766}
767
768void
769http_PutResponse(struct worker *w, int fd, struct http *to, const char *response)
770{
771
772        http_PutField(w, fd, to, HTTP_HDR_RESPONSE, response);
773}
774
775void
776http_PrintfHeader(struct worker *w, int fd, struct http *to, const char *fmt, ...)
777{
778        va_list ap;
779        unsigned l, n;
780
781        CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
782        l = WS_Reserve(to->ws, 0);
783        va_start(ap, fmt);
784        n = vsnprintf(to->ws->f, l, fmt, ap);
785        va_end(ap);
786        if (n + 1 >= l || to->nhd >= HTTP_HDR_MAX) {
787                VSL_stats->losthdr++;
788                WSL(w, SLT_LostHeader, fd, "%s", to->ws->f);
789                WS_Release(to->ws, 0);
790        } else {
791                to->hd[to->nhd].b = to->ws->f;
792                to->hd[to->nhd].e = to->ws->f + n;
793                WS_Release(to->ws, n + 1);
794                to->nhd++;
795        }
796}
797/*--------------------------------------------------------------------*/
798
799void
800http_Unset(struct http *hp, const char *hdr)
801{
802        unsigned u, v;
803
804        for (v = u = HTTP_HDR_FIRST; u < hp->nhd; u++) {
805                if (http_IsHdr(&hp->hd[u], hdr)) 
806                        continue;
807                if (v != u)
808                        memcpy(&hp->hd[v], &hp->hd[u], sizeof hp->hd[v]);
809                v++;
810        }
811        hp->nhd = v;
812}
813
814/*--------------------------------------------------------------------*/
815
816unsigned
817http_Write(struct worker *w, const struct http *hp, int resp)
818{
819        unsigned u, l;
820
821        if (resp) {
822                AN(hp->hd[HTTP_HDR_STATUS].b);
823                l = WRK_WriteH(w, &hp->hd[HTTP_HDR_PROTO], " ");
824                WSLH(w, *w->wfd, hp, HTTP_HDR_PROTO);
825                l += WRK_WriteH(w, &hp->hd[HTTP_HDR_STATUS], " ");
826                WSLH(w, *w->wfd, hp, HTTP_HDR_STATUS);
827                l += WRK_WriteH(w, &hp->hd[HTTP_HDR_RESPONSE], "\r\n");
828                WSLH(w, *w->wfd, hp, HTTP_HDR_RESPONSE);
829        } else {
830                AN(hp->hd[HTTP_HDR_URL].b);
831                l = WRK_WriteH(w, &hp->hd[HTTP_HDR_REQ], " ");
832                WSLH(w, *w->wfd, hp, HTTP_HDR_REQ);
833                l += WRK_WriteH(w, &hp->hd[HTTP_HDR_URL], " ");
834                WSLH(w, *w->wfd, hp, HTTP_HDR_URL);
835                l += WRK_WriteH(w, &hp->hd[HTTP_HDR_PROTO], "\r\n");
836                WSLH(w, *w->wfd, hp, HTTP_HDR_PROTO);
837        }
838        for (u = HTTP_HDR_FIRST; u < hp->nhd; u++) {
839                AN(hp->hd[u].b);
840                AN(hp->hd[u].e);
841                l += WRK_WriteH(w, &hp->hd[u], "\r\n");
842                WSLH(w, *w->wfd, hp, u);
843        }
844        l += WRK_Write(w, "\r\n", -1);
845        return (l);
846}
847
848/*--------------------------------------------------------------------*/
849
850void
851HTTP_Init(void)
852{
853        int i;
854#define HTTPH(a, b, c, d, e, f, g) b[0] = (char)strlen(b + 1);
855#include "http_headers.h"
856#undef HTTPH
857
858        for (i = 1; i < 32; i++)
859                if (vctyptab[i] == 0)
860                        vctyptab[i] = C_CTL;
861        vctyptab[127] = C_CTL;
862}
Note: See TracBrowser for help on using the repository browser.