summaryrefslogtreecommitdiffhomepage
path: root/src/nxt_http_parse.h
blob: 0f888949f655cf1c6a1de9763cc2d6524f5a66b7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137

/*
 * Copyright (C) NGINX, Inc.
 * Copyright (C) Valentin V. Bartenev
 */

#ifndef _NXT_HTTP_PARSER_H_INCLUDED_
#define _NXT_HTTP_PARSER_H_INCLUDED_


typedef enum {
    NXT_HTTP_PARSE_INVALID = 1,
    NXT_HTTP_PARSE_UNSUPPORTED_VERSION,
    NXT_HTTP_PARSE_TOO_LARGE_FIELD,
} nxt_http_parse_error_t;


typedef struct nxt_http_request_parse_s  nxt_http_request_parse_t;
typedef struct nxt_http_field_s          nxt_http_field_t;
typedef struct nxt_http_fields_hash_s    nxt_http_fields_hash_t;


typedef union {
    u_char                    str[8];
    uint64_t                  ui64;

    struct {
        u_char                prefix[5];
        u_char                major;
        u_char                point;
        u_char                minor;
    } s;
} nxt_http_ver_t;


struct nxt_http_request_parse_s {
    nxt_int_t                 (*handler)(nxt_http_request_parse_t *rp,
                                         u_char **pos, u_char *end);

    nxt_str_t                 method;

    u_char                    *target_start;
    u_char                    *target_end;

    nxt_str_t                 path;
    nxt_str_t                 args;

    nxt_http_ver_t            version;

    nxt_list_t                *fields;
    nxt_mp_t                  *mem_pool;

    nxt_str_t                 field_name;
    nxt_str_t                 field_value;

    uint32_t                  field_hash;

    /* target with "/." */
    uint8_t                   complex_target;   /* 1 bit */
    /* target with "%" */
    uint8_t                   quoted_target;    /* 1 bit */
    /* target with " " */
    uint8_t                   space_in_target;  /* 1 bit */

    /* Preserve encoded '/' (%2F) and '%' (%25). */
    uint8_t                   encoded_slashes;  /* 1 bit */
};


typedef nxt_int_t (*nxt_http_field_handler_t)(void *ctx,
                                              nxt_http_field_t *field,
                                              uintptr_t data);


typedef struct {
    nxt_str_t                 name;
    nxt_http_field_handler_t  handler;
    uintptr_t                 data;
} nxt_http_field_proc_t;


struct nxt_http_field_s {
    uint16_t                  hash;
    uint8_t                   skip:1;
    uint8_t                   hopbyhop:1;
    uint8_t                   name_length;
    uint32_t                  value_length;
    u_char                    *name;
    u_char                    *value;
};


#define NXT_HTTP_FIELD_HASH_INIT        159406U
#define nxt_http_field_hash_char(h, c)  (((h) << 4) + (h) + (c))
#define nxt_http_field_hash_end(h)      (((h) >> 16) ^ (h))


nxt_int_t nxt_http_parse_request_init(nxt_http_request_parse_t *rp,
    nxt_mp_t *mp);
nxt_int_t nxt_http_parse_request(nxt_http_request_parse_t *rp,
    nxt_buf_mem_t *b);
nxt_int_t nxt_http_parse_fields(nxt_http_request_parse_t *rp,
    nxt_buf_mem_t *b);

nxt_int_t nxt_http_fields_hash(nxt_lvlhsh_t *hash,
    nxt_http_field_proc_t items[], nxt_uint_t count);
nxt_uint_t nxt_http_fields_hash_collisions(nxt_lvlhsh_t *hash,
    nxt_http_field_proc_t items[], nxt_uint_t count, nxt_bool_t level);
nxt_int_t nxt_http_fields_process(nxt_list_t *fields, nxt_lvlhsh_t *hash,
    void *ctx);


extern const nxt_lvlhsh_proto_t  nxt_http_fields_hash_proto;

nxt_inline nxt_int_t
nxt_http_field_process(nxt_http_field_t *field, nxt_lvlhsh_t *hash, void *ctx)
{
    nxt_lvlhsh_query_t     lhq;
    nxt_http_field_proc_t  *proc;

    lhq.proto = &nxt_http_fields_hash_proto;

    lhq.key_hash = field->hash;
    lhq.key.length = field->name_length;
    lhq.key.start = field->name;

    if (nxt_lvlhsh_find(hash, &lhq) != NXT_OK) {
        return NXT_OK;
    }

    proc = lhq.value;

    return proc->handler(ctx, field, proc->data);
}


#endif /* _NXT_HTTP_PARSER_H_INCLUDED_ */