|
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 |
|