Mercurial > hg > nginx
annotate src/http/v3/ngx_http_v3_request.c @ 8549:d70a38acaea0 quic
HTTP/3: skip unknown frames on request stream.
As per HTTP/3 draft 29, section 4.1:
Frames of unknown types (Section 9), including reserved frames
(Section 7.2.8) MAY be sent on a request or push stream before,
after, or interleaved with other frames described in this section.
Also, trailers frame is now used as an indication of the request body end.
author | Roman Arutyunyan <arut@nginx.com> |
---|---|
date | Mon, 24 Aug 2020 09:56:36 +0300 |
parents | 9ffef6054abf |
children | 279ad36f2f4b |
rev | line source |
---|---|
8215 | 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 | |
8488
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
13 /* static table indices */ |
8497 | 14 #define NGX_HTTP_V3_HEADER_AUTHORITY 0 |
15 #define NGX_HTTP_V3_HEADER_PATH_ROOT 1 | |
8488
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
16 #define NGX_HTTP_V3_HEADER_CONTENT_LENGTH_ZERO 4 |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
17 #define NGX_HTTP_V3_HEADER_DATE 6 |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
18 #define NGX_HTTP_V3_HEADER_LAST_MODIFIED 10 |
8489
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
19 #define NGX_HTTP_V3_HEADER_LOCATION 12 |
8497 | 20 #define NGX_HTTP_V3_HEADER_METHOD_GET 17 |
21 #define NGX_HTTP_V3_HEADER_SCHEME_HTTP 22 | |
22 #define NGX_HTTP_V3_HEADER_SCHEME_HTTPS 23 | |
8488
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
23 #define NGX_HTTP_V3_HEADER_STATUS_200 25 |
8497 | 24 #define NGX_HTTP_V3_HEADER_ACCEPT_ENCODING 31 |
8488
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
25 #define NGX_HTTP_V3_HEADER_CONTENT_TYPE_TEXT_PLAIN 53 |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
26 #define NGX_HTTP_V3_HEADER_VARY_ACCEPT_ENCODING 59 |
8497 | 27 #define NGX_HTTP_V3_HEADER_ACCEPT_LANGUAGE 72 |
8488
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
28 #define NGX_HTTP_V3_HEADER_SERVER 92 |
8497 | 29 #define NGX_HTTP_V3_HEADER_USER_AGENT 95 |
8488
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
30 |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
31 |
8215 | 32 static ngx_int_t ngx_http_v3_process_pseudo_header(ngx_http_request_t *r, |
33 ngx_str_t *name, ngx_str_t *value); | |
8497 | 34 static ngx_int_t ngx_http_v3_push_resources(ngx_http_request_t *r, |
35 ngx_chain_t ***out); | |
36 static ngx_int_t ngx_http_v3_push_resource(ngx_http_request_t *r, | |
37 ngx_str_t *path, ngx_chain_t ***out); | |
38 static ngx_int_t ngx_http_v3_create_push_request( | |
39 ngx_http_request_t *pr, ngx_str_t *path, uint64_t push_id); | |
40 static ngx_int_t ngx_http_v3_set_push_header(ngx_http_request_t *r, | |
41 const char *name, ngx_str_t *value); | |
42 static void ngx_http_v3_push_request_handler(ngx_event_t *ev); | |
43 static ngx_chain_t *ngx_http_v3_create_push_promise(ngx_http_request_t *r, | |
44 ngx_str_t *path, uint64_t push_id); | |
8215 | 45 |
46 | |
47 struct { | |
48 ngx_str_t name; | |
49 ngx_uint_t method; | |
50 } ngx_http_v3_methods[] = { | |
51 | |
52 { ngx_string("GET"), NGX_HTTP_GET }, | |
53 { ngx_string("POST"), NGX_HTTP_POST }, | |
54 { ngx_string("HEAD"), NGX_HTTP_HEAD }, | |
55 { ngx_string("OPTIONS"), NGX_HTTP_OPTIONS }, | |
56 { ngx_string("PROPFIND"), NGX_HTTP_PROPFIND }, | |
57 { ngx_string("PUT"), NGX_HTTP_PUT }, | |
58 { ngx_string("MKCOL"), NGX_HTTP_MKCOL }, | |
59 { ngx_string("DELETE"), NGX_HTTP_DELETE }, | |
60 { ngx_string("COPY"), NGX_HTTP_COPY }, | |
61 { ngx_string("MOVE"), NGX_HTTP_MOVE }, | |
62 { ngx_string("PROPPATCH"), NGX_HTTP_PROPPATCH }, | |
63 { ngx_string("LOCK"), NGX_HTTP_LOCK }, | |
64 { ngx_string("UNLOCK"), NGX_HTTP_UNLOCK }, | |
65 { ngx_string("PATCH"), NGX_HTTP_PATCH }, | |
66 { ngx_string("TRACE"), NGX_HTTP_TRACE } | |
67 }; | |
68 | |
69 | |
70 ngx_int_t | |
8405
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
71 ngx_http_v3_parse_request(ngx_http_request_t *r, ngx_buf_t *b) |
8226
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
72 { |
8405
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
73 size_t len; |
8233
1e45c02f6376
HTTP/3 $request_line variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8230
diff
changeset
|
74 u_char *p; |
8405
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
75 ngx_int_t rc, n; |
8226
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
76 ngx_str_t *name, *value; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
77 ngx_connection_t *c; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
78 ngx_http_v3_parse_headers_t *st; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
79 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
80 c = r->connection; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
81 st = r->h3_parse; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
82 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
83 if (st == NULL) { |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
84 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse header"); |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
85 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
86 st = ngx_pcalloc(c->pool, sizeof(ngx_http_v3_parse_headers_t)); |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
87 if (st == NULL) { |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
88 goto failed; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
89 } |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
90 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
91 r->h3_parse = st; |
8407
d6feece1288a
Fixed $request_length for HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8406
diff
changeset
|
92 r->parse_start = b->pos; |
8408
5b367070cc9c
Fixed client buffer reallocation for HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8407
diff
changeset
|
93 r->state = 1; |
8226
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
94 } |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
95 |
8230
31f7c697b6d9
Fixed pointer increment while parsing HTTP/3 header.
Roman Arutyunyan <arut@nginx.com>
parents:
8226
diff
changeset
|
96 while (b->pos < b->last) { |
8456
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8452
diff
changeset
|
97 rc = ngx_http_v3_parse_headers(c, st, *b->pos); |
8226
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
98 |
8460
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8456
diff
changeset
|
99 if (rc > 0) { |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8456
diff
changeset
|
100 ngx_http_v3_finalize_connection(c, rc, |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8456
diff
changeset
|
101 "could not parse request headers"); |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8456
diff
changeset
|
102 goto failed; |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8456
diff
changeset
|
103 } |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8456
diff
changeset
|
104 |
8226
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
105 if (rc == NGX_ERROR) { |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
106 goto failed; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
107 } |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
108 |
8456
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8452
diff
changeset
|
109 if (rc == NGX_BUSY) { |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8452
diff
changeset
|
110 return NGX_BUSY; |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8452
diff
changeset
|
111 } |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8452
diff
changeset
|
112 |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8452
diff
changeset
|
113 b->pos++; |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8452
diff
changeset
|
114 |
8226
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
115 if (rc == NGX_AGAIN) { |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
116 continue; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
117 } |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
118 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
119 name = &st->header_rep.header.name; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
120 value = &st->header_rep.header.value; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
121 |
8405
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
122 n = ngx_http_v3_process_pseudo_header(r, name, value); |
8233
1e45c02f6376
HTTP/3 $request_line variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8230
diff
changeset
|
123 |
8405
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
124 if (n == NGX_ERROR) { |
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
125 goto failed; |
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
126 } |
8233
1e45c02f6376
HTTP/3 $request_line variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8230
diff
changeset
|
127 |
8405
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
128 if (n == NGX_OK && rc == NGX_OK) { |
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
129 continue; |
8226
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
130 } |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
131 |
8494
e334ca1b23ba
HTTP/3: support $server_protocol variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8490
diff
changeset
|
132 ngx_str_set(&r->http_protocol, "HTTP/3.0"); |
e334ca1b23ba
HTTP/3: support $server_protocol variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8490
diff
changeset
|
133 |
8405
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
134 len = (r->method_end - r->method_start) + 1 |
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
135 + (r->uri_end - r->uri_start) + 1 |
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
136 + sizeof("HTTP/3") - 1; |
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
137 |
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
138 p = ngx_pnalloc(c->pool, len); |
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
139 if (p == NULL) { |
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
140 goto failed; |
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
141 } |
8226
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
142 |
8405
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
143 r->request_start = p; |
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
144 |
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
145 p = ngx_cpymem(p, r->method_start, r->method_end - r->method_start); |
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
146 *p++ = ' '; |
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
147 p = ngx_cpymem(p, r->uri_start, r->uri_end - r->uri_start); |
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
148 *p++ = ' '; |
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
149 p = ngx_cpymem(p, "HTTP/3", sizeof("HTTP/3") - 1); |
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
150 |
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
151 r->request_end = p; |
8452
a6675a976560
HTTP/3: fixed dropping first non-pseudo header.
Roman Arutyunyan <arut@nginx.com>
parents:
8451
diff
changeset
|
152 r->state = 0; |
8226
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
153 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
154 return NGX_OK; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
155 } |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
156 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
157 return NGX_AGAIN; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
158 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
159 failed: |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
160 |
8405
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
161 return NGX_HTTP_PARSE_INVALID_REQUEST; |
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
162 } |
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
163 |
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
164 |
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
165 ngx_int_t |
8406
66feab03d9b7
HTTP/3: restricted symbols in header names.
Roman Arutyunyan <arut@nginx.com>
parents:
8405
diff
changeset
|
166 ngx_http_v3_parse_header(ngx_http_request_t *r, ngx_buf_t *b, |
66feab03d9b7
HTTP/3: restricted symbols in header names.
Roman Arutyunyan <arut@nginx.com>
parents:
8405
diff
changeset
|
167 ngx_uint_t allow_underscores) |
8405
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
168 { |
8406
66feab03d9b7
HTTP/3: restricted symbols in header names.
Roman Arutyunyan <arut@nginx.com>
parents:
8405
diff
changeset
|
169 u_char ch; |
8405
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
170 ngx_int_t rc; |
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
171 ngx_str_t *name, *value; |
8406
66feab03d9b7
HTTP/3: restricted symbols in header names.
Roman Arutyunyan <arut@nginx.com>
parents:
8405
diff
changeset
|
172 ngx_uint_t hash, i, n; |
8405
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
173 ngx_connection_t *c; |
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
174 ngx_http_v3_parse_headers_t *st; |
8452
a6675a976560
HTTP/3: fixed dropping first non-pseudo header.
Roman Arutyunyan <arut@nginx.com>
parents:
8451
diff
changeset
|
175 enum { |
a6675a976560
HTTP/3: fixed dropping first non-pseudo header.
Roman Arutyunyan <arut@nginx.com>
parents:
8451
diff
changeset
|
176 sw_start = 0, |
a6675a976560
HTTP/3: fixed dropping first non-pseudo header.
Roman Arutyunyan <arut@nginx.com>
parents:
8451
diff
changeset
|
177 sw_done, |
a6675a976560
HTTP/3: fixed dropping first non-pseudo header.
Roman Arutyunyan <arut@nginx.com>
parents:
8451
diff
changeset
|
178 sw_next, |
a6675a976560
HTTP/3: fixed dropping first non-pseudo header.
Roman Arutyunyan <arut@nginx.com>
parents:
8451
diff
changeset
|
179 sw_header |
a6675a976560
HTTP/3: fixed dropping first non-pseudo header.
Roman Arutyunyan <arut@nginx.com>
parents:
8451
diff
changeset
|
180 }; |
8405
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
181 |
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
182 c = r->connection; |
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
183 st = r->h3_parse; |
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
184 |
8452
a6675a976560
HTTP/3: fixed dropping first non-pseudo header.
Roman Arutyunyan <arut@nginx.com>
parents:
8451
diff
changeset
|
185 switch (r->state) { |
a6675a976560
HTTP/3: fixed dropping first non-pseudo header.
Roman Arutyunyan <arut@nginx.com>
parents:
8451
diff
changeset
|
186 |
a6675a976560
HTTP/3: fixed dropping first non-pseudo header.
Roman Arutyunyan <arut@nginx.com>
parents:
8451
diff
changeset
|
187 case sw_start: |
a6675a976560
HTTP/3: fixed dropping first non-pseudo header.
Roman Arutyunyan <arut@nginx.com>
parents:
8451
diff
changeset
|
188 r->parse_start = b->pos; |
a6675a976560
HTTP/3: fixed dropping first non-pseudo header.
Roman Arutyunyan <arut@nginx.com>
parents:
8451
diff
changeset
|
189 |
a6675a976560
HTTP/3: fixed dropping first non-pseudo header.
Roman Arutyunyan <arut@nginx.com>
parents:
8451
diff
changeset
|
190 if (st->state) { |
a6675a976560
HTTP/3: fixed dropping first non-pseudo header.
Roman Arutyunyan <arut@nginx.com>
parents:
8451
diff
changeset
|
191 r->state = sw_next; |
a6675a976560
HTTP/3: fixed dropping first non-pseudo header.
Roman Arutyunyan <arut@nginx.com>
parents:
8451
diff
changeset
|
192 goto done; |
a6675a976560
HTTP/3: fixed dropping first non-pseudo header.
Roman Arutyunyan <arut@nginx.com>
parents:
8451
diff
changeset
|
193 } |
a6675a976560
HTTP/3: fixed dropping first non-pseudo header.
Roman Arutyunyan <arut@nginx.com>
parents:
8451
diff
changeset
|
194 |
a6675a976560
HTTP/3: fixed dropping first non-pseudo header.
Roman Arutyunyan <arut@nginx.com>
parents:
8451
diff
changeset
|
195 name = &st->header_rep.header.name; |
a6675a976560
HTTP/3: fixed dropping first non-pseudo header.
Roman Arutyunyan <arut@nginx.com>
parents:
8451
diff
changeset
|
196 |
a6675a976560
HTTP/3: fixed dropping first non-pseudo header.
Roman Arutyunyan <arut@nginx.com>
parents:
8451
diff
changeset
|
197 if (name->len && name->data[0] != ':') { |
a6675a976560
HTTP/3: fixed dropping first non-pseudo header.
Roman Arutyunyan <arut@nginx.com>
parents:
8451
diff
changeset
|
198 r->state = sw_done; |
a6675a976560
HTTP/3: fixed dropping first non-pseudo header.
Roman Arutyunyan <arut@nginx.com>
parents:
8451
diff
changeset
|
199 goto done; |
a6675a976560
HTTP/3: fixed dropping first non-pseudo header.
Roman Arutyunyan <arut@nginx.com>
parents:
8451
diff
changeset
|
200 } |
a6675a976560
HTTP/3: fixed dropping first non-pseudo header.
Roman Arutyunyan <arut@nginx.com>
parents:
8451
diff
changeset
|
201 |
a6675a976560
HTTP/3: fixed dropping first non-pseudo header.
Roman Arutyunyan <arut@nginx.com>
parents:
8451
diff
changeset
|
202 /* fall through */ |
a6675a976560
HTTP/3: fixed dropping first non-pseudo header.
Roman Arutyunyan <arut@nginx.com>
parents:
8451
diff
changeset
|
203 |
a6675a976560
HTTP/3: fixed dropping first non-pseudo header.
Roman Arutyunyan <arut@nginx.com>
parents:
8451
diff
changeset
|
204 case sw_done: |
a6675a976560
HTTP/3: fixed dropping first non-pseudo header.
Roman Arutyunyan <arut@nginx.com>
parents:
8451
diff
changeset
|
205 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, |
a6675a976560
HTTP/3: fixed dropping first non-pseudo header.
Roman Arutyunyan <arut@nginx.com>
parents:
8451
diff
changeset
|
206 "http3 parse header done"); |
a6675a976560
HTTP/3: fixed dropping first non-pseudo header.
Roman Arutyunyan <arut@nginx.com>
parents:
8451
diff
changeset
|
207 return NGX_HTTP_PARSE_HEADER_DONE; |
a6675a976560
HTTP/3: fixed dropping first non-pseudo header.
Roman Arutyunyan <arut@nginx.com>
parents:
8451
diff
changeset
|
208 |
a6675a976560
HTTP/3: fixed dropping first non-pseudo header.
Roman Arutyunyan <arut@nginx.com>
parents:
8451
diff
changeset
|
209 case sw_next: |
8407
d6feece1288a
Fixed $request_length for HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8406
diff
changeset
|
210 r->parse_start = b->pos; |
8406
66feab03d9b7
HTTP/3: restricted symbols in header names.
Roman Arutyunyan <arut@nginx.com>
parents:
8405
diff
changeset
|
211 r->invalid_header = 0; |
8452
a6675a976560
HTTP/3: fixed dropping first non-pseudo header.
Roman Arutyunyan <arut@nginx.com>
parents:
8451
diff
changeset
|
212 break; |
8405
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
213 |
8452
a6675a976560
HTTP/3: fixed dropping first non-pseudo header.
Roman Arutyunyan <arut@nginx.com>
parents:
8451
diff
changeset
|
214 case sw_header: |
a6675a976560
HTTP/3: fixed dropping first non-pseudo header.
Roman Arutyunyan <arut@nginx.com>
parents:
8451
diff
changeset
|
215 break; |
8405
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
216 } |
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
217 |
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
218 while (b->pos < b->last) { |
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
219 rc = ngx_http_v3_parse_headers(c, st, *b->pos++); |
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
220 |
8460
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8456
diff
changeset
|
221 if (rc > 0) { |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8456
diff
changeset
|
222 ngx_http_v3_finalize_connection(c, rc, |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8456
diff
changeset
|
223 "could not parse request headers"); |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8456
diff
changeset
|
224 return NGX_HTTP_PARSE_INVALID_HEADER; |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8456
diff
changeset
|
225 } |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8456
diff
changeset
|
226 |
8405
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
227 if (rc == NGX_ERROR) { |
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
228 return NGX_HTTP_PARSE_INVALID_HEADER; |
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
229 } |
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
230 |
8452
a6675a976560
HTTP/3: fixed dropping first non-pseudo header.
Roman Arutyunyan <arut@nginx.com>
parents:
8451
diff
changeset
|
231 if (rc == NGX_DONE) { |
a6675a976560
HTTP/3: fixed dropping first non-pseudo header.
Roman Arutyunyan <arut@nginx.com>
parents:
8451
diff
changeset
|
232 r->state = sw_done; |
a6675a976560
HTTP/3: fixed dropping first non-pseudo header.
Roman Arutyunyan <arut@nginx.com>
parents:
8451
diff
changeset
|
233 goto done; |
a6675a976560
HTTP/3: fixed dropping first non-pseudo header.
Roman Arutyunyan <arut@nginx.com>
parents:
8451
diff
changeset
|
234 } |
a6675a976560
HTTP/3: fixed dropping first non-pseudo header.
Roman Arutyunyan <arut@nginx.com>
parents:
8451
diff
changeset
|
235 |
a6675a976560
HTTP/3: fixed dropping first non-pseudo header.
Roman Arutyunyan <arut@nginx.com>
parents:
8451
diff
changeset
|
236 if (rc == NGX_OK) { |
a6675a976560
HTTP/3: fixed dropping first non-pseudo header.
Roman Arutyunyan <arut@nginx.com>
parents:
8451
diff
changeset
|
237 r->state = sw_next; |
8405
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
238 goto done; |
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
239 } |
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
240 } |
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
241 |
8452
a6675a976560
HTTP/3: fixed dropping first non-pseudo header.
Roman Arutyunyan <arut@nginx.com>
parents:
8451
diff
changeset
|
242 r->state = sw_header; |
8405
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
243 return NGX_AGAIN; |
8226
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
244 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
245 done: |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
246 |
8405
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
247 name = &st->header_rep.header.name; |
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
248 value = &st->header_rep.header.value; |
8226
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
249 |
8405
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
250 r->header_name_start = name->data; |
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
251 r->header_name_end = name->data + name->len; |
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
252 r->header_start = value->data; |
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
253 r->header_end = value->data + value->len; |
8406
66feab03d9b7
HTTP/3: restricted symbols in header names.
Roman Arutyunyan <arut@nginx.com>
parents:
8405
diff
changeset
|
254 |
66feab03d9b7
HTTP/3: restricted symbols in header names.
Roman Arutyunyan <arut@nginx.com>
parents:
8405
diff
changeset
|
255 hash = 0; |
66feab03d9b7
HTTP/3: restricted symbols in header names.
Roman Arutyunyan <arut@nginx.com>
parents:
8405
diff
changeset
|
256 i = 0; |
66feab03d9b7
HTTP/3: restricted symbols in header names.
Roman Arutyunyan <arut@nginx.com>
parents:
8405
diff
changeset
|
257 |
66feab03d9b7
HTTP/3: restricted symbols in header names.
Roman Arutyunyan <arut@nginx.com>
parents:
8405
diff
changeset
|
258 for (n = 0; n < name->len; n++) { |
66feab03d9b7
HTTP/3: restricted symbols in header names.
Roman Arutyunyan <arut@nginx.com>
parents:
8405
diff
changeset
|
259 ch = name->data[n]; |
66feab03d9b7
HTTP/3: restricted symbols in header names.
Roman Arutyunyan <arut@nginx.com>
parents:
8405
diff
changeset
|
260 |
66feab03d9b7
HTTP/3: restricted symbols in header names.
Roman Arutyunyan <arut@nginx.com>
parents:
8405
diff
changeset
|
261 if (ch >= 'A' && ch <= 'Z') { |
66feab03d9b7
HTTP/3: restricted symbols in header names.
Roman Arutyunyan <arut@nginx.com>
parents:
8405
diff
changeset
|
262 /* |
66feab03d9b7
HTTP/3: restricted symbols in header names.
Roman Arutyunyan <arut@nginx.com>
parents:
8405
diff
changeset
|
263 * A request or response containing uppercase |
66feab03d9b7
HTTP/3: restricted symbols in header names.
Roman Arutyunyan <arut@nginx.com>
parents:
8405
diff
changeset
|
264 * header field names MUST be treated as malformed |
66feab03d9b7
HTTP/3: restricted symbols in header names.
Roman Arutyunyan <arut@nginx.com>
parents:
8405
diff
changeset
|
265 */ |
66feab03d9b7
HTTP/3: restricted symbols in header names.
Roman Arutyunyan <arut@nginx.com>
parents:
8405
diff
changeset
|
266 return NGX_HTTP_PARSE_INVALID_HEADER; |
66feab03d9b7
HTTP/3: restricted symbols in header names.
Roman Arutyunyan <arut@nginx.com>
parents:
8405
diff
changeset
|
267 } |
66feab03d9b7
HTTP/3: restricted symbols in header names.
Roman Arutyunyan <arut@nginx.com>
parents:
8405
diff
changeset
|
268 |
66feab03d9b7
HTTP/3: restricted symbols in header names.
Roman Arutyunyan <arut@nginx.com>
parents:
8405
diff
changeset
|
269 if (ch == '\0') { |
66feab03d9b7
HTTP/3: restricted symbols in header names.
Roman Arutyunyan <arut@nginx.com>
parents:
8405
diff
changeset
|
270 return NGX_HTTP_PARSE_INVALID_HEADER; |
66feab03d9b7
HTTP/3: restricted symbols in header names.
Roman Arutyunyan <arut@nginx.com>
parents:
8405
diff
changeset
|
271 } |
8405
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
272 |
8406
66feab03d9b7
HTTP/3: restricted symbols in header names.
Roman Arutyunyan <arut@nginx.com>
parents:
8405
diff
changeset
|
273 if (ch == '_' && !allow_underscores) { |
66feab03d9b7
HTTP/3: restricted symbols in header names.
Roman Arutyunyan <arut@nginx.com>
parents:
8405
diff
changeset
|
274 r->invalid_header = 1; |
66feab03d9b7
HTTP/3: restricted symbols in header names.
Roman Arutyunyan <arut@nginx.com>
parents:
8405
diff
changeset
|
275 continue; |
66feab03d9b7
HTTP/3: restricted symbols in header names.
Roman Arutyunyan <arut@nginx.com>
parents:
8405
diff
changeset
|
276 } |
66feab03d9b7
HTTP/3: restricted symbols in header names.
Roman Arutyunyan <arut@nginx.com>
parents:
8405
diff
changeset
|
277 |
66feab03d9b7
HTTP/3: restricted symbols in header names.
Roman Arutyunyan <arut@nginx.com>
parents:
8405
diff
changeset
|
278 if ((ch < 'a' || ch > 'z') |
66feab03d9b7
HTTP/3: restricted symbols in header names.
Roman Arutyunyan <arut@nginx.com>
parents:
8405
diff
changeset
|
279 && (ch < '0' || ch > '9') |
66feab03d9b7
HTTP/3: restricted symbols in header names.
Roman Arutyunyan <arut@nginx.com>
parents:
8405
diff
changeset
|
280 && ch != '-' && ch != '_') |
66feab03d9b7
HTTP/3: restricted symbols in header names.
Roman Arutyunyan <arut@nginx.com>
parents:
8405
diff
changeset
|
281 { |
66feab03d9b7
HTTP/3: restricted symbols in header names.
Roman Arutyunyan <arut@nginx.com>
parents:
8405
diff
changeset
|
282 r->invalid_header = 1; |
66feab03d9b7
HTTP/3: restricted symbols in header names.
Roman Arutyunyan <arut@nginx.com>
parents:
8405
diff
changeset
|
283 continue; |
66feab03d9b7
HTTP/3: restricted symbols in header names.
Roman Arutyunyan <arut@nginx.com>
parents:
8405
diff
changeset
|
284 } |
66feab03d9b7
HTTP/3: restricted symbols in header names.
Roman Arutyunyan <arut@nginx.com>
parents:
8405
diff
changeset
|
285 |
66feab03d9b7
HTTP/3: restricted symbols in header names.
Roman Arutyunyan <arut@nginx.com>
parents:
8405
diff
changeset
|
286 hash = ngx_hash(hash, ch); |
66feab03d9b7
HTTP/3: restricted symbols in header names.
Roman Arutyunyan <arut@nginx.com>
parents:
8405
diff
changeset
|
287 r->lowcase_header[i++] = ch; |
66feab03d9b7
HTTP/3: restricted symbols in header names.
Roman Arutyunyan <arut@nginx.com>
parents:
8405
diff
changeset
|
288 i &= (NGX_HTTP_LC_HEADER_LEN - 1); |
66feab03d9b7
HTTP/3: restricted symbols in header names.
Roman Arutyunyan <arut@nginx.com>
parents:
8405
diff
changeset
|
289 } |
66feab03d9b7
HTTP/3: restricted symbols in header names.
Roman Arutyunyan <arut@nginx.com>
parents:
8405
diff
changeset
|
290 |
66feab03d9b7
HTTP/3: restricted symbols in header names.
Roman Arutyunyan <arut@nginx.com>
parents:
8405
diff
changeset
|
291 r->header_hash = hash; |
66feab03d9b7
HTTP/3: restricted symbols in header names.
Roman Arutyunyan <arut@nginx.com>
parents:
8405
diff
changeset
|
292 r->lowcase_index = i; |
8405
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
293 |
d2759e4cc437
HTTP/3: split header parser in two functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8394
diff
changeset
|
294 return NGX_OK; |
8226
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
295 } |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
296 |
8215 | 297 |
298 static ngx_int_t | |
299 ngx_http_v3_process_pseudo_header(ngx_http_request_t *r, ngx_str_t *name, | |
300 ngx_str_t *value) | |
301 { | |
302 ngx_uint_t i; | |
303 ngx_connection_t *c; | |
304 | |
8226
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
305 if (name->len == 0 || name->data[0] != ':') { |
8233
1e45c02f6376
HTTP/3 $request_line variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8230
diff
changeset
|
306 return NGX_DONE; |
8226
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
307 } |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
308 |
8215 | 309 c = r->connection; |
310 | |
311 if (name->len == 7 && ngx_strncmp(name->data, ":method", 7) == 0) { | |
312 r->method_start = value->data; | |
313 r->method_end = value->data + value->len; | |
314 | |
315 for (i = 0; i < sizeof(ngx_http_v3_methods) | |
316 / sizeof(ngx_http_v3_methods[0]); i++) | |
317 { | |
318 if (value->len == ngx_http_v3_methods[i].name.len | |
319 && ngx_strncmp(value->data, ngx_http_v3_methods[i].name.data, | |
320 value->len) == 0) | |
321 { | |
322 r->method = ngx_http_v3_methods[i].method; | |
323 break; | |
324 } | |
325 } | |
326 | |
327 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
328 "http3 method \"%V\" %ui", value, r->method); | |
329 return NGX_OK; | |
330 } | |
331 | |
332 if (name->len == 5 && ngx_strncmp(name->data, ":path", 5) == 0) { | |
333 r->uri_start = value->data; | |
334 r->uri_end = value->data + value->len; | |
335 | |
336 if (ngx_http_parse_uri(r) != NGX_OK) { | |
337 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
338 "client sent invalid :path header: \"%V\"", value); | |
339 return NGX_ERROR; | |
340 } | |
341 | |
342 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
343 "http3 path \"%V\"", value); | |
344 | |
345 return NGX_OK; | |
346 } | |
347 | |
348 if (name->len == 7 && ngx_strncmp(name->data, ":scheme", 7) == 0) { | |
349 r->schema_start = value->data; | |
350 r->schema_end = value->data + value->len; | |
351 | |
352 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
353 "http3 schema \"%V\"", value); | |
354 | |
355 return NGX_OK; | |
356 } | |
357 | |
358 if (name->len == 10 && ngx_strncmp(name->data, ":authority", 10) == 0) { | |
359 r->host_start = value->data; | |
360 r->host_end = value->data + value->len; | |
361 | |
362 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
363 "http3 authority \"%V\"", value); | |
364 | |
365 return NGX_OK; | |
366 } | |
367 | |
8226
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
368 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
369 "http3 unknown pseudo header \"%V\" \"%V\"", name, value); |
8215 | 370 |
8226
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
371 return NGX_OK; |
8215 | 372 } |
373 | |
374 | |
8295
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
375 ngx_int_t |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
376 ngx_http_v3_parse_request_body(ngx_http_request_t *r, ngx_buf_t *b, |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
377 ngx_http_chunked_t *ctx) |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
378 { |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
379 ngx_int_t rc; |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
380 ngx_connection_t *c; |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
381 ngx_http_v3_parse_data_t *st; |
8548
9ffef6054abf
HTTP/3: fixed handling request body eof.
Roman Arutyunyan <arut@nginx.com>
parents:
8511
diff
changeset
|
382 enum { |
9ffef6054abf
HTTP/3: fixed handling request body eof.
Roman Arutyunyan <arut@nginx.com>
parents:
8511
diff
changeset
|
383 sw_start = 0, |
9ffef6054abf
HTTP/3: fixed handling request body eof.
Roman Arutyunyan <arut@nginx.com>
parents:
8511
diff
changeset
|
384 sw_skip |
9ffef6054abf
HTTP/3: fixed handling request body eof.
Roman Arutyunyan <arut@nginx.com>
parents:
8511
diff
changeset
|
385 }; |
8295
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
386 |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
387 c = r->connection; |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
388 st = ctx->h3_parse; |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
389 |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
390 if (st == NULL) { |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
391 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
392 "http3 parse request body"); |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
393 |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
394 st = ngx_pcalloc(c->pool, sizeof(ngx_http_v3_parse_data_t)); |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
395 if (st == NULL) { |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
396 goto failed; |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
397 } |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
398 |
8511
830680e78b24
HTTP/3: fixed context storage in request body parser.
Sergey Kandaurov <pluknet@nginx.com>
parents:
8497
diff
changeset
|
399 ctx->h3_parse = st; |
8295
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
400 } |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
401 |
8548
9ffef6054abf
HTTP/3: fixed handling request body eof.
Roman Arutyunyan <arut@nginx.com>
parents:
8511
diff
changeset
|
402 while (b->pos < b->last && ctx->size == 0) { |
8295
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
403 |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
404 rc = ngx_http_v3_parse_data(c, st, *b->pos++); |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
405 |
8460
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8456
diff
changeset
|
406 if (rc > 0) { |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8456
diff
changeset
|
407 ngx_http_v3_finalize_connection(c, rc, |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8456
diff
changeset
|
408 "could not parse request body"); |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8456
diff
changeset
|
409 goto failed; |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8456
diff
changeset
|
410 } |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8456
diff
changeset
|
411 |
8295
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
412 if (rc == NGX_ERROR) { |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
413 goto failed; |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
414 } |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
415 |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
416 if (rc == NGX_AGAIN) { |
8548
9ffef6054abf
HTTP/3: fixed handling request body eof.
Roman Arutyunyan <arut@nginx.com>
parents:
8511
diff
changeset
|
417 ctx->state = sw_skip; |
8295
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
418 continue; |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
419 } |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
420 |
8549
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8548
diff
changeset
|
421 if (rc == NGX_DONE) { |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8548
diff
changeset
|
422 return NGX_DONE; |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8548
diff
changeset
|
423 } |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8548
diff
changeset
|
424 |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8548
diff
changeset
|
425 /* rc == NGX_OK */ |
8295
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
426 |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
427 ctx->size = st->length; |
8548
9ffef6054abf
HTTP/3: fixed handling request body eof.
Roman Arutyunyan <arut@nginx.com>
parents:
8511
diff
changeset
|
428 ctx->state = sw_start; |
8295
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
429 } |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
430 |
8548
9ffef6054abf
HTTP/3: fixed handling request body eof.
Roman Arutyunyan <arut@nginx.com>
parents:
8511
diff
changeset
|
431 if (ctx->state == sw_skip) { |
8295
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
432 ctx->length = 1; |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
433 return NGX_AGAIN; |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
434 } |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
435 |
8548
9ffef6054abf
HTTP/3: fixed handling request body eof.
Roman Arutyunyan <arut@nginx.com>
parents:
8511
diff
changeset
|
436 if (b->pos == b->last) { |
9ffef6054abf
HTTP/3: fixed handling request body eof.
Roman Arutyunyan <arut@nginx.com>
parents:
8511
diff
changeset
|
437 ctx->length = ctx->size; |
9ffef6054abf
HTTP/3: fixed handling request body eof.
Roman Arutyunyan <arut@nginx.com>
parents:
8511
diff
changeset
|
438 return NGX_AGAIN; |
8295
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
439 } |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
440 |
8548
9ffef6054abf
HTTP/3: fixed handling request body eof.
Roman Arutyunyan <arut@nginx.com>
parents:
8511
diff
changeset
|
441 return NGX_OK; |
8295
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
442 |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
443 failed: |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
444 |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
445 return NGX_ERROR; |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
446 } |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
447 |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8292
diff
changeset
|
448 |
8215 | 449 ngx_chain_t * |
450 ngx_http_v3_create_header(ngx_http_request_t *r) | |
451 { | |
452 u_char *p; | |
8253
69365c7bb07f
Removed unused variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8238
diff
changeset
|
453 size_t len, n; |
8215 | 454 ngx_buf_t *b; |
8489
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
455 ngx_str_t host; |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
456 ngx_uint_t i, port; |
8497 | 457 ngx_chain_t *out, *hl, *cl, **ll; |
8215 | 458 ngx_list_part_t *part; |
459 ngx_table_elt_t *header; | |
460 ngx_connection_t *c; | |
461 ngx_http_core_loc_conf_t *clcf; | |
8489
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
462 ngx_http_core_srv_conf_t *cscf; |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
463 u_char addr[NGX_SOCKADDR_STRLEN]; |
8215 | 464 |
465 c = r->connection; | |
466 | |
467 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 create header"); | |
468 | |
8497 | 469 out = NULL; |
470 ll = &out; | |
471 | |
472 if ((c->qs->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) == 0 | |
473 && r->method != NGX_HTTP_HEAD) | |
474 { | |
475 if (ngx_http_v3_push_resources(r, &ll) != NGX_OK) { | |
476 return NULL; | |
477 } | |
478 } | |
479 | |
8488
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
480 len = ngx_http_v3_encode_header_block_prefix(NULL, 0, 0, 0); |
8215 | 481 |
482 if (r->headers_out.status == NGX_HTTP_OK) { | |
8488
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
483 len += ngx_http_v3_encode_header_ri(NULL, 0, |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
484 NGX_HTTP_V3_HEADER_STATUS_200); |
8215 | 485 |
486 } else { | |
8488
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
487 len += ngx_http_v3_encode_header_lri(NULL, 0, |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
488 NGX_HTTP_V3_HEADER_STATUS_200, |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
489 NULL, 3); |
8215 | 490 } |
491 | |
492 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); | |
493 | |
494 if (r->headers_out.server == NULL) { | |
495 if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_ON) { | |
496 n = sizeof(NGINX_VER) - 1; | |
497 | |
498 } else if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_BUILD) { | |
499 n = sizeof(NGINX_VER_BUILD) - 1; | |
500 | |
501 } else { | |
502 n = sizeof("nginx") - 1; | |
503 } | |
504 | |
8488
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
505 len += ngx_http_v3_encode_header_lri(NULL, 0, |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
506 NGX_HTTP_V3_HEADER_SERVER, |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
507 NULL, n); |
8215 | 508 } |
509 | |
510 if (r->headers_out.date == NULL) { | |
8488
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
511 len += ngx_http_v3_encode_header_lri(NULL, 0, NGX_HTTP_V3_HEADER_DATE, |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
512 NULL, ngx_cached_http_time.len); |
8215 | 513 } |
514 | |
515 if (r->headers_out.content_type.len) { | |
516 n = r->headers_out.content_type.len; | |
517 | |
518 if (r->headers_out.content_type_len == r->headers_out.content_type.len | |
519 && r->headers_out.charset.len) | |
520 { | |
521 n += sizeof("; charset=") - 1 + r->headers_out.charset.len; | |
522 } | |
523 | |
8488
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
524 len += ngx_http_v3_encode_header_lri(NULL, 0, |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
525 NGX_HTTP_V3_HEADER_CONTENT_TYPE_TEXT_PLAIN, |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
526 NULL, n); |
8215 | 527 } |
528 | |
8488
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
529 if (r->headers_out.content_length == NULL) { |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
530 if (r->headers_out.content_length_n > 0) { |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
531 len += ngx_http_v3_encode_header_lri(NULL, 0, |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
532 NGX_HTTP_V3_HEADER_CONTENT_LENGTH_ZERO, |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
533 NULL, NGX_OFF_T_LEN); |
8215 | 534 |
8488
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
535 } else if (r->headers_out.content_length_n == 0) { |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
536 len += ngx_http_v3_encode_header_ri(NULL, 0, |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
537 NGX_HTTP_V3_HEADER_CONTENT_LENGTH_ZERO); |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
538 } |
8215 | 539 } |
540 | |
541 if (r->headers_out.last_modified == NULL | |
542 && r->headers_out.last_modified_time != -1) | |
543 { | |
8488
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
544 len += ngx_http_v3_encode_header_lri(NULL, 0, |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
545 NGX_HTTP_V3_HEADER_LAST_MODIFIED, NULL, |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
546 sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1); |
8215 | 547 } |
548 | |
8489
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
549 if (r->headers_out.location |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
550 && r->headers_out.location->value.len |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
551 && r->headers_out.location->value.data[0] == '/' |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
552 && clcf->absolute_redirect) |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
553 { |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
554 r->headers_out.location->hash = 0; |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
555 |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
556 if (clcf->server_name_in_redirect) { |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
557 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
558 host = cscf->server_name; |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
559 |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
560 } else if (r->headers_in.server.len) { |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
561 host = r->headers_in.server; |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
562 |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
563 } else { |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
564 host.len = NGX_SOCKADDR_STRLEN; |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
565 host.data = addr; |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
566 |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
567 if (ngx_connection_local_sockaddr(c, &host, 0) != NGX_OK) { |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
568 return NULL; |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
569 } |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
570 } |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
571 |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
572 port = ngx_inet_get_port(c->local_sockaddr); |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
573 |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
574 n = sizeof("https://") - 1 + host.len |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
575 + r->headers_out.location->value.len; |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
576 |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
577 if (clcf->port_in_redirect) { |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
578 port = (port == 443) ? 0 : port; |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
579 |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
580 } else { |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
581 port = 0; |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
582 } |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
583 |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
584 if (port) { |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
585 n += sizeof(":65535") - 1; |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
586 } |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
587 |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
588 len += ngx_http_v3_encode_header_lri(NULL, 0, |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
589 NGX_HTTP_V3_HEADER_LOCATION, NULL, n); |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
590 |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
591 } else { |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
592 ngx_str_null(&host); |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
593 port = 0; |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
594 } |
8215 | 595 |
596 #if (NGX_HTTP_GZIP) | |
597 if (r->gzip_vary) { | |
598 if (clcf->gzip_vary) { | |
8488
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
599 len += ngx_http_v3_encode_header_ri(NULL, 0, |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
600 NGX_HTTP_V3_HEADER_VARY_ACCEPT_ENCODING); |
8215 | 601 |
602 } else { | |
603 r->gzip_vary = 0; | |
604 } | |
605 } | |
606 #endif | |
607 | |
608 part = &r->headers_out.headers.part; | |
609 header = part->elts; | |
610 | |
611 for (i = 0; /* void */; i++) { | |
612 | |
613 if (i >= part->nelts) { | |
614 if (part->next == NULL) { | |
615 break; | |
616 } | |
617 | |
618 part = part->next; | |
619 header = part->elts; | |
620 i = 0; | |
621 } | |
622 | |
623 if (header[i].hash == 0) { | |
624 continue; | |
625 } | |
626 | |
8488
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
627 len += ngx_http_v3_encode_header_l(NULL, &header[i].key, |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
628 &header[i].value); |
8215 | 629 } |
630 | |
631 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 header len:%uz", len); | |
632 | |
633 b = ngx_create_temp_buf(r->pool, len); | |
634 if (b == NULL) { | |
635 return NULL; | |
636 } | |
637 | |
8488
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
638 b->last = (u_char *) ngx_http_v3_encode_header_block_prefix(b->last, |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
639 0, 0, 0); |
8215 | 640 |
641 if (r->headers_out.status == NGX_HTTP_OK) { | |
8488
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
642 b->last = (u_char *) ngx_http_v3_encode_header_ri(b->last, 0, |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
643 NGX_HTTP_V3_HEADER_STATUS_200); |
8215 | 644 |
645 } else { | |
8488
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
646 b->last = (u_char *) ngx_http_v3_encode_header_lri(b->last, 0, |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
647 NGX_HTTP_V3_HEADER_STATUS_200, |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
648 NULL, 3); |
8226
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
649 b->last = ngx_sprintf(b->last, "%03ui", r->headers_out.status); |
8215 | 650 } |
651 | |
652 if (r->headers_out.server == NULL) { | |
653 if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_ON) { | |
654 p = (u_char *) NGINX_VER; | |
655 n = sizeof(NGINX_VER) - 1; | |
656 | |
657 } else if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_BUILD) { | |
658 p = (u_char *) NGINX_VER_BUILD; | |
659 n = sizeof(NGINX_VER_BUILD) - 1; | |
660 | |
661 } else { | |
662 p = (u_char *) "nginx"; | |
663 n = sizeof("nginx") - 1; | |
664 } | |
665 | |
8488
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
666 b->last = (u_char *) ngx_http_v3_encode_header_lri(b->last, 0, |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
667 NGX_HTTP_V3_HEADER_SERVER, |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
668 p, n); |
8215 | 669 } |
670 | |
671 if (r->headers_out.date == NULL) { | |
8488
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
672 b->last = (u_char *) ngx_http_v3_encode_header_lri(b->last, 0, |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
673 NGX_HTTP_V3_HEADER_DATE, |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
674 ngx_cached_http_time.data, |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
675 ngx_cached_http_time.len); |
8215 | 676 } |
677 | |
678 if (r->headers_out.content_type.len) { | |
679 n = r->headers_out.content_type.len; | |
680 | |
681 if (r->headers_out.content_type_len == r->headers_out.content_type.len | |
682 && r->headers_out.charset.len) | |
683 { | |
684 n += sizeof("; charset=") - 1 + r->headers_out.charset.len; | |
685 } | |
686 | |
8488
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
687 b->last = (u_char *) ngx_http_v3_encode_header_lri(b->last, 0, |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
688 NGX_HTTP_V3_HEADER_CONTENT_TYPE_TEXT_PLAIN, |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
689 NULL, n); |
8215 | 690 |
691 p = b->last; | |
8488
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
692 b->last = ngx_cpymem(b->last, r->headers_out.content_type.data, |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
693 r->headers_out.content_type.len); |
8215 | 694 |
695 if (r->headers_out.content_type_len == r->headers_out.content_type.len | |
696 && r->headers_out.charset.len) | |
697 { | |
698 b->last = ngx_cpymem(b->last, "; charset=", | |
699 sizeof("; charset=") - 1); | |
8488
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
700 b->last = ngx_cpymem(b->last, r->headers_out.charset.data, |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
701 r->headers_out.charset.len); |
8215 | 702 |
703 /* update r->headers_out.content_type for possible logging */ | |
704 | |
705 r->headers_out.content_type.len = b->last - p; | |
706 r->headers_out.content_type.data = p; | |
707 } | |
708 } | |
709 | |
8488
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
710 if (r->headers_out.content_length == NULL) { |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
711 if (r->headers_out.content_length_n > 0) { |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
712 p = ngx_sprintf(b->last, "%O", r->headers_out.content_length_n); |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
713 n = p - b->last; |
8238
a3257a725b3d
Fixed header creation for header_only responses in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8233
diff
changeset
|
714 |
8488
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
715 b->last = (u_char *) ngx_http_v3_encode_header_lri(b->last, 0, |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
716 NGX_HTTP_V3_HEADER_CONTENT_LENGTH_ZERO, |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
717 NULL, n); |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
718 |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
719 b->last = ngx_sprintf(b->last, "%O", |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
720 r->headers_out.content_length_n); |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
721 |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
722 } else if (r->headers_out.content_length_n == 0) { |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
723 b->last = (u_char *) ngx_http_v3_encode_header_ri(b->last, 0, |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
724 NGX_HTTP_V3_HEADER_CONTENT_LENGTH_ZERO); |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
725 } |
8215 | 726 } |
727 | |
728 if (r->headers_out.last_modified == NULL | |
729 && r->headers_out.last_modified_time != -1) | |
730 { | |
8488
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
731 b->last = (u_char *) ngx_http_v3_encode_header_lri(b->last, 0, |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
732 NGX_HTTP_V3_HEADER_LAST_MODIFIED, NULL, |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
733 sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1); |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
734 |
8215 | 735 b->last = ngx_http_time(b->last, r->headers_out.last_modified_time); |
736 } | |
737 | |
8489
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
738 if (host.data) { |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
739 n = sizeof("https://") - 1 + host.len |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
740 + r->headers_out.location->value.len; |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
741 |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
742 if (port) { |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
743 n += ngx_sprintf(b->last, ":%ui", port) - b->last; |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
744 } |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
745 |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
746 b->last = (u_char *) ngx_http_v3_encode_header_lri(b->last, 0, |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
747 NGX_HTTP_V3_HEADER_LOCATION, |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
748 NULL, n); |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
749 |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
750 p = b->last; |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
751 b->last = ngx_cpymem(b->last, "https://", sizeof("https://") - 1); |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
752 b->last = ngx_cpymem(b->last, host.data, host.len); |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
753 |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
754 if (port) { |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
755 b->last = ngx_sprintf(b->last, ":%ui", port); |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
756 } |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
757 |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
758 b->last = ngx_cpymem(b->last, r->headers_out.location->value.data, |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
759 r->headers_out.location->value.len); |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
760 |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
761 /* update r->headers_out.location->value for possible logging */ |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
762 |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
763 r->headers_out.location->value.len = b->last - p; |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
764 r->headers_out.location->value.data = p; |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
765 ngx_str_set(&r->headers_out.location->key, "Location"); |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
766 } |
5d2e285677a7
HTTP/3: generate Location response header for absolute redirects.
Roman Arutyunyan <arut@nginx.com>
parents:
8488
diff
changeset
|
767 |
8215 | 768 #if (NGX_HTTP_GZIP) |
769 if (r->gzip_vary) { | |
8488
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
770 b->last = (u_char *) ngx_http_v3_encode_header_ri(b->last, 0, |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
771 NGX_HTTP_V3_HEADER_VARY_ACCEPT_ENCODING); |
8215 | 772 } |
773 #endif | |
774 | |
775 part = &r->headers_out.headers.part; | |
776 header = part->elts; | |
777 | |
778 for (i = 0; /* void */; i++) { | |
779 | |
780 if (i >= part->nelts) { | |
781 if (part->next == NULL) { | |
782 break; | |
783 } | |
784 | |
785 part = part->next; | |
786 header = part->elts; | |
787 i = 0; | |
788 } | |
789 | |
790 if (header[i].hash == 0) { | |
791 continue; | |
792 } | |
793 | |
8488
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
794 b->last = (u_char *) ngx_http_v3_encode_header_l(b->last, |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
795 &header[i].key, |
79125ef2e39f
HTTP/3: header encoding functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8460
diff
changeset
|
796 &header[i].value); |
8215 | 797 } |
798 | |
8238
a3257a725b3d
Fixed header creation for header_only responses in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8233
diff
changeset
|
799 if (r->header_only) { |
a3257a725b3d
Fixed header creation for header_only responses in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8233
diff
changeset
|
800 b->last_buf = 1; |
a3257a725b3d
Fixed header creation for header_only responses in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8233
diff
changeset
|
801 } |
a3257a725b3d
Fixed header creation for header_only responses in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8233
diff
changeset
|
802 |
8215 | 803 cl = ngx_alloc_chain_link(c->pool); |
804 if (cl == NULL) { | |
805 return NULL; | |
806 } | |
807 | |
808 cl->buf = b; | |
809 cl->next = NULL; | |
810 | |
811 n = b->last - b->pos; | |
812 | |
8490
e24f7b50ba1d
HTTP/3: encode frame ids with ngx_http_v3_encode_varlen_int().
Roman Arutyunyan <arut@nginx.com>
parents:
8489
diff
changeset
|
813 len = ngx_http_v3_encode_varlen_int(NULL, NGX_HTTP_V3_FRAME_HEADERS) |
e24f7b50ba1d
HTTP/3: encode frame ids with ngx_http_v3_encode_varlen_int().
Roman Arutyunyan <arut@nginx.com>
parents:
8489
diff
changeset
|
814 + ngx_http_v3_encode_varlen_int(NULL, n); |
8215 | 815 |
816 b = ngx_create_temp_buf(c->pool, len); | |
817 if (b == NULL) { | |
818 return NULL; | |
819 } | |
820 | |
8490
e24f7b50ba1d
HTTP/3: encode frame ids with ngx_http_v3_encode_varlen_int().
Roman Arutyunyan <arut@nginx.com>
parents:
8489
diff
changeset
|
821 b->last = (u_char *) ngx_http_v3_encode_varlen_int(b->last, |
e24f7b50ba1d
HTTP/3: encode frame ids with ngx_http_v3_encode_varlen_int().
Roman Arutyunyan <arut@nginx.com>
parents:
8489
diff
changeset
|
822 NGX_HTTP_V3_FRAME_HEADERS); |
8215 | 823 b->last = (u_char *) ngx_http_v3_encode_varlen_int(b->last, n); |
824 | |
825 hl = ngx_alloc_chain_link(c->pool); | |
826 if (hl == NULL) { | |
827 return NULL; | |
828 } | |
829 | |
830 hl->buf = b; | |
831 hl->next = cl; | |
832 | |
8497 | 833 *ll = hl; |
834 ll = &cl->next; | |
835 | |
8451
908cae4f3078
HTTP/3: do not emit a DATA frame header for header_only responses.
Sergey Kandaurov <pluknet@nginx.com>
parents:
8408
diff
changeset
|
836 if (r->headers_out.content_length_n >= 0 && !r->header_only) { |
8490
e24f7b50ba1d
HTTP/3: encode frame ids with ngx_http_v3_encode_varlen_int().
Roman Arutyunyan <arut@nginx.com>
parents:
8489
diff
changeset
|
837 len = ngx_http_v3_encode_varlen_int(NULL, NGX_HTTP_V3_FRAME_DATA) |
e24f7b50ba1d
HTTP/3: encode frame ids with ngx_http_v3_encode_varlen_int().
Roman Arutyunyan <arut@nginx.com>
parents:
8489
diff
changeset
|
838 + ngx_http_v3_encode_varlen_int(NULL, |
8215 | 839 r->headers_out.content_length_n); |
840 | |
841 b = ngx_create_temp_buf(c->pool, len); | |
842 if (b == NULL) { | |
8394 | 843 return NULL; |
8215 | 844 } |
845 | |
8490
e24f7b50ba1d
HTTP/3: encode frame ids with ngx_http_v3_encode_varlen_int().
Roman Arutyunyan <arut@nginx.com>
parents:
8489
diff
changeset
|
846 b->last = (u_char *) ngx_http_v3_encode_varlen_int(b->last, |
e24f7b50ba1d
HTTP/3: encode frame ids with ngx_http_v3_encode_varlen_int().
Roman Arutyunyan <arut@nginx.com>
parents:
8489
diff
changeset
|
847 NGX_HTTP_V3_FRAME_DATA); |
8215 | 848 b->last = (u_char *) ngx_http_v3_encode_varlen_int(b->last, |
849 r->headers_out.content_length_n); | |
850 | |
8497 | 851 cl = ngx_alloc_chain_link(c->pool); |
852 if (cl == NULL) { | |
8215 | 853 return NULL; |
854 } | |
855 | |
8497 | 856 cl->buf = b; |
857 cl->next = NULL; | |
858 | |
859 *ll = cl; | |
8215 | 860 } |
861 | |
8497 | 862 return out; |
8215 | 863 } |
8292
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
864 |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
865 |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
866 ngx_chain_t * |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
867 ngx_http_v3_create_trailers(ngx_http_request_t *r) |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
868 { |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
869 ngx_buf_t *b; |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
870 ngx_chain_t *cl; |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
871 |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
872 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
873 "http3 create trailers"); |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
874 |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
875 /* XXX */ |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
876 |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
877 b = ngx_calloc_buf(r->pool); |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
878 if (b == NULL) { |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
879 return NULL; |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
880 } |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
881 |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
882 b->last_buf = 1; |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
883 |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
884 cl = ngx_alloc_chain_link(r->pool); |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
885 if (cl == NULL) { |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
886 return NULL; |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
887 } |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
888 |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
889 cl->buf = b; |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
890 cl->next = NULL; |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
891 |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
892 return cl; |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
893 } |
8497 | 894 |
895 | |
896 static ngx_int_t | |
897 ngx_http_v3_push_resources(ngx_http_request_t *r, ngx_chain_t ***out) | |
898 { | |
899 u_char *start, *end, *last; | |
900 ngx_str_t path; | |
901 ngx_int_t rc; | |
902 ngx_uint_t i, push; | |
903 ngx_table_elt_t **h; | |
904 ngx_http_v3_loc_conf_t *h3lcf; | |
905 ngx_http_complex_value_t *pushes; | |
906 | |
907 h3lcf = ngx_http_get_module_loc_conf(r, ngx_http_v3_module); | |
908 | |
909 if (h3lcf->pushes) { | |
910 pushes = h3lcf->pushes->elts; | |
911 | |
912 for (i = 0; i < h3lcf->pushes->nelts; i++) { | |
913 | |
914 if (ngx_http_complex_value(r, &pushes[i], &path) != NGX_OK) { | |
915 return NGX_ERROR; | |
916 } | |
917 | |
918 if (path.len == 0) { | |
919 continue; | |
920 } | |
921 | |
922 if (path.len == 3 && ngx_strncmp(path.data, "off", 3) == 0) { | |
923 continue; | |
924 } | |
925 | |
926 rc = ngx_http_v3_push_resource(r, &path, out); | |
927 | |
928 if (rc == NGX_ERROR) { | |
929 return NGX_ERROR; | |
930 } | |
931 | |
932 if (rc == NGX_ABORT) { | |
933 return NGX_OK; | |
934 } | |
935 | |
936 /* NGX_OK, NGX_DECLINED */ | |
937 } | |
938 } | |
939 | |
940 if (!h3lcf->push_preload) { | |
941 return NGX_OK; | |
942 } | |
943 | |
944 h = r->headers_out.link.elts; | |
945 | |
946 for (i = 0; i < r->headers_out.link.nelts; i++) { | |
947 | |
948 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
949 "http3 parse link: \"%V\"", &h[i]->value); | |
950 | |
951 start = h[i]->value.data; | |
952 end = h[i]->value.data + h[i]->value.len; | |
953 | |
954 next_link: | |
955 | |
956 while (start < end && *start == ' ') { start++; } | |
957 | |
958 if (start == end || *start++ != '<') { | |
959 continue; | |
960 } | |
961 | |
962 while (start < end && *start == ' ') { start++; } | |
963 | |
964 for (last = start; last < end && *last != '>'; last++) { | |
965 /* void */ | |
966 } | |
967 | |
968 if (last == start || last == end) { | |
969 continue; | |
970 } | |
971 | |
972 path.len = last - start; | |
973 path.data = start; | |
974 | |
975 start = last + 1; | |
976 | |
977 while (start < end && *start == ' ') { start++; } | |
978 | |
979 if (start == end) { | |
980 continue; | |
981 } | |
982 | |
983 if (*start == ',') { | |
984 start++; | |
985 goto next_link; | |
986 } | |
987 | |
988 if (*start++ != ';') { | |
989 continue; | |
990 } | |
991 | |
992 last = ngx_strlchr(start, end, ','); | |
993 | |
994 if (last == NULL) { | |
995 last = end; | |
996 } | |
997 | |
998 push = 0; | |
999 | |
1000 for ( ;; ) { | |
1001 | |
1002 while (start < last && *start == ' ') { start++; } | |
1003 | |
1004 if (last - start >= 6 | |
1005 && ngx_strncasecmp(start, (u_char *) "nopush", 6) == 0) | |
1006 { | |
1007 start += 6; | |
1008 | |
1009 if (start == last || *start == ' ' || *start == ';') { | |
1010 push = 0; | |
1011 break; | |
1012 } | |
1013 | |
1014 goto next_param; | |
1015 } | |
1016 | |
1017 if (last - start >= 11 | |
1018 && ngx_strncasecmp(start, (u_char *) "rel=preload", 11) == 0) | |
1019 { | |
1020 start += 11; | |
1021 | |
1022 if (start == last || *start == ' ' || *start == ';') { | |
1023 push = 1; | |
1024 } | |
1025 | |
1026 goto next_param; | |
1027 } | |
1028 | |
1029 if (last - start >= 4 | |
1030 && ngx_strncasecmp(start, (u_char *) "rel=", 4) == 0) | |
1031 { | |
1032 start += 4; | |
1033 | |
1034 while (start < last && *start == ' ') { start++; } | |
1035 | |
1036 if (start == last || *start++ != '"') { | |
1037 goto next_param; | |
1038 } | |
1039 | |
1040 for ( ;; ) { | |
1041 | |
1042 while (start < last && *start == ' ') { start++; } | |
1043 | |
1044 if (last - start >= 7 | |
1045 && ngx_strncasecmp(start, (u_char *) "preload", 7) == 0) | |
1046 { | |
1047 start += 7; | |
1048 | |
1049 if (start < last && (*start == ' ' || *start == '"')) { | |
1050 push = 1; | |
1051 break; | |
1052 } | |
1053 } | |
1054 | |
1055 while (start < last && *start != ' ' && *start != '"') { | |
1056 start++; | |
1057 } | |
1058 | |
1059 if (start == last) { | |
1060 break; | |
1061 } | |
1062 | |
1063 if (*start == '"') { | |
1064 break; | |
1065 } | |
1066 | |
1067 start++; | |
1068 } | |
1069 } | |
1070 | |
1071 next_param: | |
1072 | |
1073 start = ngx_strlchr(start, last, ';'); | |
1074 | |
1075 if (start == NULL) { | |
1076 break; | |
1077 } | |
1078 | |
1079 start++; | |
1080 } | |
1081 | |
1082 if (push) { | |
1083 while (path.len && path.data[path.len - 1] == ' ') { | |
1084 path.len--; | |
1085 } | |
1086 } | |
1087 | |
1088 if (push && path.len | |
1089 && !(path.len > 1 && path.data[0] == '/' && path.data[1] == '/')) | |
1090 { | |
1091 rc = ngx_http_v3_push_resource(r, &path, out); | |
1092 | |
1093 if (rc == NGX_ERROR) { | |
1094 return NGX_ERROR; | |
1095 } | |
1096 | |
1097 if (rc == NGX_ABORT) { | |
1098 return NGX_OK; | |
1099 } | |
1100 | |
1101 /* NGX_OK, NGX_DECLINED */ | |
1102 } | |
1103 | |
1104 if (last < end) { | |
1105 start = last + 1; | |
1106 goto next_link; | |
1107 } | |
1108 } | |
1109 | |
1110 return NGX_OK; | |
1111 } | |
1112 | |
1113 | |
1114 static ngx_int_t | |
1115 ngx_http_v3_push_resource(ngx_http_request_t *r, ngx_str_t *path, | |
1116 ngx_chain_t ***ll) | |
1117 { | |
1118 uint64_t push_id; | |
1119 ngx_int_t rc; | |
1120 ngx_chain_t *cl; | |
1121 ngx_connection_t *c; | |
1122 ngx_http_v3_srv_conf_t *h3scf; | |
1123 ngx_http_v3_connection_t *h3c; | |
1124 | |
1125 c = r->connection; | |
1126 h3c = c->qs->parent->data; | |
1127 h3scf = ngx_http_get_module_srv_conf(r, ngx_http_v3_module); | |
1128 | |
1129 ngx_log_debug5(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
1130 "http3 push \"%V\" pushing:%ui/%ui id:%uL/%uL", | |
1131 path, h3c->npushing, h3scf->max_concurrent_pushes, | |
1132 h3c->next_push_id, h3c->max_push_id); | |
1133 | |
1134 if (!ngx_path_separator(path->data[0])) { | |
1135 ngx_log_error(NGX_LOG_WARN, c->log, 0, | |
1136 "non-absolute path \"%V\" not pushed", path); | |
1137 return NGX_DECLINED; | |
1138 } | |
1139 | |
1140 if (h3c->next_push_id > h3c->max_push_id) { | |
1141 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
1142 "http3 abort pushes due to max_push_id"); | |
1143 return NGX_ABORT; | |
1144 } | |
1145 | |
1146 if (h3c->npushing >= h3scf->max_concurrent_pushes) { | |
1147 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
1148 "http3 abort pushes due to max_concurrent_pushes"); | |
1149 return NGX_ABORT; | |
1150 } | |
1151 | |
1152 push_id = h3c->next_push_id++; | |
1153 | |
1154 rc = ngx_http_v3_create_push_request(r, path, push_id); | |
1155 if (rc != NGX_OK) { | |
1156 return rc; | |
1157 } | |
1158 | |
1159 cl = ngx_http_v3_create_push_promise(r, path, push_id); | |
1160 if (cl == NULL) { | |
1161 return NGX_ERROR; | |
1162 } | |
1163 | |
1164 for (**ll = cl; **ll; *ll = &(**ll)->next); | |
1165 | |
1166 return NGX_OK; | |
1167 } | |
1168 | |
1169 | |
1170 static ngx_int_t | |
1171 ngx_http_v3_create_push_request(ngx_http_request_t *pr, ngx_str_t *path, | |
1172 uint64_t push_id) | |
1173 { | |
1174 ngx_pool_t *pool; | |
1175 ngx_connection_t *c, *pc; | |
1176 ngx_http_request_t *r; | |
1177 ngx_http_log_ctx_t *ctx; | |
1178 ngx_http_connection_t *hc; | |
1179 ngx_http_core_srv_conf_t *cscf; | |
1180 ngx_http_v3_connection_t *h3c; | |
1181 | |
1182 pc = pr->connection; | |
1183 | |
1184 r = NULL; | |
1185 | |
1186 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, | |
1187 "http3 create push request id:%uL", push_id); | |
1188 | |
1189 c = ngx_http_v3_create_push_stream(pc, push_id); | |
1190 if (c == NULL) { | |
1191 return NGX_ABORT; | |
1192 } | |
1193 | |
1194 hc = ngx_palloc(c->pool, sizeof(ngx_http_connection_t)); | |
1195 if (hc == NULL) { | |
1196 goto failed; | |
1197 } | |
1198 | |
1199 h3c = c->qs->parent->data; | |
1200 ngx_memcpy(hc, h3c, sizeof(ngx_http_connection_t)); | |
1201 c->data = hc; | |
1202 | |
1203 ctx = ngx_palloc(c->pool, sizeof(ngx_http_log_ctx_t)); | |
1204 if (ctx == NULL) { | |
1205 goto failed; | |
1206 } | |
1207 | |
1208 ctx->connection = c; | |
1209 ctx->request = NULL; | |
1210 ctx->current_request = NULL; | |
1211 | |
1212 c->log->handler = ngx_http_log_error; | |
1213 c->log->data = ctx; | |
1214 c->log->action = "processing pushed request headers"; | |
1215 | |
1216 c->log_error = NGX_ERROR_INFO; | |
1217 | |
1218 r = ngx_http_create_request(c); | |
1219 if (r == NULL) { | |
1220 goto failed; | |
1221 } | |
1222 | |
1223 c->data = r; | |
1224 | |
1225 ngx_str_set(&r->http_protocol, "HTTP/3.0"); | |
1226 | |
1227 r->method_name = ngx_http_core_get_method; | |
1228 r->method = NGX_HTTP_GET; | |
1229 | |
1230 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); | |
1231 | |
1232 r->header_in = ngx_create_temp_buf(r->pool, | |
1233 cscf->client_header_buffer_size); | |
1234 if (r->header_in == NULL) { | |
1235 goto failed; | |
1236 } | |
1237 | |
1238 if (ngx_list_init(&r->headers_in.headers, r->pool, 4, | |
1239 sizeof(ngx_table_elt_t)) | |
1240 != NGX_OK) | |
1241 { | |
1242 goto failed; | |
1243 } | |
1244 | |
1245 r->headers_in.connection_type = NGX_HTTP_CONNECTION_CLOSE; | |
1246 | |
1247 r->schema.data = ngx_pstrdup(r->pool, &pr->schema); | |
1248 if (r->schema.data == NULL) { | |
1249 goto failed; | |
1250 } | |
1251 | |
1252 r->schema.len = pr->schema.len; | |
1253 | |
1254 r->uri_start = ngx_pstrdup(r->pool, path); | |
1255 if (r->uri_start == NULL) { | |
1256 goto failed; | |
1257 } | |
1258 | |
1259 r->uri_end = r->uri_start + path->len; | |
1260 | |
1261 if (ngx_http_parse_uri(r) != NGX_OK) { | |
1262 goto failed; | |
1263 } | |
1264 | |
1265 if (ngx_http_process_request_uri(r) != NGX_OK) { | |
1266 goto failed; | |
1267 } | |
1268 | |
1269 if (ngx_http_v3_set_push_header(r, "host", &pr->headers_in.server) | |
1270 != NGX_OK) | |
1271 { | |
1272 goto failed; | |
1273 } | |
1274 | |
1275 if (pr->headers_in.accept_encoding) { | |
1276 if (ngx_http_v3_set_push_header(r, "accept-encoding", | |
1277 &pr->headers_in.accept_encoding->value) | |
1278 != NGX_OK) | |
1279 { | |
1280 goto failed; | |
1281 } | |
1282 } | |
1283 | |
1284 if (pr->headers_in.accept_language) { | |
1285 if (ngx_http_v3_set_push_header(r, "accept-language", | |
1286 &pr->headers_in.accept_language->value) | |
1287 != NGX_OK) | |
1288 { | |
1289 goto failed; | |
1290 } | |
1291 } | |
1292 | |
1293 if (pr->headers_in.user_agent) { | |
1294 if (ngx_http_v3_set_push_header(r, "user-agent", | |
1295 &pr->headers_in.user_agent->value) | |
1296 != NGX_OK) | |
1297 { | |
1298 goto failed; | |
1299 } | |
1300 } | |
1301 | |
1302 c->read->handler = ngx_http_v3_push_request_handler; | |
1303 c->read->handler = ngx_http_v3_push_request_handler; | |
1304 | |
1305 ngx_post_event(c->read, &ngx_posted_events); | |
1306 | |
1307 return NGX_OK; | |
1308 | |
1309 failed: | |
1310 | |
1311 if (r) { | |
1312 ngx_http_free_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); | |
1313 } | |
1314 | |
1315 c->destroyed = 1; | |
1316 | |
1317 pool = c->pool; | |
1318 | |
1319 ngx_close_connection(c); | |
1320 | |
1321 ngx_destroy_pool(pool); | |
1322 | |
1323 return NGX_ERROR; | |
1324 } | |
1325 | |
1326 | |
1327 static ngx_int_t | |
1328 ngx_http_v3_set_push_header(ngx_http_request_t *r, const char *name, | |
1329 ngx_str_t *value) | |
1330 { | |
1331 u_char *p; | |
1332 ngx_table_elt_t *h; | |
1333 ngx_http_header_t *hh; | |
1334 ngx_http_core_main_conf_t *cmcf; | |
1335 | |
1336 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
1337 "http3 push header \"%s\": \"%V\"", name, value); | |
1338 | |
1339 cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); | |
1340 | |
1341 p = ngx_pnalloc(r->pool, value->len + 1); | |
1342 if (p == NULL) { | |
1343 return NGX_ERROR; | |
1344 } | |
1345 | |
1346 ngx_memcpy(p, value->data, value->len); | |
1347 p[value->len] = '\0'; | |
1348 | |
1349 h = ngx_list_push(&r->headers_in.headers); | |
1350 if (h == NULL) { | |
1351 return NGX_ERROR; | |
1352 } | |
1353 | |
1354 h->key.data = (u_char *) name; | |
1355 h->key.len = ngx_strlen(name); | |
1356 h->hash = ngx_hash_key(h->key.data, h->key.len); | |
1357 h->lowcase_key = (u_char *) name; | |
1358 h->value.data = p; | |
1359 h->value.len = value->len; | |
1360 | |
1361 hh = ngx_hash_find(&cmcf->headers_in_hash, h->hash, | |
1362 h->lowcase_key, h->key.len); | |
1363 | |
1364 if (hh && hh->handler(r, h, hh->offset) != NGX_OK) { | |
1365 return NGX_ERROR; | |
1366 } | |
1367 | |
1368 return NGX_OK; | |
1369 } | |
1370 | |
1371 | |
1372 static void | |
1373 ngx_http_v3_push_request_handler(ngx_event_t *ev) | |
1374 { | |
1375 ngx_connection_t *c; | |
1376 ngx_http_request_t *r; | |
1377 | |
1378 c = ev->data; | |
1379 r = c->data; | |
1380 | |
1381 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 push request handler"); | |
1382 | |
1383 ngx_http_process_request(r); | |
1384 } | |
1385 | |
1386 | |
1387 static ngx_chain_t * | |
1388 ngx_http_v3_create_push_promise(ngx_http_request_t *r, ngx_str_t *path, | |
1389 uint64_t push_id) | |
1390 { | |
1391 size_t n, len; | |
1392 ngx_buf_t *b; | |
1393 ngx_chain_t *hl, *cl; | |
1394 | |
1395 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
1396 "http3 create push promise id:%uL", push_id); | |
1397 | |
1398 len = ngx_http_v3_encode_varlen_int(NULL, push_id); | |
1399 | |
1400 len += ngx_http_v3_encode_header_block_prefix(NULL, 0, 0, 0); | |
1401 | |
1402 len += ngx_http_v3_encode_header_ri(NULL, 0, | |
1403 NGX_HTTP_V3_HEADER_METHOD_GET); | |
1404 | |
1405 len += ngx_http_v3_encode_header_lri(NULL, 0, | |
1406 NGX_HTTP_V3_HEADER_AUTHORITY, | |
1407 NULL, r->headers_in.server.len); | |
1408 | |
1409 if (path->len == 1 && path->data[0] == '/') { | |
1410 len += ngx_http_v3_encode_header_ri(NULL, 0, | |
1411 NGX_HTTP_V3_HEADER_PATH_ROOT); | |
1412 | |
1413 } else { | |
1414 len += ngx_http_v3_encode_header_lri(NULL, 0, | |
1415 NGX_HTTP_V3_HEADER_PATH_ROOT, | |
1416 NULL, path->len); | |
1417 } | |
1418 | |
1419 if (r->schema.len == 5 && ngx_strncmp(r->schema.data, "https", 5) == 0) { | |
1420 len += ngx_http_v3_encode_header_ri(NULL, 0, | |
1421 NGX_HTTP_V3_HEADER_SCHEME_HTTPS); | |
1422 | |
1423 } else if (r->schema.len == 4 | |
1424 && ngx_strncmp(r->schema.data, "http", 4) == 0) | |
1425 { | |
1426 len += ngx_http_v3_encode_header_ri(NULL, 0, | |
1427 NGX_HTTP_V3_HEADER_SCHEME_HTTP); | |
1428 | |
1429 } else { | |
1430 len += ngx_http_v3_encode_header_lri(NULL, 0, | |
1431 NGX_HTTP_V3_HEADER_SCHEME_HTTP, | |
1432 NULL, r->schema.len); | |
1433 } | |
1434 | |
1435 if (r->headers_in.accept_encoding) { | |
1436 len += ngx_http_v3_encode_header_lri(NULL, 0, | |
1437 NGX_HTTP_V3_HEADER_ACCEPT_ENCODING, NULL, | |
1438 r->headers_in.accept_encoding->value.len); | |
1439 } | |
1440 | |
1441 if (r->headers_in.accept_language) { | |
1442 len += ngx_http_v3_encode_header_lri(NULL, 0, | |
1443 NGX_HTTP_V3_HEADER_ACCEPT_LANGUAGE, NULL, | |
1444 r->headers_in.accept_language->value.len); | |
1445 } | |
1446 | |
1447 if (r->headers_in.user_agent) { | |
1448 len += ngx_http_v3_encode_header_lri(NULL, 0, | |
1449 NGX_HTTP_V3_HEADER_USER_AGENT, NULL, | |
1450 r->headers_in.user_agent->value.len); | |
1451 } | |
1452 | |
1453 b = ngx_create_temp_buf(r->pool, len); | |
1454 if (b == NULL) { | |
1455 return NULL; | |
1456 } | |
1457 | |
1458 b->last = (u_char *) ngx_http_v3_encode_varlen_int(b->last, push_id); | |
1459 | |
1460 b->last = (u_char *) ngx_http_v3_encode_header_block_prefix(b->last, | |
1461 0, 0, 0); | |
1462 | |
1463 b->last = (u_char *) ngx_http_v3_encode_header_ri(b->last, 0, | |
1464 NGX_HTTP_V3_HEADER_METHOD_GET); | |
1465 | |
1466 b->last = (u_char *) ngx_http_v3_encode_header_lri(b->last, 0, | |
1467 NGX_HTTP_V3_HEADER_AUTHORITY, | |
1468 r->headers_in.server.data, | |
1469 r->headers_in.server.len); | |
1470 | |
1471 if (path->len == 1 && path->data[0] == '/') { | |
1472 b->last = (u_char *) ngx_http_v3_encode_header_ri(b->last, 0, | |
1473 NGX_HTTP_V3_HEADER_PATH_ROOT); | |
1474 | |
1475 } else { | |
1476 b->last = (u_char *) ngx_http_v3_encode_header_lri(b->last, 0, | |
1477 NGX_HTTP_V3_HEADER_PATH_ROOT, | |
1478 path->data, path->len); | |
1479 } | |
1480 | |
1481 if (r->schema.len == 5 && ngx_strncmp(r->schema.data, "https", 5) == 0) { | |
1482 b->last = (u_char *) ngx_http_v3_encode_header_ri(b->last, 0, | |
1483 NGX_HTTP_V3_HEADER_SCHEME_HTTPS); | |
1484 | |
1485 } else if (r->schema.len == 4 | |
1486 && ngx_strncmp(r->schema.data, "http", 4) == 0) | |
1487 { | |
1488 b->last = (u_char *) ngx_http_v3_encode_header_ri(b->last, 0, | |
1489 NGX_HTTP_V3_HEADER_SCHEME_HTTP); | |
1490 | |
1491 } else { | |
1492 b->last = (u_char *) ngx_http_v3_encode_header_lri(b->last, 0, | |
1493 NGX_HTTP_V3_HEADER_SCHEME_HTTP, | |
1494 r->schema.data, r->schema.len); | |
1495 } | |
1496 | |
1497 if (r->headers_in.accept_encoding) { | |
1498 b->last = (u_char *) ngx_http_v3_encode_header_lri(b->last, 0, | |
1499 NGX_HTTP_V3_HEADER_ACCEPT_ENCODING, | |
1500 r->headers_in.accept_encoding->value.data, | |
1501 r->headers_in.accept_encoding->value.len); | |
1502 } | |
1503 | |
1504 if (r->headers_in.accept_language) { | |
1505 b->last = (u_char *) ngx_http_v3_encode_header_lri(b->last, 0, | |
1506 NGX_HTTP_V3_HEADER_ACCEPT_LANGUAGE, | |
1507 r->headers_in.accept_language->value.data, | |
1508 r->headers_in.accept_language->value.len); | |
1509 } | |
1510 | |
1511 if (r->headers_in.user_agent) { | |
1512 b->last = (u_char *) ngx_http_v3_encode_header_lri(b->last, 0, | |
1513 NGX_HTTP_V3_HEADER_USER_AGENT, | |
1514 r->headers_in.user_agent->value.data, | |
1515 r->headers_in.user_agent->value.len); | |
1516 } | |
1517 | |
1518 cl = ngx_alloc_chain_link(r->pool); | |
1519 if (cl == NULL) { | |
1520 return NULL; | |
1521 } | |
1522 | |
1523 cl->buf = b; | |
1524 cl->next = NULL; | |
1525 | |
1526 n = b->last - b->pos; | |
1527 | |
1528 len = ngx_http_v3_encode_varlen_int(NULL, NGX_HTTP_V3_FRAME_PUSH_PROMISE) | |
1529 + ngx_http_v3_encode_varlen_int(NULL, n); | |
1530 | |
1531 b = ngx_create_temp_buf(r->pool, len); | |
1532 if (b == NULL) { | |
1533 return NULL; | |
1534 } | |
1535 | |
1536 b->last = (u_char *) ngx_http_v3_encode_varlen_int(b->last, | |
1537 NGX_HTTP_V3_FRAME_PUSH_PROMISE); | |
1538 b->last = (u_char *) ngx_http_v3_encode_varlen_int(b->last, n); | |
1539 | |
1540 hl = ngx_alloc_chain_link(r->pool); | |
1541 if (hl == NULL) { | |
1542 return NULL; | |
1543 } | |
1544 | |
1545 hl->buf = b; | |
1546 hl->next = cl; | |
1547 | |
1548 return hl; | |
1549 } |