Blame modules/http2/h2_headers.c

Packit 90a5c9
/* Licensed to the Apache Software Foundation (ASF) under one or more
Packit 90a5c9
 * contributor license agreements.  See the NOTICE file distributed with
Packit 90a5c9
 * this work for additional information regarding copyright ownership.
Packit 90a5c9
 * The ASF licenses this file to You under the Apache License, Version 2.0
Packit 90a5c9
 * (the "License"); you may not use this file except in compliance with
Packit 90a5c9
 * the License.  You may obtain a copy of the License at
Packit 90a5c9
 *
Packit 90a5c9
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 90a5c9
 *
Packit 90a5c9
 * Unless required by applicable law or agreed to in writing, software
Packit 90a5c9
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 90a5c9
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 90a5c9
 * See the License for the specific language governing permissions and
Packit 90a5c9
 * limitations under the License.
Packit 90a5c9
 */
Packit 90a5c9
 
Packit 90a5c9
#include <assert.h>
Packit 90a5c9
#include <stdio.h>
Packit 90a5c9
Packit 90a5c9
#include <apr_strings.h>
Packit 90a5c9
Packit 90a5c9
#include <httpd.h>
Packit 90a5c9
#include <http_core.h>
Packit 90a5c9
#include <http_log.h>
Packit 90a5c9
#include <util_time.h>
Packit 90a5c9
Packit 90a5c9
#include <nghttp2/nghttp2.h>
Packit 90a5c9
Packit 90a5c9
#include "h2_private.h"
Packit 90a5c9
#include "h2_h2.h"
Packit 90a5c9
#include "h2_util.h"
Packit 90a5c9
#include "h2_request.h"
Packit 90a5c9
#include "h2_headers.h"
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
static int is_unsafe(server_rec *s) 
Packit 90a5c9
{
Packit 90a5c9
    core_server_config *conf = ap_get_core_module_config(s->module_config);
Packit 90a5c9
    return (conf->http_conformance == AP_HTTP_CONFORMANCE_UNSAFE);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
typedef struct {
Packit 90a5c9
    apr_bucket_refcount refcount;
Packit 90a5c9
    h2_headers *headers;
Packit 90a5c9
} h2_bucket_headers;
Packit 90a5c9
 
Packit 90a5c9
static apr_status_t bucket_read(apr_bucket *b, const char **str,
Packit 90a5c9
                                apr_size_t *len, apr_read_type_e block)
Packit 90a5c9
{
Packit 90a5c9
    (void)b;
Packit 90a5c9
    (void)block;
Packit 90a5c9
    *str = NULL;
Packit 90a5c9
    *len = 0;
Packit 90a5c9
    return APR_SUCCESS;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
apr_bucket * h2_bucket_headers_make(apr_bucket *b, h2_headers *r)
Packit 90a5c9
{
Packit 90a5c9
    h2_bucket_headers *br;
Packit 90a5c9
Packit 90a5c9
    br = apr_bucket_alloc(sizeof(*br), b->list);
Packit 90a5c9
    br->headers = r;
Packit 90a5c9
Packit 90a5c9
    b = apr_bucket_shared_make(b, br, 0, 0);
Packit 90a5c9
    b->type = &h2_bucket_type_headers;
Packit 90a5c9
    
Packit 90a5c9
    return b;
Packit 90a5c9
} 
Packit 90a5c9
Packit 90a5c9
apr_bucket * h2_bucket_headers_create(apr_bucket_alloc_t *list, 
Packit 90a5c9
                                       h2_headers *r)
Packit 90a5c9
{
Packit 90a5c9
    apr_bucket *b = apr_bucket_alloc(sizeof(*b), list);
Packit 90a5c9
Packit 90a5c9
    APR_BUCKET_INIT(b);
Packit 90a5c9
    b->free = apr_bucket_free;
Packit 90a5c9
    b->list = list;
Packit 90a5c9
    b = h2_bucket_headers_make(b, r);
Packit 90a5c9
    return b;
Packit 90a5c9
}
Packit 90a5c9
                                       
Packit 90a5c9
h2_headers *h2_bucket_headers_get(apr_bucket *b)
Packit 90a5c9
{
Packit 90a5c9
    if (H2_BUCKET_IS_HEADERS(b)) {
Packit 90a5c9
        return ((h2_bucket_headers *)b->data)->headers;
Packit 90a5c9
    }
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
const apr_bucket_type_t h2_bucket_type_headers = {
Packit 90a5c9
    "H2HEADERS", 5, APR_BUCKET_METADATA,
Packit 90a5c9
    apr_bucket_destroy_noop,
Packit 90a5c9
    bucket_read,
Packit 90a5c9
    apr_bucket_setaside_noop,
Packit 90a5c9
    apr_bucket_split_notimpl,
Packit 90a5c9
    apr_bucket_shared_copy
Packit 90a5c9
};
Packit 90a5c9
Packit 90a5c9
apr_bucket *h2_bucket_headers_beam(struct h2_bucket_beam *beam,
Packit 90a5c9
                                    apr_bucket_brigade *dest,
Packit 90a5c9
                                    const apr_bucket *src)
Packit 90a5c9
{
Packit 90a5c9
    if (H2_BUCKET_IS_HEADERS(src)) {
Packit 90a5c9
        h2_headers *r = ((h2_bucket_headers *)src->data)->headers;
Packit 90a5c9
        apr_bucket *b = h2_bucket_headers_create(dest->bucket_alloc, r);
Packit 90a5c9
        APR_BRIGADE_INSERT_TAIL(dest, b);
Packit 90a5c9
        return b;
Packit 90a5c9
    }
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
h2_headers *h2_headers_create(int status, apr_table_t *headers_in, 
Packit 90a5c9
                                apr_table_t *notes, apr_off_t raw_bytes,
Packit 90a5c9
                                apr_pool_t *pool)
Packit 90a5c9
{
Packit 90a5c9
    h2_headers *headers = apr_pcalloc(pool, sizeof(h2_headers));
Packit 90a5c9
    headers->status    = status;
Packit 90a5c9
    headers->headers   = (headers_in? apr_table_clone(pool, headers_in)
Packit 90a5c9
                           : apr_table_make(pool, 5));
Packit 90a5c9
    headers->notes     = (notes? apr_table_clone(pool, notes)
Packit 90a5c9
                           : apr_table_make(pool, 5));
Packit 90a5c9
    return headers;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
h2_headers *h2_headers_rcreate(request_rec *r, int status,
Packit 90a5c9
                                 apr_table_t *header, apr_pool_t *pool)
Packit 90a5c9
{
Packit 90a5c9
    h2_headers *headers = h2_headers_create(status, header, r->notes, 0, pool);
Packit 90a5c9
    if (headers->status == HTTP_FORBIDDEN) {
Packit 90a5c9
        const char *cause = apr_table_get(r->notes, "ssl-renegotiate-forbidden");
Packit 90a5c9
        if (cause) {
Packit 90a5c9
            /* This request triggered a TLS renegotiation that is now allowed 
Packit 90a5c9
             * in HTTP/2. Tell the client that it should use HTTP/1.1 for this.
Packit 90a5c9
             */
Packit 90a5c9
            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, headers->status, r,
Packit 90a5c9
                          APLOGNO(03061) 
Packit 90a5c9
                          "h2_headers(%ld): renegotiate forbidden, cause: %s",
Packit 90a5c9
                          (long)r->connection->id, cause);
Packit 90a5c9
            headers->status = H2_ERR_HTTP_1_1_REQUIRED;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    if (is_unsafe(r->server)) {
Packit 90a5c9
        apr_table_setn(headers->notes, H2_HDR_CONFORMANCE, 
Packit 90a5c9
                       H2_HDR_CONFORMANCE_UNSAFE);
Packit 90a5c9
    }
Packit 90a5c9
    return headers;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
h2_headers *h2_headers_copy(apr_pool_t *pool, h2_headers *h)
Packit 90a5c9
{
Packit 90a5c9
    return h2_headers_create(h->status, h->headers, h->notes, h->raw_bytes, pool);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
h2_headers *h2_headers_die(apr_status_t type,
Packit 90a5c9
                             const h2_request *req, apr_pool_t *pool)
Packit 90a5c9
{
Packit 90a5c9
    h2_headers *headers;
Packit 90a5c9
    char *date;
Packit 90a5c9
    
Packit 90a5c9
    headers = apr_pcalloc(pool, sizeof(h2_headers));
Packit 90a5c9
    headers->status    = (type >= 200 && type < 600)? type : 500;
Packit 90a5c9
    headers->headers        = apr_table_make(pool, 5);
Packit 90a5c9
    headers->notes          = apr_table_make(pool, 5);
Packit 90a5c9
Packit 90a5c9
    date = apr_palloc(pool, APR_RFC822_DATE_LEN);
Packit 90a5c9
    ap_recent_rfc822_date(date, req? req->request_time : apr_time_now());
Packit 90a5c9
    apr_table_setn(headers->headers, "Date", date);
Packit 90a5c9
    apr_table_setn(headers->headers, "Server", ap_get_server_banner());
Packit 90a5c9
    
Packit 90a5c9
    return headers;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
int h2_headers_are_response(h2_headers *headers)
Packit 90a5c9
{
Packit 90a5c9
    return headers->status >= 200;
Packit 90a5c9
}
Packit 90a5c9