1 /*
2 * nghttp2 - HTTP/2 C Library
3 *
4 * Copyright (c) 2015 Tatsuhiro Tsujikawa
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25 #include "nghttp2_http.h"
26
27 #include <string.h>
28 #include <assert.h>
29 #include <stdio.h>
30
31 #include "nghttp2_hd.h"
32 #include "nghttp2_helper.h"
33
downcase(uint8_t c)34 static uint8_t downcase(uint8_t c)
35 {
36 return 'A' <= c && c <= 'Z' ? (uint8_t)(c - 'A' + 'a') : c;
37 }
38
memieq(const void * a,const void * b,size_t n)39 static int memieq(const void *a, const void *b, size_t n)
40 {
41 size_t i;
42 const uint8_t *aa = a, *bb = b;
43
44 for (i = 0; i < n; ++i) {
45 if (downcase(aa[i]) != downcase(bb[i])) {
46 return 0;
47 }
48 }
49 return 1;
50 }
51
52 #define lstrieq(A, B, N) ((sizeof((A)) - 1) == (N) && memieq((A), (B), (N)))
53
parse_uint(const uint8_t * s,size_t len)54 static int64_t parse_uint(const uint8_t *s, size_t len)
55 {
56 int64_t n = 0;
57 size_t i;
58 if (len == 0) {
59 return -1;
60 }
61 for (i = 0; i < len; ++i) {
62 if ('0' <= s[i] && s[i] <= '9') {
63 if (n > INT64_MAX / 10) {
64 return -1;
65 }
66 n *= 10;
67 if (n > INT64_MAX - (s[i] - '0')) {
68 return -1;
69 }
70 n += s[i] - '0';
71 continue;
72 }
73 return -1;
74 }
75 return n;
76 }
77
lws(const uint8_t * s,size_t n)78 static int lws(const uint8_t *s, size_t n)
79 {
80 size_t i;
81 for (i = 0; i < n; ++i) {
82 if (s[i] != ' ' && s[i] != '\t') {
83 return 0;
84 }
85 }
86 return 1;
87 }
88
check_pseudo_header(nghttp2_stream * stream,const nghttp2_hd_nv * nv,int flag)89 static int check_pseudo_header(nghttp2_stream *stream, const nghttp2_hd_nv *nv,
90 int flag)
91 {
92 if (stream->http_flags & flag) {
93 return 0;
94 }
95 if (lws(nv->value->base, nv->value->len)) {
96 return 0;
97 }
98 stream->http_flags = (uint16_t)(stream->http_flags | flag);
99 return 1;
100 }
101
expect_response_body(nghttp2_stream * stream)102 static int expect_response_body(nghttp2_stream *stream)
103 {
104 return (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_HEAD) == 0 &&
105 stream->status_code / 100 != 1 && stream->status_code != 304 &&
106 stream->status_code != 204;
107 }
108
109 /* For "http" or "https" URIs, OPTIONS request may have "*" in :path
110 header field to represent system-wide OPTIONS request. Otherwise,
111 :path header field value must start with "/". This function must
112 be called after ":method" header field was received. This function
113 returns nonzero if path is valid.*/
check_path(nghttp2_stream * stream)114 static int check_path(nghttp2_stream *stream)
115 {
116 return (stream->http_flags & NGHTTP2_HTTP_FLAG_SCHEME_HTTP) == 0 ||
117 ((stream->http_flags & NGHTTP2_HTTP_FLAG_PATH_REGULAR) ||
118 ((stream->http_flags & NGHTTP2_HTTP_FLAG_METH_OPTIONS) &&
119 (stream->http_flags & NGHTTP2_HTTP_FLAG_PATH_ASTERISK)));
120 }
121
http_request_on_header(nghttp2_stream * stream,nghttp2_hd_nv * nv,int trailer)122 static int http_request_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv,
123 int trailer)
124 {
125 if (nv->name->base[0] == ':') {
126 if (trailer ||
127 (stream->http_flags & NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED)) {
128 return NGHTTP2_ERR_HTTP_HEADER;
129 }
130 }
131
132 switch (nv->token) {
133 case NGHTTP2_TOKEN__AUTHORITY:
134 if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__AUTHORITY)) {
135 return NGHTTP2_ERR_HTTP_HEADER;
136 }
137 break;
138 case NGHTTP2_TOKEN__METHOD:
139 if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__METHOD)) {
140 return NGHTTP2_ERR_HTTP_HEADER;
141 }
142 switch (nv->value->len) {
143 case 4:
144 if (lstreq("HEAD", nv->value->base, nv->value->len)) {
145 stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_HEAD;
146 }
147 break;
148 case 7:
149 switch (nv->value->base[6]) {
150 case 'T':
151 if (lstreq("CONNECT", nv->value->base, nv->value->len)) {
152 if (stream->stream_id % 2 == 0) {
153 /* we won't allow CONNECT for push */
154 return NGHTTP2_ERR_HTTP_HEADER;
155 }
156 stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_CONNECT;
157 if (stream->http_flags &
158 (NGHTTP2_HTTP_FLAG__PATH | NGHTTP2_HTTP_FLAG__SCHEME)) {
159 return NGHTTP2_ERR_HTTP_HEADER;
160 }
161 }
162 break;
163 case 'S':
164 if (lstreq("OPTIONS", nv->value->base, nv->value->len)) {
165 stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_OPTIONS;
166 }
167 break;
168 }
169 break;
170 }
171 break;
172 case NGHTTP2_TOKEN__PATH:
173 if (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT) {
174 return NGHTTP2_ERR_HTTP_HEADER;
175 }
176 if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__PATH)) {
177 return NGHTTP2_ERR_HTTP_HEADER;
178 }
179 if (nv->value->base[0] == '/') {
180 stream->http_flags |= NGHTTP2_HTTP_FLAG_PATH_REGULAR;
181 } else if (nv->value->len == 1 && nv->value->base[0] == '*') {
182 stream->http_flags |= NGHTTP2_HTTP_FLAG_PATH_ASTERISK;
183 }
184 break;
185 case NGHTTP2_TOKEN__SCHEME:
186 if (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT) {
187 return NGHTTP2_ERR_HTTP_HEADER;
188 }
189 if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__SCHEME)) {
190 return NGHTTP2_ERR_HTTP_HEADER;
191 }
192 if ((nv->value->len == 4 && memieq("http", nv->value->base, 4)) ||
193 (nv->value->len == 5 && memieq("https", nv->value->base, 5))) {
194 stream->http_flags |= NGHTTP2_HTTP_FLAG_SCHEME_HTTP;
195 }
196 break;
197 case NGHTTP2_TOKEN_HOST:
198 if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG_HOST)) {
199 return NGHTTP2_ERR_HTTP_HEADER;
200 }
201 break;
202 case NGHTTP2_TOKEN_CONTENT_LENGTH:
203 {
204 if (stream->content_length != -1) {
205 return NGHTTP2_ERR_HTTP_HEADER;
206 }
207 stream->content_length =
208 parse_uint(nv->value->base, nv->value->len);
209 if (stream->content_length == -1) {
210 return NGHTTP2_ERR_HTTP_HEADER;
211 }
212 break;
213 }
214 /* disallowed header fields */
215 case NGHTTP2_TOKEN_CONNECTION:
216 case NGHTTP2_TOKEN_KEEP_ALIVE:
217 case NGHTTP2_TOKEN_PROXY_CONNECTION:
218 case NGHTTP2_TOKEN_TRANSFER_ENCODING:
219 case NGHTTP2_TOKEN_UPGRADE:
220 return NGHTTP2_ERR_HTTP_HEADER;
221 case NGHTTP2_TOKEN_TE:
222 if (!lstrieq("trailers", nv->value->base, nv->value->len)) {
223 return NGHTTP2_ERR_HTTP_HEADER;
224 }
225 break;
226 default:
227 if (nv->name->base[0] == ':') {
228 return NGHTTP2_ERR_HTTP_HEADER;
229 }
230 }
231
232 if (nv->name->base[0] != ':') {
233 stream->http_flags |= NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED;
234 }
235
236 return 0;
237 }
238
http_response_on_header(nghttp2_stream * stream,nghttp2_hd_nv * nv,int trailer)239 static int http_response_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv,
240 int trailer)
241 {
242 if (nv->name->base[0] == ':') {
243 if (trailer ||
244 (stream->http_flags & NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED)) {
245 return NGHTTP2_ERR_HTTP_HEADER;
246 }
247 }
248
249 switch (nv->token) {
250 case NGHTTP2_TOKEN__STATUS:
251 {
252 if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__STATUS)) {
253 return NGHTTP2_ERR_HTTP_HEADER;
254 }
255 if (nv->value->len != 3) {
256 return NGHTTP2_ERR_HTTP_HEADER;
257 }
258 stream->status_code =
259 (int16_t)parse_uint(nv->value->base, nv->value->len);
260 if (stream->status_code == -1 || stream->status_code == 101) {
261 return NGHTTP2_ERR_HTTP_HEADER;
262 }
263 break;
264 }
265 case NGHTTP2_TOKEN_CONTENT_LENGTH:
266 {
267 if (stream->status_code == 204) {
268 /* content-length header field in 204 response is prohibited by
269 RFC 7230. But some widely used servers send content-length:
270 0. Until they get fixed, we ignore it. */
271 if (stream->content_length != -1) {
272 /* Found multiple content-length field */
273 return NGHTTP2_ERR_HTTP_HEADER;
274 }
275 if (!lstrieq("0", nv->value->base, nv->value->len)) {
276 return NGHTTP2_ERR_HTTP_HEADER;
277 }
278 stream->content_length = 0;
279 return NGHTTP2_ERR_REMOVE_HTTP_HEADER;
280 }
281 if (stream->status_code / 100 == 1 ||
282 (stream->status_code == 200 &&
283 (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT))) {
284 return NGHTTP2_ERR_HTTP_HEADER;
285 }
286 if (stream->content_length != -1) {
287 return NGHTTP2_ERR_HTTP_HEADER;
288 }
289 stream->content_length =
290 parse_uint(nv->value->base, nv->value->len);
291 if (stream->content_length == -1) {
292 return NGHTTP2_ERR_HTTP_HEADER;
293 }
294 break;
295 }
296 /* disallowed header fields */
297 case NGHTTP2_TOKEN_CONNECTION:
298 case NGHTTP2_TOKEN_KEEP_ALIVE:
299 case NGHTTP2_TOKEN_PROXY_CONNECTION:
300 case NGHTTP2_TOKEN_TRANSFER_ENCODING:
301 case NGHTTP2_TOKEN_UPGRADE:
302 return NGHTTP2_ERR_HTTP_HEADER;
303 case NGHTTP2_TOKEN_TE:
304 if (!lstrieq("trailers", nv->value->base, nv->value->len)) {
305 return NGHTTP2_ERR_HTTP_HEADER;
306 }
307 break;
308 default:
309 if (nv->name->base[0] == ':') {
310 return NGHTTP2_ERR_HTTP_HEADER;
311 }
312 }
313
314 if (nv->name->base[0] != ':') {
315 stream->http_flags |= NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED;
316 }
317
318 return 0;
319 }
320
321 /* Generated by genauthroitychartbl.py */
322 static char VALID_AUTHORITY_CHARS[] = {
323 0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
324 0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,
325 0 /* BS */, 0 /* HT */, 0 /* LF */, 0 /* VT */,
326 0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */,
327 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
328 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */,
329 0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */,
330 0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */,
331 0 /* SPC */, 1 /* ! */, 0 /* " */, 0 /* # */,
332 1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */,
333 1 /* ( */, 1 /* ) */, 1 /* * */, 1 /* + */,
334 1 /* , */, 1 /* - */, 1 /* . */, 0 /* / */,
335 1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */,
336 1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */,
337 1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */,
338 0 /* < */, 1 /* = */, 0 /* > */, 0 /* ? */,
339 1 /* @ */, 1 /* A */, 1 /* B */, 1 /* C */,
340 1 /* D */, 1 /* E */, 1 /* F */, 1 /* G */,
341 1 /* H */, 1 /* I */, 1 /* J */, 1 /* K */,
342 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */,
343 1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */,
344 1 /* T */, 1 /* U */, 1 /* V */, 1 /* W */,
345 1 /* X */, 1 /* Y */, 1 /* Z */, 1 /* [ */,
346 0 /* \ */, 1 /* ] */, 0 /* ^ */, 1 /* _ */,
347 0 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
348 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */,
349 1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */,
350 1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */,
351 1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */,
352 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
353 1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */,
354 0 /* | */, 0 /* } */, 1 /* ~ */, 0 /* DEL */,
355 0 /* 0x80 */, 0 /* 0x81 */, 0 /* 0x82 */, 0 /* 0x83 */,
356 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, 0 /* 0x87 */,
357 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
358 0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */,
359 0 /* 0x90 */, 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */,
360 0 /* 0x94 */, 0 /* 0x95 */, 0 /* 0x96 */, 0 /* 0x97 */,
361 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, 0 /* 0x9b */,
362 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
363 0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */,
364 0 /* 0xa4 */, 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */,
365 0 /* 0xa8 */, 0 /* 0xa9 */, 0 /* 0xaa */, 0 /* 0xab */,
366 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, 0 /* 0xaf */,
367 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
368 0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */,
369 0 /* 0xb8 */, 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */,
370 0 /* 0xbc */, 0 /* 0xbd */, 0 /* 0xbe */, 0 /* 0xbf */,
371 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, 0 /* 0xc3 */,
372 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
373 0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */,
374 0 /* 0xcc */, 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */,
375 0 /* 0xd0 */, 0 /* 0xd1 */, 0 /* 0xd2 */, 0 /* 0xd3 */,
376 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, 0 /* 0xd7 */,
377 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
378 0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */,
379 0 /* 0xe0 */, 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */,
380 0 /* 0xe4 */, 0 /* 0xe5 */, 0 /* 0xe6 */, 0 /* 0xe7 */,
381 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, 0 /* 0xeb */,
382 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
383 0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */,
384 0 /* 0xf4 */, 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */,
385 0 /* 0xf8 */, 0 /* 0xf9 */, 0 /* 0xfa */, 0 /* 0xfb */,
386 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, 0 /* 0xff */
387 };
388
check_authority(const uint8_t * value,size_t len)389 static int check_authority(const uint8_t *value, size_t len)
390 {
391 const uint8_t *last;
392 for (last = value + len; value != last; ++value) {
393 if (!VALID_AUTHORITY_CHARS[*value]) {
394 return 0;
395 }
396 }
397 return 1;
398 }
399
check_scheme(const uint8_t * value,size_t len)400 static int check_scheme(const uint8_t *value, size_t len)
401 {
402 const uint8_t *last;
403 if (len == 0) {
404 return 0;
405 }
406
407 if (!(('A' <= *value && *value <= 'Z') ||
408 ('a' <= *value && *value <= 'z'))) {
409 return 0;
410 }
411
412 last = value + len;
413 ++value;
414
415 for (; value != last; ++value) {
416 if (!(('A' <= *value && *value <= 'Z') ||
417 ('a' <= *value && *value <= 'z') ||
418 ('0' <= *value && *value <= '9') || *value == '+' ||
419 *value == '-' || *value == '.')) {
420 return 0;
421 }
422 }
423 return 1;
424 }
425
nghttp2_http_on_header(nghttp2_session * session,nghttp2_stream * stream,nghttp2_frame * frame,nghttp2_hd_nv * nv,int trailer)426 int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream,
427 nghttp2_frame *frame, nghttp2_hd_nv *nv, int trailer)
428 {
429 int rv;
430
431 /* We are strict for pseudo header field. One bad character should
432 lead to fail. OTOH, we should be a bit forgiving for regular
433 headers, since existing public internet has so much illegal
434 headers floating around and if we kill the stream because of
435 this, we may disrupt many web sites and/or libraries. So we
436 become conservative here, and just ignore those illegal regular
437 headers. */
438 if (!nghttp2_check_header_name(nv->name->base, nv->name->len)) {
439 size_t i;
440 if (nv->name->len > 0 && nv->name->base[0] == ':') {
441 return NGHTTP2_ERR_HTTP_HEADER;
442 }
443 /* header field name must be lower-cased without exception */
444 for (i = 0; i < nv->name->len; ++i) {
445 uint8_t c = nv->name->base[i];
446 if ('A' <= c && c <= 'Z') {
447 return NGHTTP2_ERR_HTTP_HEADER;
448 }
449 }
450 /* When ignoring regular headers, we set this flag so that we
451 still enforce header field ordering rule for pseudo header
452 fields. */
453 stream->http_flags |= NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED;
454 return NGHTTP2_ERR_IGN_HTTP_HEADER;
455 }
456
457 if (nv->token == NGHTTP2_TOKEN__AUTHORITY ||
458 nv->token == NGHTTP2_TOKEN_HOST) {
459 rv = check_authority(nv->value->base, nv->value->len);
460 } else if (nv->token == NGHTTP2_TOKEN__SCHEME) {
461 rv = check_scheme(nv->value->base, nv->value->len);
462 } else {
463 rv = nghttp2_check_header_value(nv->value->base, nv->value->len);
464 }
465
466 if (rv == 0) {
467 assert(nv->name->len > 0);
468 if (nv->name->base[0] == ':') {
469 return NGHTTP2_ERR_HTTP_HEADER;
470 }
471 /* When ignoring regular headers, we set this flag so that we
472 still enforce header field ordering rule for pseudo header
473 fields. */
474 stream->http_flags |= NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED;
475 return NGHTTP2_ERR_IGN_HTTP_HEADER;
476 }
477
478 if (session->server || frame->hd.type == NGHTTP2_PUSH_PROMISE) {
479 return http_request_on_header(stream, nv, trailer);
480 }
481
482 return http_response_on_header(stream, nv, trailer);
483 }
484
nghttp2_http_on_request_headers(nghttp2_stream * stream,nghttp2_frame * frame)485 int nghttp2_http_on_request_headers(nghttp2_stream *stream,
486 nghttp2_frame *frame)
487 {
488 if (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT) {
489 if ((stream->http_flags & NGHTTP2_HTTP_FLAG__AUTHORITY) == 0) {
490 return -1;
491 }
492 stream->content_length = -1;
493 } else {
494 if ((stream->http_flags & NGHTTP2_HTTP_FLAG_REQ_HEADERS) !=
495 NGHTTP2_HTTP_FLAG_REQ_HEADERS ||
496 (stream->http_flags &
497 (NGHTTP2_HTTP_FLAG__AUTHORITY | NGHTTP2_HTTP_FLAG_HOST)) == 0) {
498 return -1;
499 }
500 if (!check_path(stream)) {
501 return -1;
502 }
503 }
504
505 if (frame->hd.type == NGHTTP2_PUSH_PROMISE) {
506 /* we are going to reuse data fields for upcoming response. Clear
507 them now, except for method flags. */
508 stream->http_flags &= NGHTTP2_HTTP_FLAG_METH_ALL;
509 stream->content_length = -1;
510 }
511
512 return 0;
513 }
514
nghttp2_http_on_response_headers(nghttp2_stream * stream)515 int nghttp2_http_on_response_headers(nghttp2_stream *stream)
516 {
517 if ((stream->http_flags & NGHTTP2_HTTP_FLAG__STATUS) == 0) {
518 return -1;
519 }
520
521 if (stream->status_code / 100 == 1) {
522 /* non-final response */
523 stream->http_flags =
524 (uint16_t)((stream->http_flags & NGHTTP2_HTTP_FLAG_METH_ALL) |
525 NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE);
526 stream->content_length = -1;
527 stream->status_code = -1;
528 return 0;
529 }
530
531 stream->http_flags = (uint16_t)(stream->http_flags &
532 ~NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE);
533
534 if (!expect_response_body(stream)) {
535 stream->content_length = 0;
536 } else if (stream->http_flags &
537 (NGHTTP2_HTTP_FLAG_METH_CONNECT |
538 NGHTTP2_HTTP_FLAG_METH_UPGRADE_WORKAROUND)) {
539 stream->content_length = -1;
540 }
541
542 return 0;
543 }
544
nghttp2_http_on_trailer_headers(nghttp2_stream * stream,nghttp2_frame * frame)545 int nghttp2_http_on_trailer_headers(nghttp2_stream *stream,
546 nghttp2_frame *frame)
547 {
548 (void)stream;
549
550 if ((frame->hd.flags & NGHTTP2_FLAG_END_STREAM) == 0) {
551 return -1;
552 }
553
554 return 0;
555 }
556
nghttp2_http_on_remote_end_stream(nghttp2_stream * stream)557 int nghttp2_http_on_remote_end_stream(nghttp2_stream *stream)
558 {
559 if (stream->http_flags & NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE) {
560 return -1;
561 }
562
563 if (stream->content_length != -1 &&
564 stream->content_length != stream->recv_content_length) {
565 return -1;
566 }
567
568 return 0;
569 }
570
nghttp2_http_on_data_chunk(nghttp2_stream * stream,size_t n)571 int nghttp2_http_on_data_chunk(nghttp2_stream *stream, size_t n)
572 {
573 stream->recv_content_length += (int64_t)n;
574
575 if ((stream->http_flags & NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE) ||
576 (stream->content_length != -1 &&
577 stream->recv_content_length > stream->content_length)) {
578 return -1;
579 }
580
581 return 0;
582 }
583
nghttp2_http_record_request_method(nghttp2_stream * stream,nghttp2_frame * frame)584 void nghttp2_http_record_request_method(nghttp2_stream *stream,
585 nghttp2_frame *frame)
586 {
587 const nghttp2_nv *nva;
588 size_t nvlen;
589 size_t i;
590
591 switch (frame->hd.type) {
592 case NGHTTP2_HEADERS:
593 nva = frame->headers.nva;
594 nvlen = frame->headers.nvlen;
595 break;
596 case NGHTTP2_PUSH_PROMISE:
597 nva = frame->push_promise.nva;
598 nvlen = frame->push_promise.nvlen;
599 break;
600 default:
601 return;
602 }
603
604 /* TODO we should do this strictly. */
605 for (i = 0; i < nvlen; ++i) {
606 const nghttp2_nv *nv = &nva[i];
607 if (!(nv->namelen == 7 && nv->name[6] == 'd' &&
608 memcmp(":metho", nv->name, nv->namelen - 1) == 0)) {
609 continue;
610 }
611 if (lstreq("CONNECT", nv->value, nv->valuelen)) {
612 stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_CONNECT;
613 return;
614 }
615 if (lstreq("HEAD", nv->value, nv->valuelen)) {
616 stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_HEAD;
617 return;
618 }
619 return;
620 }
621 }
622