Mercurial > hg > nginx-quic
annotate src/http/v3/ngx_http_v3_request.c @ 7696:31f7c697b6d9 quic
Fixed pointer increment while parsing HTTP/3 header.
author | Roman Arutyunyan <arut@nginx.com> |
---|---|
date | Wed, 18 Mar 2020 15:28:20 +0300 |
parents | 268f4389130d |
children | 1e45c02f6376 |
rev | line source |
---|---|
7681 | 1 |
2 /* | |
3 * Copyright (C) Roman Arutyunyan | |
4 * Copyright (C) Nginx, Inc. | |
5 */ | |
6 | |
7 | |
8 #include <ngx_config.h> | |
9 #include <ngx_core.h> | |
10 #include <ngx_http.h> | |
11 | |
12 | |
13 static ngx_int_t ngx_http_v3_process_pseudo_header(ngx_http_request_t *r, | |
14 ngx_str_t *name, ngx_str_t *value); | |
15 | |
16 | |
17 struct { | |
18 ngx_str_t name; | |
19 ngx_uint_t method; | |
20 } ngx_http_v3_methods[] = { | |
21 | |
22 { ngx_string("GET"), NGX_HTTP_GET }, | |
23 { ngx_string("POST"), NGX_HTTP_POST }, | |
24 { ngx_string("HEAD"), NGX_HTTP_HEAD }, | |
25 { ngx_string("OPTIONS"), NGX_HTTP_OPTIONS }, | |
26 { ngx_string("PROPFIND"), NGX_HTTP_PROPFIND }, | |
27 { ngx_string("PUT"), NGX_HTTP_PUT }, | |
28 { ngx_string("MKCOL"), NGX_HTTP_MKCOL }, | |
29 { ngx_string("DELETE"), NGX_HTTP_DELETE }, | |
30 { ngx_string("COPY"), NGX_HTTP_COPY }, | |
31 { ngx_string("MOVE"), NGX_HTTP_MOVE }, | |
32 { ngx_string("PROPPATCH"), NGX_HTTP_PROPPATCH }, | |
33 { ngx_string("LOCK"), NGX_HTTP_LOCK }, | |
34 { ngx_string("UNLOCK"), NGX_HTTP_UNLOCK }, | |
35 { ngx_string("PATCH"), NGX_HTTP_PATCH }, | |
36 { ngx_string("TRACE"), NGX_HTTP_TRACE } | |
37 }; | |
38 | |
39 | |
40 ngx_int_t | |
7692
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
41 ngx_http_v3_parse_header(ngx_http_request_t *r, ngx_buf_t *b) |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
42 { |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
43 ngx_int_t rc; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
44 ngx_str_t *name, *value; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
45 ngx_connection_t *c; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
46 ngx_http_v3_parse_headers_t *st; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
47 enum { |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
48 sw_start = 0, |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
49 sw_prev, |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
50 sw_headers, |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
51 sw_last, |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
52 sw_done |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
53 }; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
54 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
55 c = r->connection; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
56 st = r->h3_parse; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
57 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
58 if (st == NULL) { |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
59 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse header"); |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
60 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
61 st = ngx_pcalloc(c->pool, sizeof(ngx_http_v3_parse_headers_t)); |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
62 if (st == NULL) { |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
63 goto failed; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
64 } |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
65 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
66 r->h3_parse = st; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
67 } |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
68 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
69 switch (r->state) { |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
70 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
71 case sw_prev: |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
72 r->state = sw_headers; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
73 return NGX_OK; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
74 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
75 case sw_done: |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
76 goto done; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
77 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
78 case sw_last: |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
79 r->state = sw_done; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
80 return NGX_OK; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
81 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
82 default: |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
83 break; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
84 } |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
85 |
7696
31f7c697b6d9
Fixed pointer increment while parsing HTTP/3 header.
Roman Arutyunyan <arut@nginx.com>
parents:
7692
diff
changeset
|
86 while (b->pos < b->last) { |
31f7c697b6d9
Fixed pointer increment while parsing HTTP/3 header.
Roman Arutyunyan <arut@nginx.com>
parents:
7692
diff
changeset
|
87 rc = ngx_http_v3_parse_headers(c, st, *b->pos++); |
7692
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
88 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
89 if (rc == NGX_ERROR) { |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
90 goto failed; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
91 } |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
92 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
93 if (rc == NGX_AGAIN) { |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
94 continue; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
95 } |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
96 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
97 name = &st->header_rep.header.name; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
98 value = &st->header_rep.header.value; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
99 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
100 if (r->state == sw_start |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
101 && ngx_http_v3_process_pseudo_header(r, name, value) != NGX_OK) |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
102 { |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
103 if (rc == NGX_DONE) { |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
104 r->state = sw_last; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
105 } else { |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
106 r->state = sw_prev; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
107 } |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
108 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
109 } else if (rc == NGX_DONE) { |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
110 r->state = sw_done; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
111 } |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
112 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
113 if (r->state == sw_start) { |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
114 continue; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
115 } |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
116 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
117 r->header_name_start = name->data; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
118 r->header_name_end = name->data + name->len; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
119 r->header_start = value->data; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
120 r->header_end = value->data + value->len; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
121 r->header_hash = ngx_hash_key(name->data, name->len); |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
122 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
123 /* XXX r->lowcase_index = i; */ |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
124 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
125 return NGX_OK; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
126 } |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
127 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
128 return NGX_AGAIN; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
129 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
130 failed: |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
131 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
132 return r->state == sw_start ? NGX_HTTP_PARSE_INVALID_REQUEST |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
133 : NGX_HTTP_PARSE_INVALID_HEADER; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
134 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
135 done: |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
136 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
137 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse header done"); |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
138 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
139 return NGX_HTTP_PARSE_HEADER_DONE; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
140 } |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
141 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
142 #if 0 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
143 ngx_int_t |
7681 | 144 ngx_http_v3_parse_header(ngx_http_request_t *r, ngx_buf_t *b, ngx_uint_t pseudo) |
145 { | |
146 u_char *p, ch; | |
147 ngx_str_t name, value; | |
148 ngx_int_t rc; | |
149 ngx_uint_t length, index, insert_count, sign, base, delta_base, | |
150 huffman, dynamic, offset; | |
151 ngx_connection_t *c; | |
152 ngx_http_v3_header_t *h; | |
153 enum { | |
154 sw_start = 0, | |
155 sw_length, | |
156 sw_length_1, | |
157 sw_length_2, | |
158 sw_length_3, | |
159 sw_header_block, | |
160 sw_req_insert_count, | |
161 sw_delta_base, | |
162 sw_read_delta_base, | |
163 sw_header, | |
164 sw_old_header, | |
165 sw_header_ri, | |
166 sw_header_pbi, | |
167 sw_header_lri, | |
168 sw_header_lpbi, | |
169 sw_header_l_name_len, | |
170 sw_header_l_name, | |
171 sw_header_value_len, | |
172 sw_header_read_value_len, | |
173 sw_header_value | |
174 } state; | |
175 | |
176 c = r->connection; | |
177 | |
178 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
179 "http3 parse header, pseudo:%ui", pseudo); | |
180 | |
181 if (r->state == sw_old_header) { | |
182 r->state = sw_header; | |
183 return NGX_OK; | |
184 } | |
185 | |
186 length = r->h3_length; | |
187 index = r->h3_index; | |
188 insert_count = r->h3_insert_count; | |
189 sign = r->h3_sign; | |
190 delta_base = r->h3_delta_base; | |
191 huffman = r->h3_huffman; | |
192 dynamic = r->h3_dynamic; | |
193 offset = r->h3_offset; | |
194 | |
195 name.data = r->header_name_start; | |
196 name.len = r->header_name_end - r->header_name_start; | |
197 value.data = r->header_start; | |
198 value.len = r->header_end - r->header_start; | |
199 | |
200 if (r->state == sw_start) { | |
201 length = 1; | |
202 } | |
203 | |
204 again: | |
205 | |
206 state = r->state; | |
207 | |
208 if (state == sw_header && length == 0) { | |
209 r->state = sw_start; | |
210 return NGX_HTTP_PARSE_HEADER_DONE; | |
211 } | |
212 | |
213 for (p = b->pos; p < b->last; p++) { | |
214 | |
215 if (state >= sw_header_block && length-- == 0) { | |
216 goto failed; | |
217 } | |
218 | |
219 ch = *p; | |
220 | |
221 switch (state) { | |
222 | |
223 case sw_start: | |
224 | |
225 if (ch != NGX_HTTP_V3_FRAME_HEADERS) { | |
226 goto failed; | |
227 } | |
228 | |
229 r->request_start = p; | |
230 state = sw_length; | |
231 break; | |
232 | |
233 case sw_length: | |
234 | |
235 length = ch; | |
236 if (length & 0xc0) { | |
237 state = sw_length_1; | |
238 break; | |
239 } | |
240 | |
241 state = sw_header_block; | |
242 break; | |
243 | |
244 case sw_length_1: | |
245 | |
246 length = (length << 8) + ch; | |
247 if ((length & 0xc000) != 0x4000) { | |
248 state = sw_length_2; | |
249 break; | |
250 } | |
251 | |
252 length &= 0x3fff; | |
253 state = sw_header_block; | |
254 break; | |
255 | |
256 case sw_length_2: | |
257 | |
258 length = (length << 8) + ch; | |
259 if ((length & 0xc00000) != 0x800000) { | |
260 state = sw_length_3; | |
261 break; | |
262 } | |
263 | |
7692
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
264 length &= 0x3fffff; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
265 state = sw_header_block; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
266 break; |
7681 | 267 |
268 case sw_length_3: | |
269 | |
7692
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
270 length = (length << 8) + ch; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
271 length &= 0x3fffffff; |
7681 | 272 state = sw_header_block; |
273 break; | |
274 | |
275 case sw_header_block: | |
276 | |
277 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
278 "http3 header block length:%ui", length); | |
279 | |
280 if (ch != 0xff) { | |
281 insert_count = ch; | |
282 state = sw_delta_base; | |
283 break; | |
284 } | |
285 | |
286 insert_count = 0; | |
287 state = sw_req_insert_count; | |
288 break; | |
289 | |
290 case sw_req_insert_count: | |
291 | |
292 insert_count = (insert_count << 7) + (ch & 0x7f); | |
293 if (ch & 0x80) { | |
294 break; | |
295 } | |
296 | |
297 insert_count += 0xff; | |
298 state = sw_delta_base; | |
299 break; | |
300 | |
301 case sw_delta_base: | |
302 | |
303 sign = (ch & 0x80) ? 1 : 0; | |
304 delta_base = ch & 0x7f; | |
305 | |
306 if (delta_base != 0x7f) { | |
307 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
308 "http3 header block " | |
309 "insert_count:%ui, sign:%ui, delta_base:%ui", | |
310 insert_count, sign, delta_base); | |
311 goto done; | |
312 } | |
313 | |
314 delta_base = 0; | |
315 state = sw_read_delta_base; | |
316 break; | |
317 | |
318 case sw_read_delta_base: | |
319 | |
320 delta_base = (delta_base << 7) + (ch & 0x7f); | |
321 if (ch & 0x80) { | |
322 break; | |
323 } | |
324 | |
325 delta_base += 0x7f; | |
326 | |
327 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
328 "http3 header block " | |
329 "insert_count:%ui, sign:%ui, delta_base:%ui", | |
330 insert_count, sign, delta_base); | |
331 goto done; | |
332 | |
333 case sw_header: | |
334 | |
335 index = 0; | |
336 huffman = 0; | |
337 ngx_str_null(&name); | |
338 ngx_str_null(&value); | |
339 | |
340 if (ch & 0x80) { | |
341 /* Indexed Header Field */ | |
342 | |
343 dynamic = (ch & 0x40) ? 0 : 1; | |
344 index = ch & 0x3f; | |
345 | |
346 if (index != 0x3f) { | |
347 goto done; | |
348 } | |
349 | |
350 index = 0; | |
351 state = sw_header_ri; | |
352 break; | |
353 } | |
354 | |
355 if (ch & 0x40) { | |
356 /* Literal Header Field With Name Reference */ | |
357 | |
358 dynamic = (ch & 0x10) ? 0 : 1; | |
359 index = ch & 0x0f; | |
360 | |
361 if (index != 0x0f) { | |
362 state = sw_header_value_len; | |
363 break; | |
364 } | |
365 | |
366 index = 0; | |
367 state = sw_header_lri; | |
368 break; | |
369 } | |
370 | |
371 if (ch & 0x20) { | |
372 /* Literal Header Field Without Name Reference */ | |
373 | |
374 huffman = (ch & 0x08) ? 1 : 0; | |
375 name.len = ch & 0x07; | |
376 | |
377 if (name.len == 0) { | |
378 goto failed; | |
379 } | |
380 | |
381 if (name.len != 0x07) { | |
382 offset = 0; | |
383 state = sw_header_l_name; | |
384 break; | |
385 } | |
386 | |
387 name.len = 0; | |
388 state = sw_header_l_name_len; | |
389 break; | |
390 } | |
391 | |
392 if (ch & 10) { | |
393 /* Indexed Header Field With Post-Base Index */ | |
394 | |
395 dynamic = 2; | |
396 index = ch & 0x0f; | |
397 | |
398 if (index != 0x0f) { | |
399 goto done; | |
400 } | |
401 | |
402 index = 0; | |
403 state = sw_header_pbi; | |
404 break; | |
405 } | |
406 | |
407 /* Literal Header Field With Post-Base Name Reference */ | |
408 | |
409 dynamic = 2; | |
410 index = ch & 0x07; | |
411 | |
412 if (index != 0x07) { | |
413 state = sw_header_value_len; | |
414 break; | |
415 } | |
416 | |
417 index = 0; | |
418 state = sw_header_lpbi; | |
419 break; | |
420 | |
421 case sw_header_ri: | |
422 | |
423 index = (index << 7) + (ch & 0x7f); | |
424 if (ch & 0x80) { | |
425 break; | |
426 } | |
427 | |
428 index += 0x3f; | |
429 goto done; | |
430 | |
431 case sw_header_pbi: | |
432 | |
433 index = (index << 7) + (ch & 0x7f); | |
434 if (ch & 0x80) { | |
435 break; | |
436 } | |
437 | |
438 index += 0x0f; | |
439 goto done; | |
440 | |
441 case sw_header_lri: | |
442 | |
443 index = (index << 7) + (ch & 0x7f); | |
444 if (ch & 0x80) { | |
445 break; | |
446 } | |
447 | |
448 index += 0x0f; | |
449 state = sw_header_value_len; | |
450 break; | |
451 | |
452 case sw_header_lpbi: | |
453 | |
454 index = (index << 7) + (ch & 0x7f); | |
455 if (ch & 0x80) { | |
456 break; | |
457 } | |
458 | |
459 index += 0x07; | |
460 state = sw_header_value_len; | |
461 break; | |
462 | |
463 | |
464 case sw_header_l_name_len: | |
465 | |
466 name.len = (name.len << 7) + (ch & 0x7f); | |
467 if (ch & 0x80) { | |
468 break; | |
469 } | |
470 | |
471 name.len += 0x07; | |
472 offset = 0; | |
473 state = sw_header_l_name; | |
474 break; | |
475 | |
476 case sw_header_l_name: | |
477 if (offset++ == 0) { | |
478 name.data = p; | |
479 } | |
480 | |
481 if (offset != name.len) { | |
482 break; | |
483 } | |
484 | |
485 if (huffman) { | |
486 if (ngx_http_v3_decode_huffman(c, &name) != NGX_OK) { | |
487 goto failed; | |
488 } | |
489 } | |
490 | |
491 state = sw_header_value_len; | |
492 break; | |
493 | |
494 case sw_header_value_len: | |
495 | |
496 huffman = (ch & 0x80) ? 1 : 0; | |
497 value.len = ch & 0x7f; | |
498 | |
499 if (value.len == 0) { | |
500 value.data = p; | |
501 goto done; | |
502 } | |
503 | |
504 if (value.len != 0x7f) { | |
505 offset = 0; | |
506 state = sw_header_value; | |
507 break; | |
508 } | |
509 | |
510 value.len = 0; | |
511 state = sw_header_read_value_len; | |
512 break; | |
513 | |
514 case sw_header_read_value_len: | |
515 | |
516 value.len = (value.len << 7) + (ch & 0x7f); | |
517 if (ch & 0x80) { | |
518 break; | |
519 } | |
520 | |
521 value.len += 0x7f; | |
522 offset = 0; | |
523 state = sw_header_value; | |
524 break; | |
525 | |
526 case sw_header_value: | |
527 | |
528 if (offset++ == 0) { | |
529 value.data = p; | |
530 } | |
531 | |
532 if (offset != value.len) { | |
533 break; | |
534 } | |
535 | |
536 if (huffman) { | |
537 if (ngx_http_v3_decode_huffman(c, &value) != NGX_OK) { | |
538 goto failed; | |
539 } | |
540 } | |
541 | |
542 goto done; | |
543 | |
544 case sw_old_header: | |
545 | |
546 break; | |
547 } | |
548 } | |
549 | |
550 b->pos = p; | |
551 r->state = state; | |
552 r->h3_length = length; | |
553 r->h3_index = index; | |
554 r->h3_insert_count = insert_count; | |
555 r->h3_sign = sign; | |
556 r->h3_delta_base = delta_base; | |
557 r->h3_huffman = huffman; | |
558 r->h3_dynamic = dynamic; | |
559 r->h3_offset = offset; | |
560 | |
561 /* XXX fix large reallocations */ | |
562 r->header_name_start = name.data; | |
563 r->header_name_end = name.data + name.len; | |
564 r->header_start = value.data; | |
565 r->header_end = value.data + value.len; | |
566 | |
567 /* XXX r->lowcase_index = i; */ | |
568 | |
569 return NGX_AGAIN; | |
570 | |
571 done: | |
572 | |
573 b->pos = p + 1; | |
574 r->state = sw_header; | |
575 r->h3_length = length; | |
576 r->h3_insert_count = insert_count; | |
577 r->h3_sign = sign; | |
578 r->h3_delta_base = delta_base; | |
579 | |
580 if (state < sw_header) { | |
581 if (ngx_http_v3_check_insert_count(c, insert_count) != NGX_OK) { | |
582 return NGX_DONE; | |
583 } | |
584 | |
585 goto again; | |
586 } | |
587 | |
588 if (sign == 0) { | |
589 base = insert_count + delta_base; | |
590 } else { | |
591 base = insert_count - delta_base - 1; | |
592 } | |
593 | |
594 ngx_log_debug5(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
595 "http3 header %s[%ui], base:%ui, \"%V\":\"%V\"", | |
596 dynamic ? "dynamic" : "static", index, base, &name, &value); | |
597 | |
598 if (name.data == NULL) { | |
599 | |
600 if (dynamic == 2) { | |
601 index = base - index - 1; | |
602 } else if (dynamic == 1) { | |
603 index += base; | |
604 } | |
605 | |
606 h = ngx_http_v3_lookup_table(c, dynamic, index); | |
607 if (h == NULL) { | |
608 goto failed; | |
609 } | |
610 | |
611 name = h->name; | |
612 | |
613 if (value.data == NULL) { | |
614 value = h->value; | |
615 } | |
616 } | |
617 | |
7685
1307308c3cf1
Temporary fix for header null-termination in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
7681
diff
changeset
|
618 /* XXX ugly reallocation for the trailing '\0' */ |
1307308c3cf1
Temporary fix for header null-termination in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
7681
diff
changeset
|
619 |
1307308c3cf1
Temporary fix for header null-termination in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
7681
diff
changeset
|
620 p = ngx_pnalloc(c->pool, name.len + value.len + 2); |
1307308c3cf1
Temporary fix for header null-termination in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
7681
diff
changeset
|
621 if (p == NULL) { |
1307308c3cf1
Temporary fix for header null-termination in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
7681
diff
changeset
|
622 return NGX_ERROR; |
1307308c3cf1
Temporary fix for header null-termination in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
7681
diff
changeset
|
623 } |
1307308c3cf1
Temporary fix for header null-termination in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
7681
diff
changeset
|
624 |
1307308c3cf1
Temporary fix for header null-termination in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
7681
diff
changeset
|
625 ngx_memcpy(p, name.data, name.len); |
1307308c3cf1
Temporary fix for header null-termination in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
7681
diff
changeset
|
626 name.data = p; |
1307308c3cf1
Temporary fix for header null-termination in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
7681
diff
changeset
|
627 ngx_memcpy(p + name.len + 1, value.data, value.len); |
1307308c3cf1
Temporary fix for header null-termination in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
7681
diff
changeset
|
628 value.data = p + name.len + 1; |
1307308c3cf1
Temporary fix for header null-termination in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
7681
diff
changeset
|
629 |
7681 | 630 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, |
631 "http3 header \"%V\":\"%V\"", &name, &value); | |
632 | |
633 if (pseudo) { | |
634 rc = ngx_http_v3_process_pseudo_header(r, &name, &value); | |
635 | |
636 if (rc == NGX_ERROR) { | |
637 goto failed; | |
638 } | |
639 | |
640 if (rc == NGX_OK) { | |
641 r->request_end = p + 1; | |
642 goto again; | |
643 } | |
644 | |
645 /* rc == NGX_DONE */ | |
646 | |
647 r->state = sw_old_header; | |
648 } | |
649 | |
650 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
651 "http3 header left:%ui", length); | |
652 | |
653 r->header_name_start = name.data; | |
654 r->header_name_end = name.data + name.len; | |
655 r->header_start = value.data; | |
656 r->header_end = value.data + value.len; | |
657 r->header_hash = ngx_hash_key(name.data, name.len); /* XXX */ | |
658 | |
659 /* XXX r->lowcase_index = i; */ | |
660 | |
661 return NGX_OK; | |
662 | |
663 failed: | |
664 | |
665 return NGX_HTTP_PARSE_INVALID_REQUEST; | |
666 } | |
7692
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
667 #endif |
7681 | 668 |
669 | |
670 static ngx_int_t | |
671 ngx_http_v3_process_pseudo_header(ngx_http_request_t *r, ngx_str_t *name, | |
672 ngx_str_t *value) | |
673 { | |
674 ngx_uint_t i; | |
675 ngx_connection_t *c; | |
676 | |
7692
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
677 if (name->len == 0 || name->data[0] != ':') { |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
678 return NGX_DECLINED; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
679 } |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
680 |
7681 | 681 c = r->connection; |
682 | |
683 if (name->len == 7 && ngx_strncmp(name->data, ":method", 7) == 0) { | |
684 r->method_start = value->data; | |
685 r->method_end = value->data + value->len; | |
686 | |
687 for (i = 0; i < sizeof(ngx_http_v3_methods) | |
688 / sizeof(ngx_http_v3_methods[0]); i++) | |
689 { | |
690 if (value->len == ngx_http_v3_methods[i].name.len | |
691 && ngx_strncmp(value->data, ngx_http_v3_methods[i].name.data, | |
692 value->len) == 0) | |
693 { | |
694 r->method = ngx_http_v3_methods[i].method; | |
695 break; | |
696 } | |
697 } | |
698 | |
699 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
700 "http3 method \"%V\" %ui", value, r->method); | |
701 return NGX_OK; | |
702 } | |
703 | |
704 if (name->len == 5 && ngx_strncmp(name->data, ":path", 5) == 0) { | |
705 r->uri_start = value->data; | |
706 r->uri_end = value->data + value->len; | |
707 | |
708 if (ngx_http_parse_uri(r) != NGX_OK) { | |
709 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
710 "client sent invalid :path header: \"%V\"", value); | |
711 return NGX_ERROR; | |
712 } | |
713 | |
714 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
715 "http3 path \"%V\"", value); | |
716 | |
717 return NGX_OK; | |
718 } | |
719 | |
720 if (name->len == 7 && ngx_strncmp(name->data, ":scheme", 7) == 0) { | |
721 r->schema_start = value->data; | |
722 r->schema_end = value->data + value->len; | |
723 | |
724 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
725 "http3 schema \"%V\"", value); | |
726 | |
727 return NGX_OK; | |
728 } | |
729 | |
730 if (name->len == 10 && ngx_strncmp(name->data, ":authority", 10) == 0) { | |
731 r->host_start = value->data; | |
732 r->host_end = value->data + value->len; | |
733 | |
734 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
735 "http3 authority \"%V\"", value); | |
736 | |
737 return NGX_OK; | |
738 } | |
739 | |
7692
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
740 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
741 "http3 unknown pseudo header \"%V\" \"%V\"", name, value); |
7681 | 742 |
7692
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
743 return NGX_OK; |
7681 | 744 } |
745 | |
746 | |
747 ngx_chain_t * | |
748 ngx_http_v3_create_header(ngx_http_request_t *r) | |
749 { | |
750 u_char *p; | |
751 size_t len, hlen, n; | |
752 ngx_buf_t *b; | |
753 ngx_uint_t i, j; | |
754 ngx_chain_t *hl, *cl, *bl; | |
755 ngx_list_part_t *part; | |
756 ngx_table_elt_t *header; | |
757 ngx_connection_t *c; | |
758 ngx_http_core_loc_conf_t *clcf; | |
759 | |
760 c = r->connection; | |
761 | |
762 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 create header"); | |
763 | |
764 /* XXX support chunked body in the chunked filter */ | |
765 if (r->headers_out.content_length_n == -1) { | |
766 return NULL; | |
767 } | |
768 | |
769 len = 0; | |
770 | |
771 if (r->headers_out.status == NGX_HTTP_OK) { | |
772 len += ngx_http_v3_encode_prefix_int(NULL, 25, 6); | |
773 | |
774 } else { | |
775 len += 3 + ngx_http_v3_encode_prefix_int(NULL, 25, 4) | |
776 + ngx_http_v3_encode_prefix_int(NULL, 3, 7); | |
777 } | |
778 | |
779 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); | |
780 | |
781 if (r->headers_out.server == NULL) { | |
782 if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_ON) { | |
783 n = sizeof(NGINX_VER) - 1; | |
784 | |
785 } else if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_BUILD) { | |
786 n = sizeof(NGINX_VER_BUILD) - 1; | |
787 | |
788 } else { | |
789 n = sizeof("nginx") - 1; | |
790 } | |
791 | |
792 len += ngx_http_v3_encode_prefix_int(NULL, 92, 4) | |
793 + ngx_http_v3_encode_prefix_int(NULL, n, 7) + n; | |
794 } | |
795 | |
796 if (r->headers_out.date == NULL) { | |
797 len += ngx_http_v3_encode_prefix_int(NULL, 6, 4) | |
798 + ngx_http_v3_encode_prefix_int(NULL, ngx_cached_http_time.len, | |
799 7) | |
800 + ngx_cached_http_time.len; | |
801 } | |
802 | |
803 if (r->headers_out.content_type.len) { | |
804 n = r->headers_out.content_type.len; | |
805 | |
806 if (r->headers_out.content_type_len == r->headers_out.content_type.len | |
807 && r->headers_out.charset.len) | |
808 { | |
809 n += sizeof("; charset=") - 1 + r->headers_out.charset.len; | |
810 } | |
811 | |
812 len += ngx_http_v3_encode_prefix_int(NULL, 53, 4) | |
813 + ngx_http_v3_encode_prefix_int(NULL, n, 7) + n; | |
814 } | |
815 | |
816 if (r->headers_out.content_length_n == 0) { | |
817 len += ngx_http_v3_encode_prefix_int(NULL, 4, 6); | |
818 | |
819 } else { | |
820 len += ngx_http_v3_encode_prefix_int(NULL, 4, 4) + 1 + NGX_OFF_T_LEN; | |
821 } | |
822 | |
823 if (r->headers_out.last_modified == NULL | |
824 && r->headers_out.last_modified_time != -1) | |
825 { | |
826 len += ngx_http_v3_encode_prefix_int(NULL, 10, 4) + 1 | |
827 + sizeof("Last-Modified: Mon, 28 Sep 1970 06:00:00 GMT"); | |
828 } | |
829 | |
830 /* XXX location */ | |
831 | |
832 #if (NGX_HTTP_GZIP) | |
833 if (r->gzip_vary) { | |
834 if (clcf->gzip_vary) { | |
835 /* Vary: Accept-Encoding */ | |
836 len += ngx_http_v3_encode_prefix_int(NULL, 59, 6); | |
837 | |
838 } else { | |
839 r->gzip_vary = 0; | |
840 } | |
841 } | |
842 #endif | |
843 | |
844 part = &r->headers_out.headers.part; | |
845 header = part->elts; | |
846 | |
847 for (i = 0; /* void */; i++) { | |
848 | |
849 if (i >= part->nelts) { | |
850 if (part->next == NULL) { | |
851 break; | |
852 } | |
853 | |
854 part = part->next; | |
855 header = part->elts; | |
856 i = 0; | |
857 } | |
858 | |
859 if (header[i].hash == 0) { | |
860 continue; | |
861 } | |
862 | |
863 len += ngx_http_v3_encode_prefix_int(NULL, header[i].key.len, 3) | |
864 + header[i].key.len | |
865 + ngx_http_v3_encode_prefix_int(NULL, header[i].value.len, 7 ) | |
866 + header[i].value.len; | |
867 } | |
868 | |
869 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 header len:%uz", len); | |
870 | |
871 b = ngx_create_temp_buf(r->pool, len); | |
872 if (b == NULL) { | |
873 return NULL; | |
874 } | |
875 | |
876 *b->last++ = 0; | |
877 *b->last++ = 0; | |
878 | |
879 if (r->headers_out.status == NGX_HTTP_OK) { | |
880 /* :status: 200 */ | |
881 *b->last = 0xc0; | |
882 b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, 25, 6); | |
883 | |
884 } else { | |
885 /* :status: 200 */ | |
886 *b->last = 0x70; | |
887 b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, 25, 4); | |
888 *b->last = 0; | |
889 b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, 3, 7); | |
7692
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
7685
diff
changeset
|
890 b->last = ngx_sprintf(b->last, "%03ui", r->headers_out.status); |
7681 | 891 } |
892 | |
893 if (r->headers_out.server == NULL) { | |
894 if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_ON) { | |
895 p = (u_char *) NGINX_VER; | |
896 n = sizeof(NGINX_VER) - 1; | |
897 | |
898 } else if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_BUILD) { | |
899 p = (u_char *) NGINX_VER_BUILD; | |
900 n = sizeof(NGINX_VER_BUILD) - 1; | |
901 | |
902 } else { | |
903 p = (u_char *) "nginx"; | |
904 n = sizeof("nginx") - 1; | |
905 } | |
906 | |
907 /* server */ | |
908 *b->last = 0x70; | |
909 b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, 92, 4); | |
910 *b->last = 0; | |
911 b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, n, 7); | |
912 b->last = ngx_cpymem(b->last, p, n); | |
913 } | |
914 | |
915 if (r->headers_out.date == NULL) { | |
916 /* date */ | |
917 *b->last = 0x70; | |
918 b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, 6, 4); | |
919 *b->last = 0; | |
920 b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, | |
921 ngx_cached_http_time.len, 7); | |
922 b->last = ngx_cpymem(b->last, ngx_cached_http_time.data, | |
923 ngx_cached_http_time.len); | |
924 } | |
925 | |
926 if (r->headers_out.content_type.len) { | |
927 n = r->headers_out.content_type.len; | |
928 | |
929 if (r->headers_out.content_type_len == r->headers_out.content_type.len | |
930 && r->headers_out.charset.len) | |
931 { | |
932 n += sizeof("; charset=") - 1 + r->headers_out.charset.len; | |
933 } | |
934 | |
935 /* content-type: text/plain */ | |
936 *b->last = 0x70; | |
937 b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, 53, 4); | |
938 *b->last = 0; | |
939 b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, n, 7); | |
940 | |
941 p = b->last; | |
942 b->last = ngx_copy(b->last, r->headers_out.content_type.data, | |
943 r->headers_out.content_type.len); | |
944 | |
945 if (r->headers_out.content_type_len == r->headers_out.content_type.len | |
946 && r->headers_out.charset.len) | |
947 { | |
948 b->last = ngx_cpymem(b->last, "; charset=", | |
949 sizeof("; charset=") - 1); | |
950 b->last = ngx_copy(b->last, r->headers_out.charset.data, | |
951 r->headers_out.charset.len); | |
952 | |
953 /* update r->headers_out.content_type for possible logging */ | |
954 | |
955 r->headers_out.content_type.len = b->last - p; | |
956 r->headers_out.content_type.data = p; | |
957 } | |
958 } | |
959 | |
960 if (r->headers_out.content_length_n == 0) { | |
961 /* content-length: 0 */ | |
962 *b->last = 0xc0; | |
963 b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, 4, 6); | |
964 | |
965 } else if (r->headers_out.content_length_n > 0) { | |
966 /* content-length: 0 */ | |
967 *b->last = 0x70; | |
968 b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, 4, 4); | |
969 p = b->last++; | |
970 b->last = ngx_sprintf(b->last, "%O", r->headers_out.content_length_n); | |
971 *p = b->last - p - 1; | |
972 } | |
973 | |
974 if (r->headers_out.last_modified == NULL | |
975 && r->headers_out.last_modified_time != -1) | |
976 { | |
977 /* last-modified */ | |
978 *b->last = 0x70; | |
979 b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, 10, 4); | |
980 p = b->last++; | |
981 b->last = ngx_http_time(b->last, r->headers_out.last_modified_time); | |
982 *p = b->last - p - 1; | |
983 } | |
984 | |
985 #if (NGX_HTTP_GZIP) | |
986 if (r->gzip_vary) { | |
987 /* vary: accept-encoding */ | |
988 *b->last = 0xc0; | |
989 b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, 59, 6); | |
990 } | |
991 #endif | |
992 | |
993 part = &r->headers_out.headers.part; | |
994 header = part->elts; | |
995 | |
996 for (i = 0; /* void */; i++) { | |
997 | |
998 if (i >= part->nelts) { | |
999 if (part->next == NULL) { | |
1000 break; | |
1001 } | |
1002 | |
1003 part = part->next; | |
1004 header = part->elts; | |
1005 i = 0; | |
1006 } | |
1007 | |
1008 if (header[i].hash == 0) { | |
1009 continue; | |
1010 } | |
1011 | |
1012 *b->last = 0x30; | |
1013 b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, | |
1014 header[i].key.len, | |
1015 3); | |
1016 for (j = 0; j < header[i].key.len; j++) { | |
1017 *b->last++ = ngx_tolower(header[i].key.data[j]); | |
1018 } | |
1019 | |
1020 *b->last = 0; | |
1021 b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, | |
1022 header[i].value.len, | |
1023 7); | |
1024 b->last = ngx_copy(b->last, header[i].value.data, header[i].value.len); | |
1025 } | |
1026 | |
1027 cl = ngx_alloc_chain_link(c->pool); | |
1028 if (cl == NULL) { | |
1029 return NULL; | |
1030 } | |
1031 | |
1032 cl->buf = b; | |
1033 cl->next = NULL; | |
1034 | |
1035 n = b->last - b->pos; | |
1036 | |
1037 len = 1 + ngx_http_v3_encode_varlen_int(NULL, n); | |
1038 | |
1039 b = ngx_create_temp_buf(c->pool, len); | |
1040 if (b == NULL) { | |
1041 return NULL; | |
1042 } | |
1043 | |
1044 *b->last++ = NGX_HTTP_V3_FRAME_HEADERS; | |
1045 b->last = (u_char *) ngx_http_v3_encode_varlen_int(b->last, n); | |
1046 | |
1047 hl = ngx_alloc_chain_link(c->pool); | |
1048 if (hl == NULL) { | |
1049 return NULL; | |
1050 } | |
1051 | |
1052 hl->buf = b; | |
1053 hl->next = cl; | |
1054 | |
1055 hlen = 1 + ngx_http_v3_encode_varlen_int(NULL, len); | |
1056 | |
1057 if (r->headers_out.content_length_n >= 0) { | |
1058 len = 1 + ngx_http_v3_encode_varlen_int(NULL, | |
1059 r->headers_out.content_length_n); | |
1060 | |
1061 b = ngx_create_temp_buf(c->pool, len); | |
1062 if (b == NULL) { | |
1063 NULL; | |
1064 } | |
1065 | |
1066 *b->last++ = NGX_HTTP_V3_FRAME_DATA; | |
1067 b->last = (u_char *) ngx_http_v3_encode_varlen_int(b->last, | |
1068 r->headers_out.content_length_n); | |
1069 | |
1070 bl = ngx_alloc_chain_link(c->pool); | |
1071 if (bl == NULL) { | |
1072 return NULL; | |
1073 } | |
1074 | |
1075 bl->buf = b; | |
1076 bl->next = NULL; | |
1077 cl->next = bl; | |
1078 } | |
1079 | |
1080 return hl; | |
1081 } |