"Fossies" - the Fresh Open Source Software Archive

Member "mod_http2-1.15.17/mod_http2/h2_request.c" (22 Feb 2021, 14273 Bytes) of package /linux/www/apache_httpd_modules/mod_http2-1.15.17.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "h2_request.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.15.16_vs_1.15.17.

    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     int was_added;
   51     h2_req_add_header(x->headers, x->pool, key, strlen(key), value, strlen(value), 0, &was_added);
   52     return 1;
   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     req->http_status = H2_HTTP_STATUS_UNSET;
   88     if (r->server) {
   89         req->serialize = h2_config_rgeti(r, H2_CONF_SER_HEADERS);
   90     }
   91 
   92     x.pool = pool;
   93     x.headers = req->headers;
   94     x.status = APR_SUCCESS;
   95     apr_table_do(set_h1_header, &x, r->headers_in, NULL);
   96     
   97     *preq = req;
   98     return x.status;
   99 }
  100 
  101 apr_status_t h2_request_add_header(h2_request *req, apr_pool_t *pool, 
  102                                    const char *name, size_t nlen,
  103                                    const char *value, size_t vlen,
  104                                    size_t max_field_len, int *pwas_added)
  105 {
  106     apr_status_t status = APR_SUCCESS;
  107     
  108     *pwas_added = 0;
  109     if (nlen <= 0) {
  110         return status;
  111     }
  112     
  113     if (name[0] == ':') {
  114         /* pseudo header, see ch. 8.1.2.3, always should come first */
  115         if (!apr_is_empty_table(req->headers)) {
  116             ap_log_perror(APLOG_MARK, APLOG_ERR, 0, pool,
  117                           APLOGNO(02917) 
  118                           "h2_request: pseudo header after request start");
  119             return APR_EGENERAL;
  120         }
  121         
  122         if (H2_HEADER_METHOD_LEN == nlen
  123             && !strncmp(H2_HEADER_METHOD, name, nlen)) {
  124             req->method = apr_pstrndup(pool, value, vlen);
  125         }
  126         else if (H2_HEADER_SCHEME_LEN == nlen
  127                  && !strncmp(H2_HEADER_SCHEME, name, nlen)) {
  128             req->scheme = apr_pstrndup(pool, value, vlen);
  129         }
  130         else if (H2_HEADER_PATH_LEN == nlen
  131                  && !strncmp(H2_HEADER_PATH, name, nlen)) {
  132             req->path = apr_pstrndup(pool, value, vlen);
  133         }
  134         else if (H2_HEADER_AUTH_LEN == nlen
  135                  && !strncmp(H2_HEADER_AUTH, name, nlen)) {
  136             req->authority = apr_pstrndup(pool, value, vlen);
  137         }
  138         else {
  139             char buffer[32];
  140             memset(buffer, 0, 32);
  141             strncpy(buffer, name, (nlen > 31)? 31 : nlen);
  142             ap_log_perror(APLOG_MARK, APLOG_WARNING, 0, pool,
  143                           APLOGNO(02954) 
  144                           "h2_request: ignoring unknown pseudo header %s",
  145                           buffer);
  146         }
  147     }
  148     else {
  149         /* non-pseudo header, add to table */
  150         status = h2_req_add_header(req->headers, pool, name, nlen, value, vlen, 
  151                                    max_field_len, pwas_added);
  152     }
  153     
  154     return status;
  155 }
  156 
  157 apr_status_t h2_request_end_headers(h2_request *req, apr_pool_t *pool, int eos, size_t raw_bytes)
  158 {
  159     const char *s;
  160     
  161     /* rfc7540, ch. 8.1.2.3:
  162      * - if we have :authority, it overrides any Host header 
  163      * - :authority MUST be omitted when converting h1->h2, so we
  164      *   might get a stream without, but then Host needs to be there */
  165     if (!req->authority) {
  166         const char *host = apr_table_get(req->headers, "Host");
  167         if (!host) {
  168             return APR_BADARG;
  169         }
  170         req->authority = host;
  171     }
  172     else {
  173         apr_table_setn(req->headers, "Host", req->authority);
  174     }
  175 
  176     s = apr_table_get(req->headers, "Content-Length");
  177     if (!s) {
  178         /* HTTP/2 does not need a Content-Length for framing, but our
  179          * internal request processing is used to HTTP/1.1, so we
  180          * need to either add a Content-Length or a Transfer-Encoding
  181          * if any content can be expected. */
  182         if (!eos) {
  183             /* We have not seen a content-length and have no eos,
  184              * simulate a chunked encoding for our HTTP/1.1 infrastructure,
  185              * in case we have "H2SerializeHeaders on" here
  186              */
  187             req->chunked = 1;
  188             apr_table_mergen(req->headers, "Transfer-Encoding", "chunked");
  189         }
  190         else if (apr_table_get(req->headers, "Content-Type")) {
  191             /* If we have a content-type, but already seen eos, no more
  192              * data will come. Signal a zero content length explicitly.
  193              */
  194             apr_table_setn(req->headers, "Content-Length", "0");
  195         }
  196     }
  197     req->raw_bytes += raw_bytes;
  198     
  199     return APR_SUCCESS;
  200 }
  201 
  202 h2_request *h2_request_clone(apr_pool_t *p, const h2_request *src)
  203 {
  204     h2_request *dst = apr_pmemdup(p, src, sizeof(*dst));
  205     dst->method       = apr_pstrdup(p, src->method);
  206     dst->scheme       = apr_pstrdup(p, src->scheme);
  207     dst->authority    = apr_pstrdup(p, src->authority);
  208     dst->path         = apr_pstrdup(p, src->path);
  209     dst->headers      = apr_table_clone(p, src->headers);
  210     return dst;
  211 }
  212 
  213 #if !AP_MODULE_MAGIC_AT_LEAST(20150222, 13)
  214 static request_rec *my_ap_create_request(conn_rec *c)
  215 {
  216     apr_pool_t *p;
  217     request_rec *r;
  218 
  219     apr_pool_create(&p, c->pool);
  220     apr_pool_tag(p, "request");
  221     r = apr_pcalloc(p, sizeof(request_rec));
  222     AP_READ_REQUEST_ENTRY((intptr_t)r, (uintptr_t)c);
  223     r->pool            = p;
  224     r->connection      = c;
  225     r->server          = c->base_server;
  226     
  227     r->user            = NULL;
  228     r->ap_auth_type    = NULL;
  229     
  230     r->allowed_methods = ap_make_method_list(p, 2);
  231 
  232     r->headers_in      = apr_table_make(r->pool, 5);
  233     r->trailers_in     = apr_table_make(r->pool, 5);
  234     r->subprocess_env  = apr_table_make(r->pool, 25);
  235     r->headers_out     = apr_table_make(r->pool, 12);
  236     r->err_headers_out = apr_table_make(r->pool, 5);
  237     r->trailers_out    = apr_table_make(r->pool, 5);
  238     r->notes           = apr_table_make(r->pool, 5);
  239     
  240     r->request_config  = ap_create_request_config(r->pool);
  241     /* Must be set before we run create request hook */
  242     
  243     r->proto_output_filters = c->output_filters;
  244     r->output_filters  = r->proto_output_filters;
  245     r->proto_input_filters = c->input_filters;
  246     r->input_filters   = r->proto_input_filters;
  247     ap_run_create_request(r);
  248     r->per_dir_config  = r->server->lookup_defaults;
  249     
  250     r->sent_bodyct     = 0;                      /* bytect isn't for body */
  251     
  252     r->read_length     = 0;
  253     r->read_body       = REQUEST_NO_BODY;
  254     
  255     r->status          = HTTP_OK;  /* Until further notice */
  256     r->header_only     = 0;
  257     r->the_request     = NULL;
  258     
  259     /* Begin by presuming any module can make its own path_info assumptions,
  260      * until some module interjects and changes the value.
  261      */
  262     r->used_path_info = AP_REQ_DEFAULT_PATH_INFO;
  263     
  264     r->useragent_addr = c->client_addr;
  265     r->useragent_ip = c->client_ip;
  266     
  267     return r;
  268 }
  269 #endif
  270 
  271 request_rec *h2_request_create_rec(const h2_request *req, conn_rec *c)
  272 {
  273     int access_status;
  274 
  275 #if AP_MODULE_MAGIC_AT_LEAST(20150222, 13)
  276     request_rec *r = ap_create_request(c);
  277 #else
  278     request_rec *r = my_ap_create_request(c);
  279 #endif
  280 
  281 #if AP_MODULE_MAGIC_AT_LEAST(20200331, 3)
  282     ap_run_pre_read_request(r, c);
  283 
  284     /* Time to populate r with the data we have. */
  285     r->request_time = req->request_time;
  286     r->the_request = apr_psprintf(r->pool, "%s %s HTTP/2.0",
  287                                   req->method, req->path ? req->path : "");
  288     r->headers_in = apr_table_clone(r->pool, req->headers);
  289 
  290     /* Start with r->hostname = NULL, ap_check_request_header() will get it
  291      * form Host: header, otherwise we get complains about port numbers.
  292      */
  293     r->hostname = NULL;
  294 
  295     /* Validate HTTP/1 request and select vhost. */
  296     if (!ap_parse_request_line(r) || !ap_check_request_header(r)) {
  297         /* we may have switched to another server still */
  298         r->per_dir_config = r->server->lookup_defaults;
  299         if (req->http_status != H2_HTTP_STATUS_UNSET) {
  300             access_status = req->http_status;
  301             /* Be safe and close the connection */
  302             c->keepalive = AP_CONN_CLOSE;
  303         }
  304         else {
  305             access_status = r->status;
  306         }
  307         r->status = HTTP_OK;
  308         goto die;
  309     }
  310 #else
  311     {
  312         const char *s;
  313 
  314         r->headers_in = apr_table_clone(r->pool, req->headers);
  315         ap_run_pre_read_request(r, c);
  316 
  317         /* Time to populate r with the data we have. */
  318         r->request_time = req->request_time;
  319         r->method = apr_pstrdup(r->pool, req->method);
  320         /* Provide quick information about the request method as soon as known */
  321         r->method_number = ap_method_number_of(r->method);
  322         if (r->method_number == M_GET && r->method[0] == 'H') {
  323             r->header_only = 1;
  324         }
  325         ap_parse_uri(r, req->path ? req->path : "");
  326         r->protocol = (char*)"HTTP/2.0";
  327         r->proto_num = HTTP_VERSION(2, 0);
  328         r->the_request = apr_psprintf(r->pool, "%s %s HTTP/2.0",
  329                                       r->method, req->path ? req->path : "");
  330 
  331         /* Start with r->hostname = NULL, ap_check_request_header() will get it
  332          * form Host: header, otherwise we get complains about port numbers.
  333          */
  334         r->hostname = NULL;
  335         ap_update_vhost_from_headers(r);
  336 
  337          /* we may have switched to another server */
  338          r->per_dir_config = r->server->lookup_defaults;
  339 
  340          s = apr_table_get(r->headers_in, "Expect");
  341          if (s && s[0]) {
  342             if (ap_cstr_casecmp(s, "100-continue") == 0) {
  343                 r->expecting_100 = 1;
  344             }
  345             else {
  346                 r->status = HTTP_EXPECTATION_FAILED;
  347                 access_status = r->status;
  348                 goto die;
  349             }
  350          }
  351     }
  352 #endif
  353 
  354     /* we may have switched to another server */
  355     r->per_dir_config = r->server->lookup_defaults;
  356 
  357     if (req->http_status != H2_HTTP_STATUS_UNSET) {
  358         access_status = req->http_status;
  359         r->status = HTTP_OK;
  360         /* Be safe and close the connection */
  361         c->keepalive = AP_CONN_CLOSE;
  362         goto die;
  363     }
  364 
  365     /*
  366      * Add the HTTP_IN filter here to ensure that ap_discard_request_body
  367      * called by ap_die and by ap_send_error_response works correctly on
  368      * status codes that do not cause the connection to be dropped and
  369      * in situations where the connection should be kept alive.
  370      */
  371     ap_add_input_filter_handle(ap_http_input_filter_handle,
  372                                NULL, r, r->connection);
  373     
  374     if ((access_status = ap_run_post_read_request(r))) {
  375         /* Request check post hooks failed. An example of this would be a
  376          * request for a vhost where h2 is disabled --> 421.
  377          */
  378         ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(03367)
  379                       "h2_request: access_status=%d, request_create failed",
  380                       access_status);
  381         goto die;
  382     }
  383 
  384     AP_READ_REQUEST_SUCCESS((uintptr_t)r, (char *)r->method, 
  385                             (char *)r->uri, (char *)r->server->defn_name, 
  386                             r->status);
  387     return r;
  388 
  389 die:
  390     ap_die(access_status, r);
  391 
  392     /* ap_die() sent the response through the output filters, we must now
  393      * end the request with an EOR bucket for stream/pipeline accounting.
  394      */
  395     {
  396         apr_bucket_brigade *eor_bb;
  397 #if AP_MODULE_MAGIC_AT_LEAST(20180905, 1)
  398         eor_bb = ap_acquire_brigade(c);
  399         APR_BRIGADE_INSERT_TAIL(eor_bb,
  400                                 ap_bucket_eor_create(c->bucket_alloc, r));
  401         ap_pass_brigade(c->output_filters, eor_bb);
  402         ap_release_brigade(c, eor_bb);
  403 #else
  404         eor_bb = apr_brigade_create(c->pool, c->bucket_alloc);
  405         APR_BRIGADE_INSERT_TAIL(eor_bb,
  406                                 ap_bucket_eor_create(c->bucket_alloc, r));
  407         ap_pass_brigade(c->output_filters, eor_bb);
  408         apr_brigade_destroy(eor_bb);
  409 #endif
  410     }
  411 
  412     r = NULL;
  413     AP_READ_REQUEST_FAILURE((uintptr_t)r);
  414     return NULL;
  415 }
  416 
  417 
  418