lsquic_http1x_if.c revision 06b2a236
1/* Copyright (c) 2017 - 2021 LiteSpeed Technologies Inc.  See LICENSE. */
2#include <assert.h>
3#include <ctype.h>
4#include <stddef.h>
5#include <stdlib.h>
6#include <string.h>
7
8#include "lsquic.h"
9#include "lsquic_headers.h"
10#include "lsquic_http1x_if.h"
11#include "lshpack.h"
12
13#define LSQUIC_LOGGER_MODULE LSQLM_HTTP1X
14#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(hwc->hwc_conn)
15#include "lsquic_logger.h"
16
17enum pseudo_header
18{
19    PSEH_METHOD,
20    PSEH_SCHEME,
21    PSEH_AUTHORITY,
22    PSEH_PATH,
23    PSEH_STATUS,
24    N_PSEH
25};
26
27#define BIT(x) (1 << (x))
28
29#define ALL_REQUEST_PSEH (BIT(PSEH_METHOD)|BIT(PSEH_SCHEME)|BIT(PSEH_AUTHORITY)|BIT(PSEH_PATH))
30#define REQUIRED_REQUEST_PSEH (BIT(PSEH_METHOD)|BIT(PSEH_SCHEME)|BIT(PSEH_PATH))
31
32#define ALL_SERVER_PSEH BIT(PSEH_STATUS)
33#define REQUIRED_SERVER_PSEH ALL_SERVER_PSEH
34
35#define PSEH_LEN(h) (sizeof(#h) - 5)
36
37struct header_writer_ctx
38{
39    const struct lsquic_conn    *hwc_conn;
40    char                        *buf;
41    char                        *cookie_val;
42    unsigned                     cookie_sz, cookie_nalloc;
43    unsigned                     max_headers_sz,
44                                 headers_sz,
45                                 w_off;
46    enum {
47        HWC_SERVER       = 1 << 0,
48        HWC_EXPECT_COLON = 1 << 1,
49        HWC_SEEN_HOST    = 1 << 2,
50        HWC_PUSH_PROMISE = 1 << 3,
51    }                            hwc_flags;
52    enum pseudo_header           pseh_mask;
53    char                        *pseh_bufs[N_PSEH];
54    struct http1x_headers        hwc_h1h;
55    size_t                       hwc_header_buf_nalloc;
56    struct lsxpack_header        hwc_xhdr;
57};
58
59
60#define HWC_PSEH_LEN(hwc, ph) ((int) strlen((hwc)->pseh_bufs[ph]))
61
62#define HWC_PSEH_VAL(hwc, ph) ((hwc)->pseh_bufs[ph])
63
64static void *
65h1h_create_header_set (void *ctx, lsquic_stream_t *stream, int is_push_promise)
66{
67    const struct http1x_ctor_ctx *hcc = ctx;
68    struct header_writer_ctx *hwc;
69
70    hwc = calloc(1, sizeof(*hwc));
71    if (!hwc)
72        return NULL;
73
74    hwc->hwc_flags = HWC_EXPECT_COLON;
75    if (hcc->is_server)
76        hwc->hwc_flags |= HWC_SERVER;
77    if (is_push_promise)
78        hwc->hwc_flags |= HWC_PUSH_PROMISE;
79    hwc->max_headers_sz = hcc->max_headers_sz;
80    hwc->hwc_conn = hcc->conn;
81    return &hwc->hwc_h1h;
82}
83
84
85static int
86hwc_uh_write (struct header_writer_ctx *hwc, const void *buf, size_t sz)
87{
88    char *h1h_buf;
89
90    if (hwc->w_off + sz > hwc->headers_sz)
91    {
92        if (hwc->headers_sz * 2 >= hwc->w_off + sz)
93            hwc->headers_sz *= 2;
94        else
95            hwc->headers_sz = hwc->w_off + sz;
96        h1h_buf = realloc(hwc->hwc_h1h.h1h_buf, hwc->headers_sz);
97        if (!h1h_buf)
98            return -1;
99        hwc->hwc_h1h.h1h_buf = h1h_buf;
100    }
101    memcpy(&hwc->hwc_h1h.h1h_buf[hwc->w_off], buf, sz);
102    hwc->w_off += sz;
103    return 0;
104}
105
106
107static int
108save_pseudo_header (struct header_writer_ctx *hwc, enum pseudo_header ph,
109                    const char *val, unsigned val_len)
110{
111    if (0 == (hwc->pseh_mask & BIT(ph)))
112    {
113        assert(!hwc->pseh_bufs[ph]);
114        hwc->pseh_bufs[ph] = malloc(val_len + 1);
115        if (!hwc->pseh_bufs[ph])
116            return -1;
117        hwc->pseh_mask |= BIT(ph);
118        memcpy(hwc->pseh_bufs[ph], val, val_len);
119        hwc->pseh_bufs[ph][val_len] = '\0';
120        return 0;
121    }
122    else
123    {
124        LSQ_INFO("header %u is already present", ph);
125        return 1;
126    }
127}
128
129
130static int
131add_pseudo_header (struct header_writer_ctx *hwc, struct lsxpack_header *xhdr)
132{
133    const char *name, *val;
134    unsigned name_len, val_len;
135
136    if (!(hwc->hwc_flags & HWC_EXPECT_COLON))
137    {
138        LSQ_INFO("unexpected colon");
139        return 1;
140    }
141
142    name = lsxpack_header_get_name(xhdr);
143    val = lsxpack_header_get_value(xhdr);
144    name_len = xhdr->name_len;
145    val_len = xhdr->val_len;
146
147    switch (name_len)
148    {
149    case 5:
150        if (0 == memcmp(name,     ":path", 5))
151            return save_pseudo_header(hwc, PSEH_PATH, val, val_len);
152        break;
153    case 7:
154        switch (name[2])
155        {
156        case 'c':
157            if (0 == memcmp(name, ":scheme", 7))
158                return save_pseudo_header(hwc, PSEH_SCHEME, val, val_len);
159            break;
160        case 'e':
161            if (0 == memcmp(name, ":method", 7))
162                return save_pseudo_header(hwc, PSEH_METHOD, val, val_len);
163            break;
164        case 't':
165            if (0 == memcmp(name, ":status", 7))
166                return save_pseudo_header(hwc, PSEH_STATUS, val, val_len);
167            break;
168        }
169        break;
170    case 10:
171        if (0 == memcmp(name,     ":authority", 10))
172            return save_pseudo_header(hwc, PSEH_AUTHORITY, val, val_len);
173        break;
174    }
175
176    LSQ_INFO("unknown pseudo-header `%.*s'", name_len, name);
177    return 1;
178}
179
180
181#define HTTP_CODE_LEN 3
182
183static const char *
184code_str_to_reason (const char code_str[HTTP_CODE_LEN])
185{
186    /* RFC 7231, Section 6: */
187    static const char *const http_reason_phrases[] =
188    {
189    #define HTTP_REASON_CODE(code, reason) [code - 100] = reason
190        HTTP_REASON_CODE(100, "Continue"),
191        HTTP_REASON_CODE(101, "Switching Protocols"),
192        HTTP_REASON_CODE(200, "OK"),
193        HTTP_REASON_CODE(201, "Created"),
194        HTTP_REASON_CODE(202, "Accepted"),
195        HTTP_REASON_CODE(203, "Non-Authoritative Information"),
196        HTTP_REASON_CODE(204, "No Content"),
197        HTTP_REASON_CODE(205, "Reset Content"),
198        HTTP_REASON_CODE(206, "Partial Content"),
199        HTTP_REASON_CODE(300, "Multiple Choices"),
200        HTTP_REASON_CODE(301, "Moved Permanently"),
201        HTTP_REASON_CODE(302, "Found"),
202        HTTP_REASON_CODE(303, "See Other"),
203        HTTP_REASON_CODE(304, "Not Modified"),
204        HTTP_REASON_CODE(305, "Use Proxy"),
205        HTTP_REASON_CODE(307, "Temporary Redirect"),
206        HTTP_REASON_CODE(400, "Bad Request"),
207        HTTP_REASON_CODE(401, "Unauthorized"),
208        HTTP_REASON_CODE(402, "Payment Required"),
209        HTTP_REASON_CODE(403, "Forbidden"),
210        HTTP_REASON_CODE(404, "Not Found"),
211        HTTP_REASON_CODE(405, "Method Not Allowed"),
212        HTTP_REASON_CODE(406, "Not Acceptable"),
213        HTTP_REASON_CODE(407, "Proxy Authentication Required"),
214        HTTP_REASON_CODE(408, "Request Timeout"),
215        HTTP_REASON_CODE(409, "Conflict"),
216        HTTP_REASON_CODE(410, "Gone"),
217        HTTP_REASON_CODE(411, "Length Required"),
218        HTTP_REASON_CODE(412, "Precondition Failed"),
219        HTTP_REASON_CODE(413, "Payload Too Large"),
220        HTTP_REASON_CODE(414, "URI Too Long"),
221        HTTP_REASON_CODE(415, "Unsupported Media Type"),
222        HTTP_REASON_CODE(416, "Range Not Satisfiable"),
223        HTTP_REASON_CODE(417, "Expectation Failed"),
224        HTTP_REASON_CODE(426, "Upgrade Required"),
225        HTTP_REASON_CODE(500, "Internal Server Error"),
226        HTTP_REASON_CODE(501, "Not Implemented"),
227        HTTP_REASON_CODE(502, "Bad Gateway"),
228        HTTP_REASON_CODE(503, "Service Unavailable"),
229        HTTP_REASON_CODE(504, "Gateway Timeout"),
230        HTTP_REASON_CODE(505, "HTTP Version Not Supported"),
231    #undef HTTP_REASON_CODE
232    };
233
234    long code;
235    char code_buf[HTTP_CODE_LEN + 1];
236
237    memcpy(code_buf, code_str, HTTP_CODE_LEN);
238    code_buf[HTTP_CODE_LEN] = '\0';
239    code = strtol(code_buf, NULL, 10) - 100;
240    if (code > 0 && code < (long) (sizeof(http_reason_phrases) /
241                                        sizeof(http_reason_phrases[0])))
242        return http_reason_phrases[code];
243    else
244        return NULL;
245}
246
247
248static int
249convert_response_pseudo_headers (struct header_writer_ctx *hwc)
250{
251    if ((hwc->pseh_mask & REQUIRED_SERVER_PSEH) != REQUIRED_SERVER_PSEH)
252    {
253        LSQ_INFO("not all response pseudo-headers are specified");
254        return 1;
255    }
256    if (hwc->pseh_mask & ALL_REQUEST_PSEH)
257    {
258        LSQ_INFO("response pseudo-headers contain request-only headers");
259        return 1;
260    }
261
262    const char *code_str, *reason;
263    int code_len;
264
265    code_str = HWC_PSEH_VAL(hwc, PSEH_STATUS);
266    code_len = HWC_PSEH_LEN(hwc, PSEH_STATUS);
267
268#define HWC_UH_WRITE(h, buf, sz) do {                                   \
269    if (0 != hwc_uh_write(h, buf, sz))                                  \
270        return -1;                                                      \
271} while (0)
272
273    HWC_UH_WRITE(hwc, "HTTP/1.1 ", 9);
274    HWC_UH_WRITE(hwc, code_str, code_len);
275    if (HTTP_CODE_LEN == code_len && (reason = code_str_to_reason(code_str)))
276    {
277        HWC_UH_WRITE(hwc, " ", 1);
278        HWC_UH_WRITE(hwc, reason, strlen(reason));
279        HWC_UH_WRITE(hwc, "\r\n", 2);
280    }
281    else
282        HWC_UH_WRITE(hwc, " \r\n", 3);
283    if (hwc->max_headers_sz && hwc->w_off > hwc->max_headers_sz)
284    {
285        LSQ_INFO("headers too large");
286        return 1;
287    }
288    return 0;
289
290#undef HWC_UH_WRITE
291}
292
293
294static int
295convert_request_pseudo_headers (struct header_writer_ctx *hwc)
296{
297    if ((hwc->pseh_mask & REQUIRED_REQUEST_PSEH) != REQUIRED_REQUEST_PSEH)
298    {
299        LSQ_INFO("not all request pseudo-headers are specified");
300        return 1;
301    }
302    if (hwc->pseh_mask & ALL_SERVER_PSEH)
303    {
304        LSQ_INFO("request pseudo-headers contain response-only headers");
305        return 1;
306    }
307
308#define HWC_UH_WRITE(h, buf, sz) do {                                   \
309    if (0 != hwc_uh_write(h, buf, sz))                                  \
310        return -1;                                                      \
311} while (0)
312
313    HWC_UH_WRITE(hwc, HWC_PSEH_VAL(hwc, PSEH_METHOD), HWC_PSEH_LEN(hwc, PSEH_METHOD));
314    HWC_UH_WRITE(hwc, " ", 1);
315    HWC_UH_WRITE(hwc, HWC_PSEH_VAL(hwc, PSEH_PATH), HWC_PSEH_LEN(hwc, PSEH_PATH));
316    HWC_UH_WRITE(hwc, " HTTP/1.1\r\n", 11);
317
318    if (hwc->max_headers_sz && hwc->w_off > hwc->max_headers_sz)
319    {
320        LSQ_INFO("headers too large");
321        return 1;
322    }
323
324    return 0;
325
326#undef HWC_UH_WRITE
327}
328
329
330static int
331convert_pseudo_headers (struct header_writer_ctx *hwc)
332{
333    /* We are *reading* the message.  Thus, a server expects a request, and a
334     * client expects a response.  Unless we receive a push promise from the
335     * server, in which case this should also be a request.
336     */
337    if (hwc->hwc_flags & (HWC_SERVER|HWC_PUSH_PROMISE))
338        return convert_request_pseudo_headers(hwc);
339    else
340        return convert_response_pseudo_headers(hwc);
341}
342
343
344static int
345save_cookie (struct header_writer_ctx *hwc, const char *val, unsigned val_len)
346{
347    char *cookie_val;
348
349    if (0 == hwc->cookie_sz)
350    {
351        hwc->cookie_nalloc = hwc->cookie_sz = val_len;
352        cookie_val = malloc(hwc->cookie_nalloc);
353        if (!cookie_val)
354            return -1;
355        hwc->cookie_val = cookie_val;
356        memcpy(hwc->cookie_val, val, val_len);
357    }
358    else
359    {
360        hwc->cookie_sz += val_len + 2 /* "; " */;
361        if (hwc->cookie_sz > hwc->cookie_nalloc)
362        {
363            hwc->cookie_nalloc = hwc->cookie_nalloc * 2 + val_len + 2;
364            cookie_val = realloc(hwc->cookie_val, hwc->cookie_nalloc);
365            if (!cookie_val)
366                return -1;
367            hwc->cookie_val = cookie_val;
368        }
369        memcpy(hwc->cookie_val + hwc->cookie_sz - val_len - 2, "; ", 2);
370        memcpy(hwc->cookie_val + hwc->cookie_sz - val_len, val, val_len);
371    }
372
373    return 0;
374}
375
376
377static int
378add_real_header (struct header_writer_ctx *hwc, struct lsxpack_header *xhdr)
379{
380    int err;
381    unsigned i;
382    int n_upper;
383    const char *name, *val;
384    unsigned name_len, val_len;
385
386    if (hwc->hwc_flags & HWC_EXPECT_COLON)
387    {
388        if (0 != (err = convert_pseudo_headers(hwc)))
389            return err;
390        hwc->hwc_flags &= ~HWC_EXPECT_COLON;
391    }
392
393    name = lsxpack_header_get_name(xhdr);
394    val = lsxpack_header_get_value(xhdr);
395    name_len = xhdr->name_len;
396    val_len = xhdr->val_len;
397
398    if (4 == name_len && 0 == memcmp(name, "host", 4))
399        hwc->hwc_flags |= HWC_SEEN_HOST;
400
401    n_upper = 0;
402    for (i = 0; i < name_len; ++i)
403        n_upper += isupper(name[i]);
404    if (n_upper > 0)
405    {
406        LSQ_INFO("Header name `%.*s' contains uppercase letters",
407            name_len, name);
408        return 1;
409    }
410
411    if (6 == name_len && memcmp(name, "cookie", 6) == 0)
412    {
413        return save_cookie(hwc, val, val_len);
414    }
415
416#define HWC_UH_WRITE(h, buf, sz) do {                                   \
417    if (0 != hwc_uh_write(h, buf, sz))                                  \
418        return -1;                                                      \
419} while (0)
420
421    HWC_UH_WRITE(hwc, name, name_len);
422    HWC_UH_WRITE(hwc, ": ", 2);
423    HWC_UH_WRITE(hwc, val, val_len);
424    HWC_UH_WRITE(hwc, "\r\n", 2);
425
426    if (hwc->max_headers_sz && hwc->w_off > hwc->max_headers_sz)
427    {
428        LSQ_INFO("headers too large");
429        return 1;
430    }
431
432    return 0;
433
434#undef HWC_UH_WRITE
435}
436
437
438static int
439add_header_to_uh (struct header_writer_ctx *hwc, struct lsxpack_header *xhdr)
440{
441    const char *name;
442
443    name = lsxpack_header_get_name(xhdr);
444    LSQ_DEBUG("Got header '%.*s': '%.*s'", (int) xhdr->name_len, name,
445                        (int) xhdr->val_len, lsxpack_header_get_value(xhdr));
446    if (':' == name[0])
447        return add_pseudo_header(hwc, xhdr);
448    else
449        return add_real_header(hwc, xhdr);
450}
451
452
453static int
454h1h_finish_hset (struct header_writer_ctx *hwc)
455{
456    int st;
457
458    if (hwc->hwc_flags & HWC_EXPECT_COLON)
459    {
460        st = convert_pseudo_headers(hwc);
461        if (0 != st)
462            return st;
463        hwc->hwc_flags &= ~HWC_EXPECT_COLON;
464    }
465
466#define HWC_UH_WRITE(h, buf, sz) do {                                   \
467    st = hwc_uh_write(h, buf, sz);                                      \
468    if (0 != st)                                                        \
469        return st;                                                      \
470} while (0)
471
472    if ((hwc->pseh_mask & BIT(PSEH_AUTHORITY)) &&
473                                0 == (hwc->hwc_flags & HWC_SEEN_HOST))
474    {
475        LSQ_DEBUG("Setting 'Host: %.*s'", HWC_PSEH_LEN(hwc, PSEH_AUTHORITY),
476                                            HWC_PSEH_VAL(hwc, PSEH_AUTHORITY));
477        HWC_UH_WRITE(hwc, "Host: ", 6);
478        HWC_UH_WRITE(hwc, HWC_PSEH_VAL(hwc, PSEH_AUTHORITY),
479                                        HWC_PSEH_LEN(hwc, PSEH_AUTHORITY));
480        HWC_UH_WRITE(hwc, "\r\n", 2);
481    }
482
483    if (hwc->cookie_val)
484    {
485        LSQ_DEBUG("Setting 'Cookie: %.*s'", hwc->cookie_sz, hwc->cookie_val);
486        HWC_UH_WRITE(hwc, "Cookie: ", 8);
487        HWC_UH_WRITE(hwc, hwc->cookie_val, hwc->cookie_sz);
488        HWC_UH_WRITE(hwc, "\r\n", 2);
489    }
490
491    HWC_UH_WRITE(hwc, "\r\n", 2 + 1 /* NUL byte */);
492    hwc->w_off -= 1;     /* Do not count NUL byte */
493    hwc->hwc_h1h.h1h_size = hwc->w_off;
494
495    if (hwc->max_headers_sz && hwc->w_off > hwc->max_headers_sz)
496    {
497        LSQ_INFO("headers too large");
498        return 1;
499    }
500
501    return 0;
502}
503
504#define HWC_PTR(data_in) (struct header_writer_ctx *) \
505    ((unsigned char *) (hset) - offsetof(struct header_writer_ctx, hwc_h1h))
506
507
508static struct lsxpack_header *
509h1h_prepare_decode (void *hset, struct lsxpack_header *xhdr, size_t req_space)
510{
511    struct header_writer_ctx *const hwc = HWC_PTR(hset);
512    size_t nalloc;
513    char *buf;
514
515    if (req_space < 0x100)
516        req_space = 0x100;
517
518    if (req_space > MAX_HTTP1X_HEADERS_SIZE || req_space > LSXPACK_MAX_STRLEN)
519    {
520        LSQ_DEBUG("requested space for header is too large: %zd bytes",
521                                                                    req_space);
522        return NULL;
523    }
524
525    if (!xhdr)
526    {
527        if (0 == hwc->hwc_header_buf_nalloc
528                                    || req_space > hwc->hwc_header_buf_nalloc)
529        {
530            buf = malloc(req_space);
531            if (!buf)
532            {
533                LSQ_DEBUG("cannot allocate %zd bytes", req_space);
534                return NULL;
535            }
536            hwc->hwc_header_buf_nalloc = req_space;
537        }
538        else
539            buf = hwc->hwc_xhdr.buf;
540        lsxpack_header_prepare_decode(&hwc->hwc_xhdr, buf, 0, req_space);
541    }
542    else
543    {
544        if (req_space > hwc->hwc_header_buf_nalloc)
545        {
546            if (req_space < hwc->hwc_header_buf_nalloc * 2)
547                nalloc = hwc->hwc_header_buf_nalloc * 2;
548            else
549                nalloc = req_space;
550            buf = realloc(hwc->hwc_xhdr.buf, nalloc);
551            if (!buf)
552            {
553                LSQ_DEBUG("cannot reallocate to %zd bytes", nalloc);
554                return NULL;
555            }
556            hwc->hwc_xhdr.buf = buf;
557            hwc->hwc_header_buf_nalloc = nalloc;
558        }
559        hwc->hwc_xhdr.val_len = req_space;
560    }
561
562    return &hwc->hwc_xhdr;
563}
564
565
566static int
567h1h_process_header (void *hset, struct lsxpack_header *xhdr)
568{
569    struct header_writer_ctx *const hwc = HWC_PTR(hset);
570    if (xhdr)
571        return add_header_to_uh(hwc, xhdr);
572    else
573        return h1h_finish_hset(hwc);
574}
575
576
577static void
578h1h_discard_header_set (void *hset)
579{
580    struct header_writer_ctx *const hwc = HWC_PTR(hset);
581    unsigned i;
582
583    for (i = 0; i < sizeof(hwc->pseh_bufs) / sizeof(hwc->pseh_bufs[0]); ++i)
584        if (hwc->pseh_bufs[i])
585            free(hwc->pseh_bufs[i]);
586    if (hwc->cookie_val)
587        free(hwc->cookie_val);
588    free(hwc->hwc_h1h.h1h_buf);
589    free(hwc->hwc_xhdr.buf);
590    free(hwc);
591}
592
593
594static const struct lsquic_hset_if http1x_if =
595{
596    .hsi_create_header_set  = h1h_create_header_set,
597    .hsi_prepare_decode     = h1h_prepare_decode,
598    .hsi_process_header     = h1h_process_header,
599    .hsi_discard_header_set = h1h_discard_header_set,
600};
601
602const struct lsquic_hset_if *const lsquic_http1x_if = &http1x_if;
603