Mercurial > hg > nginx
comparison src/http/v3/ngx_http_v3_request.c @ 8405:d2759e4cc437 quic
HTTP/3: split header parser in two functions.
The first one parses pseudo-headers and is analagous to the request line
parser in HTTP/1. The second one parses regular headers and is analogous to
the header parser in HTTP/1.
Additionally, error handling of client passing malformed uri is now fixed.
author | Roman Arutyunyan <arut@nginx.com> |
---|---|
date | Tue, 19 May 2020 15:29:10 +0300 |
parents | df18ae7161b8 |
children | 66feab03d9b7 |
comparison
equal
deleted
inserted
replaced
8404:e5d4f057a6cb | 8405:d2759e4cc437 |
---|---|
36 { ngx_string("TRACE"), NGX_HTTP_TRACE } | 36 { ngx_string("TRACE"), NGX_HTTP_TRACE } |
37 }; | 37 }; |
38 | 38 |
39 | 39 |
40 ngx_int_t | 40 ngx_int_t |
41 ngx_http_v3_parse_request(ngx_http_request_t *r, ngx_buf_t *b) | |
42 { | |
43 size_t len; | |
44 u_char *p; | |
45 ngx_int_t rc, n; | |
46 ngx_str_t *name, *value; | |
47 ngx_connection_t *c; | |
48 ngx_http_v3_parse_headers_t *st; | |
49 | |
50 c = r->connection; | |
51 st = r->h3_parse; | |
52 | |
53 if (st == NULL) { | |
54 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse header"); | |
55 | |
56 st = ngx_pcalloc(c->pool, sizeof(ngx_http_v3_parse_headers_t)); | |
57 if (st == NULL) { | |
58 goto failed; | |
59 } | |
60 | |
61 r->h3_parse = st; | |
62 } | |
63 | |
64 while (b->pos < b->last) { | |
65 rc = ngx_http_v3_parse_headers(c, st, *b->pos++); | |
66 | |
67 if (rc == NGX_ERROR) { | |
68 goto failed; | |
69 } | |
70 | |
71 if (rc == NGX_AGAIN) { | |
72 continue; | |
73 } | |
74 | |
75 name = &st->header_rep.header.name; | |
76 value = &st->header_rep.header.value; | |
77 | |
78 n = ngx_http_v3_process_pseudo_header(r, name, value); | |
79 | |
80 if (n == NGX_ERROR) { | |
81 goto failed; | |
82 } | |
83 | |
84 if (n == NGX_OK && rc == NGX_OK) { | |
85 continue; | |
86 } | |
87 | |
88 len = (r->method_end - r->method_start) + 1 | |
89 + (r->uri_end - r->uri_start) + 1 | |
90 + sizeof("HTTP/3") - 1; | |
91 | |
92 p = ngx_pnalloc(c->pool, len); | |
93 if (p == NULL) { | |
94 goto failed; | |
95 } | |
96 | |
97 r->request_start = p; | |
98 | |
99 p = ngx_cpymem(p, r->method_start, r->method_end - r->method_start); | |
100 *p++ = ' '; | |
101 p = ngx_cpymem(p, r->uri_start, r->uri_end - r->uri_start); | |
102 *p++ = ' '; | |
103 p = ngx_cpymem(p, "HTTP/3", sizeof("HTTP/3") - 1); | |
104 | |
105 r->request_end = p; | |
106 | |
107 return NGX_OK; | |
108 } | |
109 | |
110 return NGX_AGAIN; | |
111 | |
112 failed: | |
113 | |
114 return NGX_HTTP_PARSE_INVALID_REQUEST; | |
115 } | |
116 | |
117 | |
118 ngx_int_t | |
41 ngx_http_v3_parse_header(ngx_http_request_t *r, ngx_buf_t *b) | 119 ngx_http_v3_parse_header(ngx_http_request_t *r, ngx_buf_t *b) |
42 { | 120 { |
43 size_t n; | |
44 u_char *p; | |
45 ngx_int_t rc; | 121 ngx_int_t rc; |
46 ngx_str_t *name, *value; | 122 ngx_str_t *name, *value; |
47 ngx_connection_t *c; | 123 ngx_connection_t *c; |
48 ngx_http_v3_parse_headers_t *st; | 124 ngx_http_v3_parse_headers_t *st; |
49 enum { | |
50 sw_start = 0, | |
51 sw_prev, | |
52 sw_headers, | |
53 sw_last, | |
54 sw_done | |
55 }; | |
56 | 125 |
57 c = r->connection; | 126 c = r->connection; |
58 st = r->h3_parse; | 127 st = r->h3_parse; |
59 | 128 |
60 if (st == NULL) { | 129 if (st->state == 0) { |
61 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse header"); | 130 if (r->header_name_start == NULL) { |
62 | 131 name = &st->header_rep.header.name; |
63 st = ngx_pcalloc(c->pool, sizeof(ngx_http_v3_parse_headers_t)); | 132 |
64 if (st == NULL) { | 133 if (name->len && name->data[0] != ':') { |
65 goto failed; | 134 goto done; |
66 } | 135 } |
67 | 136 } |
68 r->h3_parse = st; | 137 |
69 } | 138 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, |
70 | 139 "http3 parse header done"); |
71 switch (r->state) { | 140 |
72 | 141 return NGX_HTTP_PARSE_HEADER_DONE; |
73 case sw_prev: | |
74 r->state = sw_headers; | |
75 return NGX_OK; | |
76 | |
77 case sw_done: | |
78 goto done; | |
79 | |
80 case sw_last: | |
81 r->state = sw_done; | |
82 return NGX_OK; | |
83 | |
84 default: | |
85 break; | |
86 } | 142 } |
87 | 143 |
88 while (b->pos < b->last) { | 144 while (b->pos < b->last) { |
89 rc = ngx_http_v3_parse_headers(c, st, *b->pos++); | 145 rc = ngx_http_v3_parse_headers(c, st, *b->pos++); |
90 | 146 |
91 if (rc == NGX_ERROR) { | 147 if (rc == NGX_ERROR) { |
92 goto failed; | 148 return NGX_HTTP_PARSE_INVALID_HEADER; |
93 } | 149 } |
94 | 150 |
95 if (rc == NGX_AGAIN) { | 151 if (rc != NGX_AGAIN) { |
96 continue; | 152 goto done; |
97 } | 153 } |
98 | |
99 name = &st->header_rep.header.name; | |
100 value = &st->header_rep.header.value; | |
101 | |
102 if (r->state == sw_start) { | |
103 | |
104 if (ngx_http_v3_process_pseudo_header(r, name, value) == NGX_OK) { | |
105 if (rc == NGX_OK) { | |
106 continue; | |
107 } | |
108 | |
109 r->state = sw_done; | |
110 | |
111 } else if (rc == NGX_OK) { | |
112 r->state = sw_prev; | |
113 | |
114 } else { | |
115 r->state = sw_last; | |
116 } | |
117 | |
118 n = (r->method_end - r->method_start) + 1 | |
119 + (r->uri_end - r->uri_start) + 1 | |
120 + sizeof("HTTP/3") - 1; | |
121 | |
122 p = ngx_pnalloc(c->pool, n); | |
123 if (p == NULL) { | |
124 goto failed; | |
125 } | |
126 | |
127 r->request_start = p; | |
128 | |
129 p = ngx_cpymem(p, r->method_start, r->method_end - r->method_start); | |
130 *p++ = ' '; | |
131 p = ngx_cpymem(p, r->uri_start, r->uri_end - r->uri_start); | |
132 *p++ = ' '; | |
133 p = ngx_cpymem(p, "HTTP/3", sizeof("HTTP/3") - 1); | |
134 | |
135 r->request_end = p; | |
136 | |
137 } else if (rc == NGX_DONE) { | |
138 r->state = sw_done; | |
139 } | |
140 | |
141 r->header_name_start = name->data; | |
142 r->header_name_end = name->data + name->len; | |
143 r->header_start = value->data; | |
144 r->header_end = value->data + value->len; | |
145 r->header_hash = ngx_hash_key(name->data, name->len); | |
146 | |
147 /* XXX r->lowcase_index = i; */ | |
148 | |
149 return NGX_OK; | |
150 } | 154 } |
151 | 155 |
152 return NGX_AGAIN; | 156 return NGX_AGAIN; |
153 | 157 |
154 failed: | |
155 | |
156 return r->state == sw_start ? NGX_HTTP_PARSE_INVALID_REQUEST | |
157 : NGX_HTTP_PARSE_INVALID_HEADER; | |
158 | |
159 done: | 158 done: |
160 | 159 |
161 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse header done"); | 160 name = &st->header_rep.header.name; |
162 | 161 value = &st->header_rep.header.value; |
163 return NGX_HTTP_PARSE_HEADER_DONE; | 162 |
163 r->header_name_start = name->data; | |
164 r->header_name_end = name->data + name->len; | |
165 r->header_start = value->data; | |
166 r->header_end = value->data + value->len; | |
167 r->header_hash = ngx_hash_key(name->data, name->len); | |
168 | |
169 /* XXX r->lowcase_index = i; */ | |
170 | |
171 return NGX_OK; | |
164 } | 172 } |
165 | 173 |
166 | 174 |
167 static ngx_int_t | 175 static ngx_int_t |
168 ngx_http_v3_process_pseudo_header(ngx_http_request_t *r, ngx_str_t *name, | 176 ngx_http_v3_process_pseudo_header(ngx_http_request_t *r, ngx_str_t *name, |