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,