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