]> granicus.if.org Git - apache/blob - modules/http2/h2_request.c
Reverting the unwanted revert of r1852989.
[apache] / modules / http2 / h2_request.c
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16  
17 #include <assert.h>
18
19 #include <apr_strings.h>
20 #include <ap_mmn.h>
21
22 #include <httpd.h>
23 #include <http_core.h>
24 #include <http_connection.h>
25 #include <http_protocol.h>
26 #include <http_request.h>
27 #include <http_log.h>
28 #include <http_vhost.h>
29 #include <util_filter.h>
30 #include <ap_mpm.h>
31 #include <mod_core.h>
32 #include <scoreboard.h>
33
34 #include "h2_private.h"
35 #include "h2_config.h"
36 #include "h2_push.h"
37 #include "h2_request.h"
38 #include "h2_util.h"
39
40
41 typedef struct {
42     apr_table_t *headers;
43     apr_pool_t *pool;
44     apr_status_t status;
45 } h1_ctx;
46
47 static int set_h1_header(void *ctx, const char *key, const char *value)
48 {
49     h1_ctx *x = ctx;
50     x->status = h2_req_add_header(x->headers, x->pool, key, strlen(key), 
51                                   value, strlen(value));
52     return (x->status == APR_SUCCESS)? 1 : 0;
53 }
54
55 apr_status_t h2_request_rcreate(h2_request **preq, apr_pool_t *pool, 
56                                 request_rec *r)
57 {
58     h2_request *req;
59     const char *scheme, *authority, *path;
60     h1_ctx x;
61     
62     *preq = NULL;
63     scheme = apr_pstrdup(pool, r->parsed_uri.scheme? r->parsed_uri.scheme
64               : ap_http_scheme(r));
65     authority = apr_pstrdup(pool, r->hostname);
66     path = apr_uri_unparse(pool, &r->parsed_uri, APR_URI_UNP_OMITSITEPART);
67     
68     if (!r->method || !scheme || !r->hostname || !path) {
69         return APR_EINVAL;
70     }
71
72     if (!ap_strchr_c(authority, ':') && r->server && r->server->port) {
73         apr_port_t defport = apr_uri_port_of_scheme(scheme);
74         if (defport != r->server->port) {
75             /* port info missing and port is not default for scheme: append */
76             authority = apr_psprintf(pool, "%s:%d", authority,
77                                      (int)r->server->port);
78         }
79     }
80     
81     req = apr_pcalloc(pool, sizeof(*req));
82     req->method    = apr_pstrdup(pool, r->method);
83     req->scheme    = scheme;
84     req->authority = authority;
85     req->path      = path;
86     req->headers   = apr_table_make(pool, 10);
87     if (r->server) {
88         req->serialize = h2_config_rgeti(r, H2_CONF_SER_HEADERS);
89     }
90
91     x.pool = pool;
92     x.headers = req->headers;
93     x.status = APR_SUCCESS;
94     apr_table_do(set_h1_header, &x, r->headers_in, NULL);
95     
96     *preq = req;
97     return x.status;
98 }
99
100 apr_status_t h2_request_add_header(h2_request *req, apr_pool_t *pool, 
101                                    const char *name, size_t nlen,
102                                    const char *value, size_t vlen)
103 {
104     apr_status_t status = APR_SUCCESS;
105     
106     if (nlen <= 0) {
107         return status;
108     }
109     
110     if (name[0] == ':') {
111         /* pseudo header, see ch. 8.1.2.3, always should come first */
112         if (!apr_is_empty_table(req->headers)) {
113             ap_log_perror(APLOG_MARK, APLOG_ERR, 0, pool,
114                           APLOGNO(02917) 
115                           "h2_request: pseudo header after request start");
116             return APR_EGENERAL;
117         }
118         
119         if (H2_HEADER_METHOD_LEN == nlen
120             && !strncmp(H2_HEADER_METHOD, name, nlen)) {
121             req->method = apr_pstrndup(pool, value, vlen);
122         }
123         else if (H2_HEADER_SCHEME_LEN == nlen
124                  && !strncmp(H2_HEADER_SCHEME, name, nlen)) {
125             req->scheme = apr_pstrndup(pool, value, vlen);
126         }
127         else if (H2_HEADER_PATH_LEN == nlen
128                  && !strncmp(H2_HEADER_PATH, name, nlen)) {
129             req->path = apr_pstrndup(pool, value, vlen);
130         }
131         else if (H2_HEADER_AUTH_LEN == nlen
132                  && !strncmp(H2_HEADER_AUTH, name, nlen)) {
133             req->authority = apr_pstrndup(pool, value, vlen);
134         }
135         else {
136             char buffer[32];
137             memset(buffer, 0, 32);
138             strncpy(buffer, name, (nlen > 31)? 31 : nlen);
139             ap_log_perror(APLOG_MARK, APLOG_WARNING, 0, pool,
140                           APLOGNO(02954) 
141                           "h2_request: ignoring unknown pseudo header %s",
142                           buffer);
143         }
144     }
145     else {
146         /* non-pseudo header, append to work bucket of stream */
147         status = h2_req_add_header(req->headers, pool, name, nlen, value, vlen);
148     }
149     
150     return status;
151 }
152
153 apr_status_t h2_request_end_headers(h2_request *req, apr_pool_t *pool, int eos, size_t raw_bytes)
154 {
155     const char *s;
156     
157     /* rfc7540, ch. 8.1.2.3:
158      * - if we have :authority, it overrides any Host header 
159      * - :authority MUST be ommited when converting h1->h2, so we
160      *   might get a stream without, but then Host needs to be there */
161     if (!req->authority) {
162         const char *host = apr_table_get(req->headers, "Host");
163         if (!host) {
164             return APR_BADARG;
165         }
166         req->authority = host;
167     }
168     else {
169         apr_table_setn(req->headers, "Host", req->authority);
170     }
171
172     s = apr_table_get(req->headers, "Content-Length");
173     if (!s) {
174         /* HTTP/2 does not need a Content-Length for framing, but our
175          * internal request processing is used to HTTP/1.1, so we
176          * need to either add a Content-Length or a Transfer-Encoding
177          * if any content can be expected. */
178         if (!eos) {
179             /* We have not seen a content-length and have no eos,
180              * simulate a chunked encoding for our HTTP/1.1 infrastructure,
181              * in case we have "H2SerializeHeaders on" here
182              */
183             req->chunked = 1;
184             apr_table_mergen(req->headers, "Transfer-Encoding", "chunked");
185         }
186         else if (apr_table_get(req->headers, "Content-Type")) {
187             /* If we have a content-type, but already seen eos, no more
188              * data will come. Signal a zero content length explicitly.
189              */
190             apr_table_setn(req->headers, "Content-Length", "0");
191         }
192     }
193     req->raw_bytes += raw_bytes;
194     
195     return APR_SUCCESS;
196 }
197
198 h2_request *h2_request_clone(apr_pool_t *p, const h2_request *src)
199 {
200     h2_request *dst = apr_pmemdup(p, src, sizeof(*dst));
201     dst->method       = apr_pstrdup(p, src->method);
202     dst->scheme       = apr_pstrdup(p, src->scheme);
203     dst->authority    = apr_pstrdup(p, src->authority);
204     dst->path         = apr_pstrdup(p, src->path);
205     dst->headers      = apr_table_clone(p, src->headers);
206     return dst;
207 }
208
209 #if !AP_MODULE_MAGIC_AT_LEAST(20150222, 13)
210 static request_rec *my_ap_create_request(conn_rec *c)
211 {
212     apr_pool_t *p;
213     request_rec *r;
214
215     apr_pool_create(&p, c->pool);
216     apr_pool_tag(p, "request");
217     r = apr_pcalloc(p, sizeof(request_rec));
218     AP_READ_REQUEST_ENTRY((intptr_t)r, (uintptr_t)c);
219     r->pool            = p;
220     r->connection      = c;
221     r->server          = c->base_server;
222     
223     r->user            = NULL;
224     r->ap_auth_type    = NULL;
225     
226     r->allowed_methods = ap_make_method_list(p, 2);
227
228     r->headers_in      = apr_table_make(r->pool, 5);
229     r->trailers_in     = apr_table_make(r->pool, 5);
230     r->subprocess_env  = apr_table_make(r->pool, 25);
231     r->headers_out     = apr_table_make(r->pool, 12);
232     r->err_headers_out = apr_table_make(r->pool, 5);
233     r->trailers_out    = apr_table_make(r->pool, 5);
234     r->notes           = apr_table_make(r->pool, 5);
235     
236     r->request_config  = ap_create_request_config(r->pool);
237     /* Must be set before we run create request hook */
238     
239     r->proto_output_filters = c->output_filters;
240     r->output_filters  = r->proto_output_filters;
241     r->proto_input_filters = c->input_filters;
242     r->input_filters   = r->proto_input_filters;
243     ap_run_create_request(r);
244     r->per_dir_config  = r->server->lookup_defaults;
245     
246     r->sent_bodyct     = 0;                      /* bytect isn't for body */
247     
248     r->read_length     = 0;
249     r->read_body       = REQUEST_NO_BODY;
250     
251     r->status          = HTTP_OK;  /* Until further notice */
252     r->header_only     = 0;
253     r->the_request     = NULL;
254     
255     /* Begin by presuming any module can make its own path_info assumptions,
256      * until some module interjects and changes the value.
257      */
258     r->used_path_info = AP_REQ_DEFAULT_PATH_INFO;
259     
260     r->useragent_addr = c->client_addr;
261     r->useragent_ip = c->client_ip;
262     
263     return r;
264 }
265 #endif
266
267 request_rec *h2_request_create_rec(const h2_request *req, conn_rec *c)
268 {
269     int access_status = HTTP_OK;    
270     const char *rpath;
271     const char *s;
272
273 #if AP_MODULE_MAGIC_AT_LEAST(20150222, 13)
274     request_rec *r = ap_create_request(c);
275 #else
276     request_rec *r = my_ap_create_request(c);
277 #endif
278
279     r->headers_in = apr_table_clone(r->pool, req->headers);
280
281     ap_run_pre_read_request(r, c);
282     
283     /* Time to populate r with the data we have. */
284     r->request_time = req->request_time;
285     r->method = apr_pstrdup(r->pool, req->method);
286     /* Provide quick information about the request method as soon as known */
287     r->method_number = ap_method_number_of(r->method);
288     if (r->method_number == M_GET && r->method[0] == 'H') {
289         r->header_only = 1;
290     }
291
292     rpath = (req->path ? req->path : "");
293     ap_parse_uri(r, rpath);
294     r->protocol = (char*)"HTTP/2.0";
295     r->proto_num = HTTP_VERSION(2, 0);
296
297     r->the_request = apr_psprintf(r->pool, "%s %s %s", 
298                                   r->method, rpath, r->protocol);
299     
300     /* update what we think the virtual host is based on the headers we've
301      * now read. may update status.
302      * Leave r->hostname empty, vhost will parse if form our Host: header,
303      * otherwise we get complains about port numbers.
304      */
305     r->hostname = NULL;
306     ap_update_vhost_from_headers(r);
307     
308     /* we may have switched to another server */
309     r->per_dir_config = r->server->lookup_defaults;
310     
311     s = apr_table_get(r->headers_in, "Expect");
312     if (s && s[0]) {
313         if (ap_cstr_casecmp(s, "100-continue") == 0) {
314             r->expecting_100 = 1;
315         }
316         else {
317             r->status = HTTP_EXPECTATION_FAILED;
318             ap_send_error_response(r, 0);
319         }
320     }
321
322     /*
323      * Add the HTTP_IN filter here to ensure that ap_discard_request_body
324      * called by ap_die and by ap_send_error_response works correctly on
325      * status codes that do not cause the connection to be dropped and
326      * in situations where the connection should be kept alive.
327      */
328     ap_add_input_filter_handle(ap_http_input_filter_handle,
329                                NULL, r, r->connection);
330     
331     if (access_status != HTTP_OK
332         || (access_status = ap_run_post_read_request(r))) {
333         /* Request check post hooks failed. An example of this would be a
334          * request for a vhost where h2 is disabled --> 421.
335          */
336         ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(03367)
337                       "h2_request: access_status=%d, request_create failed",
338                       access_status);
339         ap_die(access_status, r);
340         ap_update_child_status(c->sbh, SERVER_BUSY_LOG, r);
341         ap_run_log_transaction(r);
342         r = NULL;
343         goto traceout;
344     }
345
346     AP_READ_REQUEST_SUCCESS((uintptr_t)r, (char *)r->method, 
347                             (char *)r->uri, (char *)r->server->defn_name, 
348                             r->status);
349     return r;
350 traceout:
351     AP_READ_REQUEST_FAILURE((uintptr_t)r);
352     return r;
353 }
354
355
356