|
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 <apr_lib.h>
|
|
Packit |
90a5c9 |
#include <apr_strings.h>
|
|
Packit |
90a5c9 |
#include <apr_thread_mutex.h>
|
|
Packit |
90a5c9 |
#include <apr_thread_cond.h>
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#include <httpd.h>
|
|
Packit |
90a5c9 |
#include <http_core.h>
|
|
Packit |
90a5c9 |
#include <http_log.h>
|
|
Packit |
90a5c9 |
#include <http_request.h>
|
|
Packit |
90a5c9 |
#include <mod_proxy.h>
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#include <nghttp2/nghttp2.h>
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#include "h2.h"
|
|
Packit |
90a5c9 |
#include "h2_proxy_util.h"
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
APLOG_USE_MODULE(proxy_http2);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* h2_log2(n) iff n is a power of 2 */
|
|
Packit |
90a5c9 |
unsigned char h2_proxy_log2(int n)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
int lz = 0;
|
|
Packit |
90a5c9 |
if (!n) {
|
|
Packit |
90a5c9 |
return 0;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (!(n & 0xffff0000u)) {
|
|
Packit |
90a5c9 |
lz += 16;
|
|
Packit |
90a5c9 |
n = (n << 16);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (!(n & 0xff000000u)) {
|
|
Packit |
90a5c9 |
lz += 8;
|
|
Packit |
90a5c9 |
n = (n << 8);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (!(n & 0xf0000000u)) {
|
|
Packit |
90a5c9 |
lz += 4;
|
|
Packit |
90a5c9 |
n = (n << 4);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (!(n & 0xc0000000u)) {
|
|
Packit |
90a5c9 |
lz += 2;
|
|
Packit |
90a5c9 |
n = (n << 2);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (!(n & 0x80000000u)) {
|
|
Packit |
90a5c9 |
lz += 1;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return 31 - lz;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/*******************************************************************************
|
|
Packit |
90a5c9 |
* ihash - hash for structs with int identifier
|
|
Packit |
90a5c9 |
******************************************************************************/
|
|
Packit |
90a5c9 |
struct h2_proxy_ihash_t {
|
|
Packit |
90a5c9 |
apr_hash_t *hash;
|
|
Packit |
90a5c9 |
size_t ioff;
|
|
Packit |
90a5c9 |
};
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static unsigned int ihash(const char *key, apr_ssize_t *klen)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return (unsigned int)(*((int*)key));
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
h2_proxy_ihash_t *h2_proxy_ihash_create(apr_pool_t *pool, size_t offset_of_int)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
h2_proxy_ihash_t *ih = apr_pcalloc(pool, sizeof(h2_proxy_ihash_t));
|
|
Packit |
90a5c9 |
ih->hash = apr_hash_make_custom(pool, ihash);
|
|
Packit |
90a5c9 |
ih->ioff = offset_of_int;
|
|
Packit |
90a5c9 |
return ih;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
size_t h2_proxy_ihash_count(h2_proxy_ihash_t *ih)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return apr_hash_count(ih->hash);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
int h2_proxy_ihash_empty(h2_proxy_ihash_t *ih)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return apr_hash_count(ih->hash) == 0;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
void *h2_proxy_ihash_get(h2_proxy_ihash_t *ih, int id)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return apr_hash_get(ih->hash, &id, sizeof(id));
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
typedef struct {
|
|
Packit |
90a5c9 |
h2_proxy_ihash_iter_t *iter;
|
|
Packit |
90a5c9 |
void *ctx;
|
|
Packit |
90a5c9 |
} iter_ctx;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int ihash_iter(void *ctx, const void *key, apr_ssize_t klen,
|
|
Packit |
90a5c9 |
const void *val)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
iter_ctx *ictx = ctx;
|
|
Packit |
90a5c9 |
return ictx->iter(ictx->ctx, (void*)val); /* why is this passed const?*/
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
int h2_proxy_ihash_iter(h2_proxy_ihash_t *ih, h2_proxy_ihash_iter_t *fn, void *ctx)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
iter_ctx ictx;
|
|
Packit |
90a5c9 |
ictx.iter = fn;
|
|
Packit |
90a5c9 |
ictx.ctx = ctx;
|
|
Packit |
90a5c9 |
return apr_hash_do(ihash_iter, &ictx, ih->hash);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
void h2_proxy_ihash_add(h2_proxy_ihash_t *ih, void *val)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_hash_set(ih->hash, ((char *)val + ih->ioff), sizeof(int), val);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
void h2_proxy_ihash_remove(h2_proxy_ihash_t *ih, int id)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_hash_set(ih->hash, &id, sizeof(id), NULL);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
void h2_proxy_ihash_remove_val(h2_proxy_ihash_t *ih, void *val)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
int id = *((int*)((char *)val + ih->ioff));
|
|
Packit |
90a5c9 |
apr_hash_set(ih->hash, &id, sizeof(id), NULL);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
void h2_proxy_ihash_clear(h2_proxy_ihash_t *ih)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_hash_clear(ih->hash);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
typedef struct {
|
|
Packit |
90a5c9 |
h2_proxy_ihash_t *ih;
|
|
Packit |
90a5c9 |
void **buffer;
|
|
Packit |
90a5c9 |
size_t max;
|
|
Packit |
90a5c9 |
size_t len;
|
|
Packit |
90a5c9 |
} collect_ctx;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int collect_iter(void *x, void *val)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
collect_ctx *ctx = x;
|
|
Packit |
90a5c9 |
if (ctx->len < ctx->max) {
|
|
Packit |
90a5c9 |
ctx->buffer[ctx->len++] = val;
|
|
Packit |
90a5c9 |
return 1;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return 0;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
size_t h2_proxy_ihash_shift(h2_proxy_ihash_t *ih, void **buffer, size_t max)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
collect_ctx ctx;
|
|
Packit |
90a5c9 |
size_t i;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
ctx.ih = ih;
|
|
Packit |
90a5c9 |
ctx.buffer = buffer;
|
|
Packit |
90a5c9 |
ctx.max = max;
|
|
Packit |
90a5c9 |
ctx.len = 0;
|
|
Packit |
90a5c9 |
h2_proxy_ihash_iter(ih, collect_iter, &ctx;;
|
|
Packit |
90a5c9 |
for (i = 0; i < ctx.len; ++i) {
|
|
Packit |
90a5c9 |
h2_proxy_ihash_remove_val(ih, buffer[i]);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return ctx.len;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
typedef struct {
|
|
Packit |
90a5c9 |
h2_proxy_ihash_t *ih;
|
|
Packit |
90a5c9 |
int *buffer;
|
|
Packit |
90a5c9 |
size_t max;
|
|
Packit |
90a5c9 |
size_t len;
|
|
Packit |
90a5c9 |
} icollect_ctx;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int icollect_iter(void *x, void *val)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
icollect_ctx *ctx = x;
|
|
Packit |
90a5c9 |
if (ctx->len < ctx->max) {
|
|
Packit |
90a5c9 |
ctx->buffer[ctx->len++] = *((int*)((char *)val + ctx->ih->ioff));
|
|
Packit |
90a5c9 |
return 1;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return 0;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
size_t h2_proxy_ihash_ishift(h2_proxy_ihash_t *ih, int *buffer, size_t max)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
icollect_ctx ctx;
|
|
Packit |
90a5c9 |
size_t i;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
ctx.ih = ih;
|
|
Packit |
90a5c9 |
ctx.buffer = buffer;
|
|
Packit |
90a5c9 |
ctx.max = max;
|
|
Packit |
90a5c9 |
ctx.len = 0;
|
|
Packit |
90a5c9 |
h2_proxy_ihash_iter(ih, icollect_iter, &ctx;;
|
|
Packit |
90a5c9 |
for (i = 0; i < ctx.len; ++i) {
|
|
Packit |
90a5c9 |
h2_proxy_ihash_remove(ih, buffer[i]);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return ctx.len;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/*******************************************************************************
|
|
Packit |
90a5c9 |
* iqueue - sorted list of int
|
|
Packit |
90a5c9 |
******************************************************************************/
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static void iq_grow(h2_proxy_iqueue *q, int nlen);
|
|
Packit |
90a5c9 |
static void iq_swap(h2_proxy_iqueue *q, int i, int j);
|
|
Packit |
90a5c9 |
static int iq_bubble_up(h2_proxy_iqueue *q, int i, int top,
|
|
Packit |
90a5c9 |
h2_proxy_iq_cmp *cmp, void *ctx);
|
|
Packit |
90a5c9 |
static int iq_bubble_down(h2_proxy_iqueue *q, int i, int bottom,
|
|
Packit |
90a5c9 |
h2_proxy_iq_cmp *cmp, void *ctx);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
h2_proxy_iqueue *h2_proxy_iq_create(apr_pool_t *pool, int capacity)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
h2_proxy_iqueue *q = apr_pcalloc(pool, sizeof(h2_proxy_iqueue));
|
|
Packit |
90a5c9 |
if (q) {
|
|
Packit |
90a5c9 |
q->pool = pool;
|
|
Packit |
90a5c9 |
iq_grow(q, capacity);
|
|
Packit |
90a5c9 |
q->nelts = 0;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return q;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
int h2_proxy_iq_empty(h2_proxy_iqueue *q)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return q->nelts == 0;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
int h2_proxy_iq_count(h2_proxy_iqueue *q)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return q->nelts;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
void h2_proxy_iq_add(h2_proxy_iqueue *q, int sid, h2_proxy_iq_cmp *cmp, void *ctx)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
int i;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (q->nelts >= q->nalloc) {
|
|
Packit |
90a5c9 |
iq_grow(q, q->nalloc * 2);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
i = (q->head + q->nelts) % q->nalloc;
|
|
Packit |
90a5c9 |
q->elts[i] = sid;
|
|
Packit |
90a5c9 |
++q->nelts;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (cmp) {
|
|
Packit |
90a5c9 |
/* bubble it to the front of the queue */
|
|
Packit |
90a5c9 |
iq_bubble_up(q, i, q->head, cmp, ctx);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
int h2_proxy_iq_remove(h2_proxy_iqueue *q, int sid)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
int i;
|
|
Packit |
90a5c9 |
for (i = 0; i < q->nelts; ++i) {
|
|
Packit |
90a5c9 |
if (sid == q->elts[(q->head + i) % q->nalloc]) {
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (i < q->nelts) {
|
|
Packit |
90a5c9 |
++i;
|
|
Packit |
90a5c9 |
for (; i < q->nelts; ++i) {
|
|
Packit |
90a5c9 |
q->elts[(q->head+i-1)%q->nalloc] = q->elts[(q->head+i)%q->nalloc];
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
--q->nelts;
|
|
Packit |
90a5c9 |
return 1;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return 0;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
void h2_proxy_iq_clear(h2_proxy_iqueue *q)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
q->nelts = 0;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
void h2_proxy_iq_sort(h2_proxy_iqueue *q, h2_proxy_iq_cmp *cmp, void *ctx)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
/* Assume that changes in ordering are minimal. This needs,
|
|
Packit |
90a5c9 |
* best case, q->nelts - 1 comparisons to check that nothing
|
|
Packit |
90a5c9 |
* changed.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
if (q->nelts > 0) {
|
|
Packit |
90a5c9 |
int i, ni, prev, last;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* Start at the end of the queue and create a tail of sorted
|
|
Packit |
90a5c9 |
* entries. Make that tail one element longer in each iteration.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
last = i = (q->head + q->nelts - 1) % q->nalloc;
|
|
Packit |
90a5c9 |
while (i != q->head) {
|
|
Packit |
90a5c9 |
prev = (q->nalloc + i - 1) % q->nalloc;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
ni = iq_bubble_up(q, i, prev, cmp, ctx);
|
|
Packit |
90a5c9 |
if (ni == prev) {
|
|
Packit |
90a5c9 |
/* i bubbled one up, bubble the new i down, which
|
|
Packit |
90a5c9 |
* keeps all tasks below i sorted. */
|
|
Packit |
90a5c9 |
iq_bubble_down(q, i, last, cmp, ctx);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
i = prev;
|
|
Packit |
90a5c9 |
};
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
int h2_proxy_iq_shift(h2_proxy_iqueue *q)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
int sid;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (q->nelts <= 0) {
|
|
Packit |
90a5c9 |
return 0;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
sid = q->elts[q->head];
|
|
Packit |
90a5c9 |
q->head = (q->head + 1) % q->nalloc;
|
|
Packit |
90a5c9 |
q->nelts--;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return sid;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static void iq_grow(h2_proxy_iqueue *q, int nlen)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
if (nlen > q->nalloc) {
|
|
Packit |
90a5c9 |
int *nq = apr_pcalloc(q->pool, sizeof(int) * nlen);
|
|
Packit |
90a5c9 |
if (q->nelts > 0) {
|
|
Packit |
90a5c9 |
int l = ((q->head + q->nelts) % q->nalloc) - q->head;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
memmove(nq, q->elts + q->head, sizeof(int) * l);
|
|
Packit |
90a5c9 |
if (l < q->nelts) {
|
|
Packit |
90a5c9 |
/* elts wrapped, append elts in [0, remain] to nq */
|
|
Packit |
90a5c9 |
int remain = q->nelts - l;
|
|
Packit |
90a5c9 |
memmove(nq + l, q->elts, sizeof(int) * remain);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
q->elts = nq;
|
|
Packit |
90a5c9 |
q->nalloc = nlen;
|
|
Packit |
90a5c9 |
q->head = 0;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static void iq_swap(h2_proxy_iqueue *q, int i, int j)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
int x = q->elts[i];
|
|
Packit |
90a5c9 |
q->elts[i] = q->elts[j];
|
|
Packit |
90a5c9 |
q->elts[j] = x;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int iq_bubble_up(h2_proxy_iqueue *q, int i, int top,
|
|
Packit |
90a5c9 |
h2_proxy_iq_cmp *cmp, void *ctx)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
int prev;
|
|
Packit |
90a5c9 |
while (((prev = (q->nalloc + i - 1) % q->nalloc), i != top)
|
|
Packit |
90a5c9 |
&& (*cmp)(q->elts[i], q->elts[prev], ctx) < 0) {
|
|
Packit |
90a5c9 |
iq_swap(q, prev, i);
|
|
Packit |
90a5c9 |
i = prev;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return i;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int iq_bubble_down(h2_proxy_iqueue *q, int i, int bottom,
|
|
Packit |
90a5c9 |
h2_proxy_iq_cmp *cmp, void *ctx)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
int next;
|
|
Packit |
90a5c9 |
while (((next = (q->nalloc + i + 1) % q->nalloc), i != bottom)
|
|
Packit |
90a5c9 |
&& (*cmp)(q->elts[i], q->elts[next], ctx) > 0) {
|
|
Packit |
90a5c9 |
iq_swap(q, next, i);
|
|
Packit |
90a5c9 |
i = next;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return i;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/*******************************************************************************
|
|
Packit |
90a5c9 |
* h2_proxy_ngheader
|
|
Packit |
90a5c9 |
******************************************************************************/
|
|
Packit |
90a5c9 |
#define H2_HD_MATCH_LIT_CS(l, name) \
|
|
Packit |
90a5c9 |
((strlen(name) == sizeof(l) - 1) && !apr_strnatcasecmp(l, name))
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int h2_util_ignore_header(const char *name)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
/* never forward, ch. 8.1.2.2 */
|
|
Packit |
90a5c9 |
return (H2_HD_MATCH_LIT_CS("connection", name)
|
|
Packit |
90a5c9 |
|| H2_HD_MATCH_LIT_CS("proxy-connection", name)
|
|
Packit |
90a5c9 |
|| H2_HD_MATCH_LIT_CS("upgrade", name)
|
|
Packit |
90a5c9 |
|| H2_HD_MATCH_LIT_CS("keep-alive", name)
|
|
Packit |
90a5c9 |
|| H2_HD_MATCH_LIT_CS("transfer-encoding", name));
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int count_header(void *ctx, const char *key, const char *value)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
if (!h2_util_ignore_header(key)) {
|
|
Packit |
90a5c9 |
(*((size_t*)ctx))++;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return 1;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#define NV_ADD_LIT_CS(nv, k, v) add_header(nv, k, sizeof(k) - 1, v, strlen(v))
|
|
Packit |
90a5c9 |
#define NV_ADD_CS_CS(nv, k, v) add_header(nv, k, strlen(k), v, strlen(v))
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int add_header(h2_proxy_ngheader *ngh,
|
|
Packit |
90a5c9 |
const char *key, size_t key_len,
|
|
Packit |
90a5c9 |
const char *value, size_t val_len)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
nghttp2_nv *nv = &ngh->nv[ngh->nvlen++];
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
nv->name = (uint8_t*)key;
|
|
Packit |
90a5c9 |
nv->namelen = key_len;
|
|
Packit |
90a5c9 |
nv->value = (uint8_t*)value;
|
|
Packit |
90a5c9 |
nv->valuelen = val_len;
|
|
Packit |
90a5c9 |
return 1;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int add_table_header(void *ctx, const char *key, const char *value)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
if (!h2_util_ignore_header(key)) {
|
|
Packit |
90a5c9 |
add_header(ctx, key, strlen(key), value, strlen(value));
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return 1;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
h2_proxy_ngheader *h2_proxy_util_nghd_make_req(apr_pool_t *p,
|
|
Packit |
90a5c9 |
const h2_proxy_request *req)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
h2_proxy_ngheader *ngh;
|
|
Packit |
90a5c9 |
size_t n;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
ap_assert(req);
|
|
Packit |
90a5c9 |
ap_assert(req->scheme);
|
|
Packit |
90a5c9 |
ap_assert(req->authority);
|
|
Packit |
90a5c9 |
ap_assert(req->path);
|
|
Packit |
90a5c9 |
ap_assert(req->method);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
n = 4;
|
|
Packit |
90a5c9 |
apr_table_do(count_header, &n, req->headers, NULL);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
ngh = apr_pcalloc(p, sizeof(h2_proxy_ngheader));
|
|
Packit |
90a5c9 |
ngh->nv = apr_pcalloc(p, n * sizeof(nghttp2_nv));
|
|
Packit |
90a5c9 |
NV_ADD_LIT_CS(ngh, ":scheme", req->scheme);
|
|
Packit |
90a5c9 |
NV_ADD_LIT_CS(ngh, ":authority", req->authority);
|
|
Packit |
90a5c9 |
NV_ADD_LIT_CS(ngh, ":path", req->path);
|
|
Packit |
90a5c9 |
NV_ADD_LIT_CS(ngh, ":method", req->method);
|
|
Packit |
90a5c9 |
apr_table_do(add_table_header, ngh, req->headers, NULL);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return ngh;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/*******************************************************************************
|
|
Packit |
90a5c9 |
* header HTTP/1 <-> HTTP/2 conversions
|
|
Packit |
90a5c9 |
******************************************************************************/
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
typedef struct {
|
|
Packit |
90a5c9 |
const char *name;
|
|
Packit |
90a5c9 |
size_t len;
|
|
Packit |
90a5c9 |
} literal;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#define H2_DEF_LITERAL(n) { (n), (sizeof(n)-1) }
|
|
Packit |
90a5c9 |
#define H2_LIT_ARGS(a) (a),H2_ALEN(a)
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static literal IgnoredRequestHeaders[] = {
|
|
Packit |
90a5c9 |
H2_DEF_LITERAL("upgrade"),
|
|
Packit |
90a5c9 |
H2_DEF_LITERAL("connection"),
|
|
Packit |
90a5c9 |
H2_DEF_LITERAL("keep-alive"),
|
|
Packit |
90a5c9 |
H2_DEF_LITERAL("http2-settings"),
|
|
Packit |
90a5c9 |
H2_DEF_LITERAL("proxy-connection"),
|
|
Packit |
90a5c9 |
H2_DEF_LITERAL("transfer-encoding"),
|
|
Packit |
90a5c9 |
};
|
|
Packit |
90a5c9 |
static literal IgnoredProxyRespHds[] = {
|
|
Packit |
90a5c9 |
H2_DEF_LITERAL("alt-svc"),
|
|
Packit |
90a5c9 |
};
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int ignore_header(const literal *lits, size_t llen,
|
|
Packit |
90a5c9 |
const char *name, size_t nlen)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
const literal *lit;
|
|
Packit |
90a5c9 |
int i;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
for (i = 0; i < llen; ++i) {
|
|
Packit |
90a5c9 |
lit = &lits[i];
|
|
Packit |
90a5c9 |
if (lit->len == nlen && !apr_strnatcasecmp(lit->name, name)) {
|
|
Packit |
90a5c9 |
return 1;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return 0;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int h2_proxy_req_ignore_header(const char *name, size_t len)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return ignore_header(H2_LIT_ARGS(IgnoredRequestHeaders), name, len);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
int h2_proxy_res_ignore_header(const char *name, size_t len)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return (h2_proxy_req_ignore_header(name, len)
|
|
Packit |
90a5c9 |
|| ignore_header(H2_LIT_ARGS(IgnoredProxyRespHds), name, len));
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
void h2_proxy_util_camel_case_header(char *s, size_t len)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
size_t start = 1;
|
|
Packit |
90a5c9 |
size_t i;
|
|
Packit |
90a5c9 |
for (i = 0; i < len; ++i) {
|
|
Packit |
90a5c9 |
if (start) {
|
|
Packit |
90a5c9 |
if (s[i] >= 'a' && s[i] <= 'z') {
|
|
Packit |
90a5c9 |
s[i] -= 'a' - 'A';
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
start = 0;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (s[i] == '-') {
|
|
Packit |
90a5c9 |
start = 1;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/*******************************************************************************
|
|
Packit |
90a5c9 |
* h2 request handling
|
|
Packit |
90a5c9 |
******************************************************************************/
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/** Match a header value against a string constance, case insensitive */
|
|
Packit |
90a5c9 |
#define H2_HD_MATCH_LIT(l, name, nlen) \
|
|
Packit |
90a5c9 |
((nlen == sizeof(l) - 1) && !apr_strnatcasecmp(l, name))
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static apr_status_t h2_headers_add_h1(apr_table_t *headers, apr_pool_t *pool,
|
|
Packit |
90a5c9 |
const char *name, size_t nlen,
|
|
Packit |
90a5c9 |
const char *value, size_t vlen)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
char *hname, *hvalue;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (h2_proxy_req_ignore_header(name, nlen)) {
|
|
Packit |
90a5c9 |
return APR_SUCCESS;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (H2_HD_MATCH_LIT("cookie", name, nlen)) {
|
|
Packit |
90a5c9 |
const char *existing = apr_table_get(headers, "cookie");
|
|
Packit |
90a5c9 |
if (existing) {
|
|
Packit |
90a5c9 |
char *nval;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* Cookie header come separately in HTTP/2, but need
|
|
Packit |
90a5c9 |
* to be merged by "; " (instead of default ", ")
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
hvalue = apr_pstrndup(pool, value, vlen);
|
|
Packit |
90a5c9 |
nval = apr_psprintf(pool, "%s; %s", existing, hvalue);
|
|
Packit |
90a5c9 |
apr_table_setn(headers, "Cookie", nval);
|
|
Packit |
90a5c9 |
return APR_SUCCESS;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (H2_HD_MATCH_LIT("host", name, nlen)) {
|
|
Packit |
90a5c9 |
if (apr_table_get(headers, "Host")) {
|
|
Packit |
90a5c9 |
return APR_SUCCESS; /* ignore duplicate */
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
hname = apr_pstrndup(pool, name, nlen);
|
|
Packit |
90a5c9 |
hvalue = apr_pstrndup(pool, value, vlen);
|
|
Packit |
90a5c9 |
h2_proxy_util_camel_case_header(hname, nlen);
|
|
Packit |
90a5c9 |
apr_table_mergen(headers, hname, hvalue);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return APR_SUCCESS;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static h2_proxy_request *h2_proxy_req_createn(int id, apr_pool_t *pool, const char *method,
|
|
Packit |
90a5c9 |
const char *scheme, const char *authority,
|
|
Packit |
90a5c9 |
const char *path, apr_table_t *header,
|
|
Packit |
90a5c9 |
int serialize)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
h2_proxy_request *req = apr_pcalloc(pool, sizeof(h2_proxy_request));
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
req->method = method;
|
|
Packit |
90a5c9 |
req->scheme = scheme;
|
|
Packit |
90a5c9 |
req->authority = authority;
|
|
Packit |
90a5c9 |
req->path = path;
|
|
Packit |
90a5c9 |
req->headers = header? header : apr_table_make(pool, 10);
|
|
Packit |
90a5c9 |
req->request_time = apr_time_now();
|
|
Packit |
90a5c9 |
req->serialize = serialize;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return req;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
h2_proxy_request *h2_proxy_req_create(int id, apr_pool_t *pool, int serialize)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return h2_proxy_req_createn(id, pool, NULL, NULL, NULL, NULL, NULL, serialize);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
typedef struct {
|
|
Packit |
90a5c9 |
apr_table_t *headers;
|
|
Packit |
90a5c9 |
apr_pool_t *pool;
|
|
Packit |
90a5c9 |
} h1_ctx;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int set_h1_header(void *ctx, const char *key, const char *value)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
h1_ctx *x = ctx;
|
|
Packit |
90a5c9 |
size_t klen = strlen(key);
|
|
Packit |
90a5c9 |
if (!h2_proxy_req_ignore_header(key, klen)) {
|
|
Packit |
90a5c9 |
h2_headers_add_h1(x->headers, x->pool, key, klen, value, strlen(value));
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return 1;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t h2_proxy_req_make(h2_proxy_request *req, apr_pool_t *pool,
|
|
Packit |
90a5c9 |
const char *method, const char *scheme,
|
|
Packit |
90a5c9 |
const char *authority, const char *path,
|
|
Packit |
90a5c9 |
apr_table_t *headers)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
h1_ctx x;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
req->method = method;
|
|
Packit |
90a5c9 |
req->scheme = scheme;
|
|
Packit |
90a5c9 |
req->authority = authority;
|
|
Packit |
90a5c9 |
req->path = path;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
ap_assert(req->scheme);
|
|
Packit |
90a5c9 |
ap_assert(req->authority);
|
|
Packit |
90a5c9 |
ap_assert(req->path);
|
|
Packit |
90a5c9 |
ap_assert(req->method);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
x.pool = pool;
|
|
Packit |
90a5c9 |
x.headers = req->headers;
|
|
Packit |
90a5c9 |
apr_table_do(set_h1_header, &x, headers, NULL);
|
|
Packit |
90a5c9 |
return APR_SUCCESS;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/*******************************************************************************
|
|
Packit |
90a5c9 |
* frame logging
|
|
Packit |
90a5c9 |
******************************************************************************/
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
int h2_proxy_util_frame_print(const nghttp2_frame *frame, char *buffer, size_t maxlen)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
char scratch[128];
|
|
Packit |
90a5c9 |
size_t s_len = sizeof(scratch)/sizeof(scratch[0]);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
switch (frame->hd.type) {
|
|
Packit |
90a5c9 |
case NGHTTP2_DATA: {
|
|
Packit |
90a5c9 |
return apr_snprintf(buffer, maxlen,
|
|
Packit |
90a5c9 |
"DATA[length=%d, flags=%d, stream=%d, padlen=%d]",
|
|
Packit |
90a5c9 |
(int)frame->hd.length, frame->hd.flags,
|
|
Packit |
90a5c9 |
frame->hd.stream_id, (int)frame->data.padlen);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
case NGHTTP2_HEADERS: {
|
|
Packit |
90a5c9 |
return apr_snprintf(buffer, maxlen,
|
|
Packit |
90a5c9 |
"HEADERS[length=%d, hend=%d, stream=%d, eos=%d]",
|
|
Packit |
90a5c9 |
(int)frame->hd.length,
|
|
Packit |
90a5c9 |
!!(frame->hd.flags & NGHTTP2_FLAG_END_HEADERS),
|
|
Packit |
90a5c9 |
frame->hd.stream_id,
|
|
Packit |
90a5c9 |
!!(frame->hd.flags & NGHTTP2_FLAG_END_STREAM));
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
case NGHTTP2_PRIORITY: {
|
|
Packit |
90a5c9 |
return apr_snprintf(buffer, maxlen,
|
|
Packit |
90a5c9 |
"PRIORITY[length=%d, flags=%d, stream=%d]",
|
|
Packit |
90a5c9 |
(int)frame->hd.length,
|
|
Packit |
90a5c9 |
frame->hd.flags, frame->hd.stream_id);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
case NGHTTP2_RST_STREAM: {
|
|
Packit |
90a5c9 |
return apr_snprintf(buffer, maxlen,
|
|
Packit |
90a5c9 |
"RST_STREAM[length=%d, flags=%d, stream=%d]",
|
|
Packit |
90a5c9 |
(int)frame->hd.length,
|
|
Packit |
90a5c9 |
frame->hd.flags, frame->hd.stream_id);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
case NGHTTP2_SETTINGS: {
|
|
Packit |
90a5c9 |
if (frame->hd.flags & NGHTTP2_FLAG_ACK) {
|
|
Packit |
90a5c9 |
return apr_snprintf(buffer, maxlen,
|
|
Packit |
90a5c9 |
"SETTINGS[ack=1, stream=%d]",
|
|
Packit |
90a5c9 |
frame->hd.stream_id);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return apr_snprintf(buffer, maxlen,
|
|
Packit |
90a5c9 |
"SETTINGS[length=%d, stream=%d]",
|
|
Packit |
90a5c9 |
(int)frame->hd.length, frame->hd.stream_id);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
case NGHTTP2_PUSH_PROMISE: {
|
|
Packit |
90a5c9 |
return apr_snprintf(buffer, maxlen,
|
|
Packit |
90a5c9 |
"PUSH_PROMISE[length=%d, hend=%d, stream=%d]",
|
|
Packit |
90a5c9 |
(int)frame->hd.length,
|
|
Packit |
90a5c9 |
!!(frame->hd.flags & NGHTTP2_FLAG_END_HEADERS),
|
|
Packit |
90a5c9 |
frame->hd.stream_id);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
case NGHTTP2_PING: {
|
|
Packit |
90a5c9 |
return apr_snprintf(buffer, maxlen,
|
|
Packit |
90a5c9 |
"PING[length=%d, ack=%d, stream=%d]",
|
|
Packit |
90a5c9 |
(int)frame->hd.length,
|
|
Packit |
90a5c9 |
frame->hd.flags&NGHTTP2_FLAG_ACK,
|
|
Packit |
90a5c9 |
frame->hd.stream_id);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
case NGHTTP2_GOAWAY: {
|
|
Packit |
90a5c9 |
size_t len = (frame->goaway.opaque_data_len < s_len)?
|
|
Packit |
90a5c9 |
frame->goaway.opaque_data_len : s_len-1;
|
|
Packit |
90a5c9 |
memcpy(scratch, frame->goaway.opaque_data, len);
|
|
Packit |
90a5c9 |
scratch[len] = '\0';
|
|
Packit |
90a5c9 |
return apr_snprintf(buffer, maxlen, "GOAWAY[error=%d, reason='%s', "
|
|
Packit |
90a5c9 |
"last_stream=%d]", frame->goaway.error_code,
|
|
Packit |
90a5c9 |
scratch, frame->goaway.last_stream_id);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
case NGHTTP2_WINDOW_UPDATE: {
|
|
Packit |
90a5c9 |
return apr_snprintf(buffer, maxlen,
|
|
Packit |
90a5c9 |
"WINDOW_UPDATE[stream=%d, incr=%d]",
|
|
Packit |
90a5c9 |
frame->hd.stream_id,
|
|
Packit |
90a5c9 |
frame->window_update.window_size_increment);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
default:
|
|
Packit |
90a5c9 |
return apr_snprintf(buffer, maxlen,
|
|
Packit |
90a5c9 |
"type=%d[length=%d, flags=%d, stream=%d]",
|
|
Packit |
90a5c9 |
frame->hd.type, (int)frame->hd.length,
|
|
Packit |
90a5c9 |
frame->hd.flags, frame->hd.stream_id);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/*******************************************************************************
|
|
Packit |
90a5c9 |
* link header handling
|
|
Packit |
90a5c9 |
******************************************************************************/
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
typedef struct {
|
|
Packit |
90a5c9 |
apr_pool_t *pool;
|
|
Packit |
90a5c9 |
request_rec *r;
|
|
Packit |
90a5c9 |
proxy_dir_conf *conf;
|
|
Packit |
90a5c9 |
const char *s;
|
|
Packit |
90a5c9 |
int slen;
|
|
Packit |
90a5c9 |
int i;
|
|
Packit |
90a5c9 |
const char *server_uri;
|
|
Packit |
90a5c9 |
int su_len;
|
|
Packit |
90a5c9 |
const char *real_backend_uri;
|
|
Packit |
90a5c9 |
int rbu_len;
|
|
Packit |
90a5c9 |
const char *p_server_uri;
|
|
Packit |
90a5c9 |
int psu_len;
|
|
Packit |
90a5c9 |
int link_start;
|
|
Packit |
90a5c9 |
int link_end;
|
|
Packit |
90a5c9 |
} link_ctx;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int attr_char(char c)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
switch (c) {
|
|
Packit |
90a5c9 |
case '!':
|
|
Packit |
90a5c9 |
case '#':
|
|
Packit |
90a5c9 |
case '$':
|
|
Packit |
90a5c9 |
case '&':
|
|
Packit |
90a5c9 |
case '+':
|
|
Packit |
90a5c9 |
case '-':
|
|
Packit |
90a5c9 |
case '.':
|
|
Packit |
90a5c9 |
case '^':
|
|
Packit |
90a5c9 |
case '_':
|
|
Packit |
90a5c9 |
case '`':
|
|
Packit |
90a5c9 |
case '|':
|
|
Packit |
90a5c9 |
case '~':
|
|
Packit |
90a5c9 |
return 1;
|
|
Packit |
90a5c9 |
default:
|
|
Packit |
90a5c9 |
return apr_isalnum(c);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int ptoken_char(char c)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
switch (c) {
|
|
Packit |
90a5c9 |
case '!':
|
|
Packit |
90a5c9 |
case '#':
|
|
Packit |
90a5c9 |
case '$':
|
|
Packit |
90a5c9 |
case '&':
|
|
Packit |
90a5c9 |
case '\'':
|
|
Packit |
90a5c9 |
case '(':
|
|
Packit |
90a5c9 |
case ')':
|
|
Packit |
90a5c9 |
case '*':
|
|
Packit |
90a5c9 |
case '+':
|
|
Packit |
90a5c9 |
case '-':
|
|
Packit |
90a5c9 |
case '.':
|
|
Packit |
90a5c9 |
case '/':
|
|
Packit |
90a5c9 |
case ':':
|
|
Packit |
90a5c9 |
case '<':
|
|
Packit |
90a5c9 |
case '=':
|
|
Packit |
90a5c9 |
case '>':
|
|
Packit |
90a5c9 |
case '?':
|
|
Packit |
90a5c9 |
case '@':
|
|
Packit |
90a5c9 |
case '[':
|
|
Packit |
90a5c9 |
case ']':
|
|
Packit |
90a5c9 |
case '^':
|
|
Packit |
90a5c9 |
case '_':
|
|
Packit |
90a5c9 |
case '`':
|
|
Packit |
90a5c9 |
case '{':
|
|
Packit |
90a5c9 |
case '|':
|
|
Packit |
90a5c9 |
case '}':
|
|
Packit |
90a5c9 |
case '~':
|
|
Packit |
90a5c9 |
return 1;
|
|
Packit |
90a5c9 |
default:
|
|
Packit |
90a5c9 |
return apr_isalnum(c);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int skip_ws(link_ctx *ctx)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
char c;
|
|
Packit |
90a5c9 |
while (ctx->i < ctx->slen
|
|
Packit |
90a5c9 |
&& (((c = ctx->s[ctx->i]) == ' ') || (c == '\t'))) {
|
|
Packit |
90a5c9 |
++ctx->i;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return (ctx->i < ctx->slen);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int find_chr(link_ctx *ctx, char c, int *pidx)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
int j;
|
|
Packit |
90a5c9 |
for (j = ctx->i; j < ctx->slen; ++j) {
|
|
Packit |
90a5c9 |
if (ctx->s[j] == c) {
|
|
Packit |
90a5c9 |
*pidx = j;
|
|
Packit |
90a5c9 |
return 1;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return 0;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int read_chr(link_ctx *ctx, char c)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
if (ctx->i < ctx->slen && ctx->s[ctx->i] == c) {
|
|
Packit |
90a5c9 |
++ctx->i;
|
|
Packit |
90a5c9 |
return 1;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return 0;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int skip_qstring(link_ctx *ctx)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
if (skip_ws(ctx) && read_chr(ctx, '\"')) {
|
|
Packit |
90a5c9 |
int end;
|
|
Packit |
90a5c9 |
if (find_chr(ctx, '\"', &end)) {
|
|
Packit |
90a5c9 |
ctx->i = end + 1;
|
|
Packit |
90a5c9 |
return 1;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return 0;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int skip_ptoken(link_ctx *ctx)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
if (skip_ws(ctx)) {
|
|
Packit |
90a5c9 |
int i;
|
|
Packit |
90a5c9 |
for (i = ctx->i; i < ctx->slen && ptoken_char(ctx->s[i]); ++i) {
|
|
Packit |
90a5c9 |
/* nop */
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (i > ctx->i) {
|
|
Packit |
90a5c9 |
ctx->i = i;
|
|
Packit |
90a5c9 |
return 1;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return 0;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int read_link(link_ctx *ctx)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
ctx->link_start = ctx->link_end = 0;
|
|
Packit |
90a5c9 |
if (skip_ws(ctx) && read_chr(ctx, '<')) {
|
|
Packit |
90a5c9 |
int end;
|
|
Packit |
90a5c9 |
if (find_chr(ctx, '>', &end)) {
|
|
Packit |
90a5c9 |
ctx->link_start = ctx->i;
|
|
Packit |
90a5c9 |
ctx->link_end = end;
|
|
Packit |
90a5c9 |
ctx->i = end + 1;
|
|
Packit |
90a5c9 |
return 1;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return 0;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int skip_pname(link_ctx *ctx)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
if (skip_ws(ctx)) {
|
|
Packit |
90a5c9 |
int i;
|
|
Packit |
90a5c9 |
for (i = ctx->i; i < ctx->slen && attr_char(ctx->s[i]); ++i) {
|
|
Packit |
90a5c9 |
/* nop */
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (i > ctx->i) {
|
|
Packit |
90a5c9 |
ctx->i = i;
|
|
Packit |
90a5c9 |
return 1;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return 0;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int skip_pvalue(link_ctx *ctx)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
if (skip_ws(ctx) && read_chr(ctx, '=')) {
|
|
Packit |
90a5c9 |
if (skip_qstring(ctx) || skip_ptoken(ctx)) {
|
|
Packit |
90a5c9 |
return 1;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return 0;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int skip_param(link_ctx *ctx)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
if (skip_ws(ctx) && read_chr(ctx, ';')) {
|
|
Packit |
90a5c9 |
if (skip_pname(ctx)) {
|
|
Packit |
90a5c9 |
skip_pvalue(ctx); /* value is optional */
|
|
Packit |
90a5c9 |
return 1;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return 0;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int read_sep(link_ctx *ctx)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
if (skip_ws(ctx) && read_chr(ctx, ',')) {
|
|
Packit |
90a5c9 |
return 1;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return 0;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static size_t subst_str(link_ctx *ctx, int start, int end, const char *ns)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
int olen, nlen, plen;
|
|
Packit |
90a5c9 |
int delta;
|
|
Packit |
90a5c9 |
char *p;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
olen = end - start;
|
|
Packit |
90a5c9 |
nlen = (int)strlen(ns);
|
|
Packit |
90a5c9 |
delta = nlen - olen;
|
|
Packit |
90a5c9 |
plen = ctx->slen + delta + 1;
|
|
Packit |
90a5c9 |
p = apr_pcalloc(ctx->pool, plen);
|
|
Packit |
90a5c9 |
memcpy(p, ctx->s, start);
|
|
Packit |
90a5c9 |
memcpy(p + start, ns, nlen);
|
|
Packit |
90a5c9 |
strcpy(p + start + nlen, ctx->s + end);
|
|
Packit |
90a5c9 |
ctx->s = p;
|
|
Packit |
90a5c9 |
ctx->slen = (int)strlen(p);
|
|
Packit |
90a5c9 |
if (ctx->i >= end) {
|
|
Packit |
90a5c9 |
ctx->i += delta;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return nlen;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static void map_link(link_ctx *ctx)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
if (ctx->link_start < ctx->link_end) {
|
|
Packit |
90a5c9 |
char buffer[HUGE_STRING_LEN];
|
|
Packit |
90a5c9 |
int need_len, link_len, buffer_len, prepend_p_server;
|
|
Packit |
90a5c9 |
const char *mapped;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
buffer[0] = '\0';
|
|
Packit |
90a5c9 |
buffer_len = 0;
|
|
Packit |
90a5c9 |
link_len = ctx->link_end - ctx->link_start;
|
|
Packit |
90a5c9 |
need_len = link_len + 1;
|
|
Packit |
90a5c9 |
prepend_p_server = (ctx->s[ctx->link_start] == '/');
|
|
Packit |
90a5c9 |
if (prepend_p_server) {
|
|
Packit |
90a5c9 |
/* common to use relative uris in link header, for mappings
|
|
Packit |
90a5c9 |
* to work need to prefix the backend server uri */
|
|
Packit |
90a5c9 |
need_len += ctx->psu_len;
|
|
Packit |
90a5c9 |
apr_cpystrn(buffer, ctx->p_server_uri, sizeof(buffer));
|
|
Packit |
90a5c9 |
buffer_len = ctx->psu_len;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (need_len > sizeof(buffer)) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, ctx->r, APLOGNO(03482)
|
|
Packit |
90a5c9 |
"link_reverse_map uri too long, skipped: %s", ctx->s);
|
|
Packit |
90a5c9 |
return;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
apr_cpystrn(buffer + buffer_len, ctx->s + ctx->link_start, link_len + 1);
|
|
Packit |
90a5c9 |
if (!prepend_p_server
|
|
Packit |
90a5c9 |
&& strcmp(ctx->real_backend_uri, ctx->p_server_uri)
|
|
Packit |
90a5c9 |
&& !strncmp(buffer, ctx->real_backend_uri, ctx->rbu_len)) {
|
|
Packit |
90a5c9 |
/* the server uri and our local proxy uri we use differ, for mapping
|
|
Packit |
90a5c9 |
* to work, we need to use the proxy uri */
|
|
Packit |
90a5c9 |
int path_start = ctx->link_start + ctx->rbu_len;
|
|
Packit |
90a5c9 |
link_len -= ctx->rbu_len;
|
|
Packit |
90a5c9 |
memcpy(buffer, ctx->p_server_uri, ctx->psu_len);
|
|
Packit |
90a5c9 |
memcpy(buffer + ctx->psu_len, ctx->s + path_start, link_len);
|
|
Packit |
90a5c9 |
buffer_len = ctx->psu_len + link_len;
|
|
Packit |
90a5c9 |
buffer[buffer_len] = '\0';
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
mapped = ap_proxy_location_reverse_map(ctx->r, ctx->conf, buffer);
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, ctx->r,
|
|
Packit |
90a5c9 |
"reverse_map[%s] %s --> %s", ctx->p_server_uri, buffer, mapped);
|
|
Packit |
90a5c9 |
if (mapped != buffer) {
|
|
Packit |
90a5c9 |
if (prepend_p_server) {
|
|
Packit |
90a5c9 |
if (ctx->server_uri == NULL) {
|
|
Packit |
90a5c9 |
ctx->server_uri = ap_construct_url(ctx->pool, "", ctx->r);
|
|
Packit |
90a5c9 |
ctx->su_len = (int)strlen(ctx->server_uri);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (!strncmp(mapped, ctx->server_uri, ctx->su_len)) {
|
|
Packit |
90a5c9 |
mapped += ctx->su_len;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
subst_str(ctx, ctx->link_start, ctx->link_end, mapped);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* RFC 5988 <https://tools.ietf.org/html/rfc5988#section-6.2.1>
|
|
Packit |
90a5c9 |
Link = "Link" ":" #link-value
|
|
Packit |
90a5c9 |
link-value = "<" URI-Reference ">" *( ";" link-param )
|
|
Packit |
90a5c9 |
link-param = ( ( "rel" "=" relation-types )
|
|
Packit |
90a5c9 |
| ( "anchor" "=" <"> URI-Reference <"> )
|
|
Packit |
90a5c9 |
| ( "rev" "=" relation-types )
|
|
Packit |
90a5c9 |
| ( "hreflang" "=" Language-Tag )
|
|
Packit |
90a5c9 |
| ( "media" "=" ( MediaDesc | ( <"> MediaDesc <"> ) ) )
|
|
Packit |
90a5c9 |
| ( "title" "=" quoted-string )
|
|
Packit |
90a5c9 |
| ( "title*" "=" ext-value )
|
|
Packit |
90a5c9 |
| ( "type" "=" ( media-type | quoted-mt ) )
|
|
Packit |
90a5c9 |
| ( link-extension ) )
|
|
Packit |
90a5c9 |
link-extension = ( parmname [ "=" ( ptoken | quoted-string ) ] )
|
|
Packit |
90a5c9 |
| ( ext-name-star "=" ext-value )
|
|
Packit |
90a5c9 |
ext-name-star = parmname "*" ; reserved for RFC2231-profiled
|
|
Packit |
90a5c9 |
; extensions. Whitespace NOT
|
|
Packit |
90a5c9 |
; allowed in between.
|
|
Packit |
90a5c9 |
ptoken = 1*ptokenchar
|
|
Packit |
90a5c9 |
ptokenchar = "!" | "#" | "$" | "%" | "&" | "'" | "("
|
|
Packit |
90a5c9 |
| ")" | "*" | "+" | "-" | "." | "/" | DIGIT
|
|
Packit |
90a5c9 |
| ":" | "<" | "=" | ">" | "?" | "@" | ALPHA
|
|
Packit |
90a5c9 |
| "[" | "]" | "^" | "_" | "`" | "{" | "|"
|
|
Packit |
90a5c9 |
| "}" | "~"
|
|
Packit |
90a5c9 |
media-type = type-name "/" subtype-name
|
|
Packit |
90a5c9 |
quoted-mt = <"> media-type <">
|
|
Packit |
90a5c9 |
relation-types = relation-type
|
|
Packit |
90a5c9 |
| <"> relation-type *( 1*SP relation-type ) <">
|
|
Packit |
90a5c9 |
relation-type = reg-rel-type | ext-rel-type
|
|
Packit |
90a5c9 |
reg-rel-type = LOALPHA *( LOALPHA | DIGIT | "." | "-" )
|
|
Packit |
90a5c9 |
ext-rel-type = URI
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
and from <https://tools.ietf.org/html/rfc5987>
|
|
Packit |
90a5c9 |
parmname = 1*attr-char
|
|
Packit |
90a5c9 |
attr-char = ALPHA / DIGIT
|
|
Packit |
90a5c9 |
/ "!" / "#" / "$" / "&" / "+" / "-" / "."
|
|
Packit |
90a5c9 |
/ "^" / "_" / "`" / "|" / "~"
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
const char *h2_proxy_link_reverse_map(request_rec *r,
|
|
Packit |
90a5c9 |
proxy_dir_conf *conf,
|
|
Packit |
90a5c9 |
const char *real_backend_uri,
|
|
Packit |
90a5c9 |
const char *proxy_server_uri,
|
|
Packit |
90a5c9 |
const char *s)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
link_ctx ctx;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (r->proxyreq != PROXYREQ_REVERSE) {
|
|
Packit |
90a5c9 |
return s;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
memset(&ctx, 0, sizeof(ctx));
|
|
Packit |
90a5c9 |
ctx.r = r;
|
|
Packit |
90a5c9 |
ctx.pool = r->pool;
|
|
Packit |
90a5c9 |
ctx.conf = conf;
|
|
Packit |
90a5c9 |
ctx.real_backend_uri = real_backend_uri;
|
|
Packit |
90a5c9 |
ctx.rbu_len = (int)strlen(ctx.real_backend_uri);
|
|
Packit |
90a5c9 |
ctx.p_server_uri = proxy_server_uri;
|
|
Packit |
90a5c9 |
ctx.psu_len = (int)strlen(ctx.p_server_uri);
|
|
Packit |
90a5c9 |
ctx.s = s;
|
|
Packit |
90a5c9 |
ctx.slen = (int)strlen(s);
|
|
Packit |
90a5c9 |
while (read_link(&ctx)) {
|
|
Packit |
90a5c9 |
while (skip_param(&ctx)) {
|
|
Packit |
90a5c9 |
/* nop */
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
map_link(&ctx;;
|
|
Packit |
90a5c9 |
if (!read_sep(&ctx)) {
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
|
|
Packit |
90a5c9 |
"link_reverse_map %s --> %s", s, ctx.s);
|
|
Packit |
90a5c9 |
return ctx.s;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/*******************************************************************************
|
|
Packit |
90a5c9 |
* FIFO queue
|
|
Packit |
90a5c9 |
******************************************************************************/
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
struct h2_proxy_fifo {
|
|
Packit |
90a5c9 |
void **elems;
|
|
Packit |
90a5c9 |
int nelems;
|
|
Packit |
90a5c9 |
int set;
|
|
Packit |
90a5c9 |
int head;
|
|
Packit |
90a5c9 |
int count;
|
|
Packit |
90a5c9 |
int aborted;
|
|
Packit |
90a5c9 |
apr_thread_mutex_t *lock;
|
|
Packit |
90a5c9 |
apr_thread_cond_t *not_empty;
|
|
Packit |
90a5c9 |
apr_thread_cond_t *not_full;
|
|
Packit |
90a5c9 |
};
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int nth_index(h2_proxy_fifo *fifo, int n)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return (fifo->head + n) % fifo->nelems;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static apr_status_t fifo_destroy(void *data)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
h2_proxy_fifo *fifo = data;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_thread_cond_destroy(fifo->not_empty);
|
|
Packit |
90a5c9 |
apr_thread_cond_destroy(fifo->not_full);
|
|
Packit |
90a5c9 |
apr_thread_mutex_destroy(fifo->lock);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return APR_SUCCESS;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int index_of(h2_proxy_fifo *fifo, void *elem)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
int i;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
for (i = 0; i < fifo->count; ++i) {
|
|
Packit |
90a5c9 |
if (elem == fifo->elems[nth_index(fifo, i)]) {
|
|
Packit |
90a5c9 |
return i;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return -1;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static apr_status_t create_int(h2_proxy_fifo **pfifo, apr_pool_t *pool,
|
|
Packit |
90a5c9 |
int capacity, int as_set)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_status_t rv;
|
|
Packit |
90a5c9 |
h2_proxy_fifo *fifo;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
fifo = apr_pcalloc(pool, sizeof(*fifo));
|
|
Packit |
90a5c9 |
if (fifo == NULL) {
|
|
Packit |
90a5c9 |
return APR_ENOMEM;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
rv = apr_thread_mutex_create(&fifo->lock,
|
|
Packit |
90a5c9 |
APR_THREAD_MUTEX_UNNESTED, pool);
|
|
Packit |
90a5c9 |
if (rv != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
return rv;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
rv = apr_thread_cond_create(&fifo->not_empty, pool);
|
|
Packit |
90a5c9 |
if (rv != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
return rv;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
rv = apr_thread_cond_create(&fifo->not_full, pool);
|
|
Packit |
90a5c9 |
if (rv != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
return rv;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
fifo->elems = apr_pcalloc(pool, capacity * sizeof(void*));
|
|
Packit |
90a5c9 |
if (fifo->elems == NULL) {
|
|
Packit |
90a5c9 |
return APR_ENOMEM;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
fifo->nelems = capacity;
|
|
Packit |
90a5c9 |
fifo->set = as_set;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
*pfifo = fifo;
|
|
Packit |
90a5c9 |
apr_pool_cleanup_register(pool, fifo, fifo_destroy, apr_pool_cleanup_null);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return APR_SUCCESS;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t h2_proxy_fifo_create(h2_proxy_fifo **pfifo, apr_pool_t *pool, int capacity)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return create_int(pfifo, pool, capacity, 0);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t h2_proxy_fifo_set_create(h2_proxy_fifo **pfifo, apr_pool_t *pool, int capacity)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return create_int(pfifo, pool, capacity, 1);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t h2_proxy_fifo_term(h2_proxy_fifo *fifo)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_status_t rv;
|
|
Packit |
90a5c9 |
if ((rv = apr_thread_mutex_lock(fifo->lock)) == APR_SUCCESS) {
|
|
Packit |
90a5c9 |
fifo->aborted = 1;
|
|
Packit |
90a5c9 |
apr_thread_mutex_unlock(fifo->lock);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return rv;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t h2_proxy_fifo_interrupt(h2_proxy_fifo *fifo)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_status_t rv;
|
|
Packit |
90a5c9 |
if ((rv = apr_thread_mutex_lock(fifo->lock)) == APR_SUCCESS) {
|
|
Packit |
90a5c9 |
apr_thread_cond_broadcast(fifo->not_empty);
|
|
Packit |
90a5c9 |
apr_thread_cond_broadcast(fifo->not_full);
|
|
Packit |
90a5c9 |
apr_thread_mutex_unlock(fifo->lock);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return rv;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
int h2_proxy_fifo_count(h2_proxy_fifo *fifo)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return fifo->count;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
int h2_proxy_fifo_capacity(h2_proxy_fifo *fifo)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return fifo->nelems;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static apr_status_t check_not_empty(h2_proxy_fifo *fifo, int block)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
if (fifo->count == 0) {
|
|
Packit |
90a5c9 |
if (!block) {
|
|
Packit |
90a5c9 |
return APR_EAGAIN;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
while (fifo->count == 0) {
|
|
Packit |
90a5c9 |
if (fifo->aborted) {
|
|
Packit |
90a5c9 |
return APR_EOF;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
apr_thread_cond_wait(fifo->not_empty, fifo->lock);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return APR_SUCCESS;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static apr_status_t fifo_push(h2_proxy_fifo *fifo, void *elem, int block)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_status_t rv;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (fifo->aborted) {
|
|
Packit |
90a5c9 |
return APR_EOF;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if ((rv = apr_thread_mutex_lock(fifo->lock)) == APR_SUCCESS) {
|
|
Packit |
90a5c9 |
if (fifo->set && index_of(fifo, elem) >= 0) {
|
|
Packit |
90a5c9 |
/* set mode, elem already member */
|
|
Packit |
90a5c9 |
apr_thread_mutex_unlock(fifo->lock);
|
|
Packit |
90a5c9 |
return APR_EEXIST;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (fifo->count == fifo->nelems) {
|
|
Packit |
90a5c9 |
if (block) {
|
|
Packit |
90a5c9 |
while (fifo->count == fifo->nelems) {
|
|
Packit |
90a5c9 |
if (fifo->aborted) {
|
|
Packit |
90a5c9 |
apr_thread_mutex_unlock(fifo->lock);
|
|
Packit |
90a5c9 |
return APR_EOF;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
apr_thread_cond_wait(fifo->not_full, fifo->lock);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
apr_thread_mutex_unlock(fifo->lock);
|
|
Packit |
90a5c9 |
return APR_EAGAIN;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
ap_assert(fifo->count < fifo->nelems);
|
|
Packit |
90a5c9 |
fifo->elems[nth_index(fifo, fifo->count)] = elem;
|
|
Packit |
90a5c9 |
++fifo->count;
|
|
Packit |
90a5c9 |
if (fifo->count == 1) {
|
|
Packit |
90a5c9 |
apr_thread_cond_broadcast(fifo->not_empty);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
apr_thread_mutex_unlock(fifo->lock);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return rv;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t h2_proxy_fifo_push(h2_proxy_fifo *fifo, void *elem)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return fifo_push(fifo, elem, 1);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t h2_proxy_fifo_try_push(h2_proxy_fifo *fifo, void *elem)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return fifo_push(fifo, elem, 0);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static void *pull_head(h2_proxy_fifo *fifo)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
void *elem;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
ap_assert(fifo->count > 0);
|
|
Packit |
90a5c9 |
elem = fifo->elems[fifo->head];
|
|
Packit |
90a5c9 |
--fifo->count;
|
|
Packit |
90a5c9 |
if (fifo->count > 0) {
|
|
Packit |
90a5c9 |
fifo->head = nth_index(fifo, 1);
|
|
Packit |
90a5c9 |
if (fifo->count+1 == fifo->nelems) {
|
|
Packit |
90a5c9 |
apr_thread_cond_broadcast(fifo->not_full);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return elem;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static apr_status_t fifo_pull(h2_proxy_fifo *fifo, void **pelem, int block)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_status_t rv;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (fifo->aborted) {
|
|
Packit |
90a5c9 |
return APR_EOF;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if ((rv = apr_thread_mutex_lock(fifo->lock)) == APR_SUCCESS) {
|
|
Packit |
90a5c9 |
if ((rv = check_not_empty(fifo, block)) != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
apr_thread_mutex_unlock(fifo->lock);
|
|
Packit |
90a5c9 |
*pelem = NULL;
|
|
Packit |
90a5c9 |
return rv;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
ap_assert(fifo->count > 0);
|
|
Packit |
90a5c9 |
*pelem = pull_head(fifo);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_thread_mutex_unlock(fifo->lock);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return rv;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t h2_proxy_fifo_pull(h2_proxy_fifo *fifo, void **pelem)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return fifo_pull(fifo, pelem, 1);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t h2_proxy_fifo_try_pull(h2_proxy_fifo *fifo, void **pelem)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return fifo_pull(fifo, pelem, 0);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t h2_proxy_fifo_remove(h2_proxy_fifo *fifo, void *elem)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_status_t rv;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (fifo->aborted) {
|
|
Packit |
90a5c9 |
return APR_EOF;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if ((rv = apr_thread_mutex_lock(fifo->lock)) == APR_SUCCESS) {
|
|
Packit |
90a5c9 |
int i, rc;
|
|
Packit |
90a5c9 |
void *e;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
rc = 0;
|
|
Packit |
90a5c9 |
for (i = 0; i < fifo->count; ++i) {
|
|
Packit |
90a5c9 |
e = fifo->elems[nth_index(fifo, i)];
|
|
Packit |
90a5c9 |
if (e == elem) {
|
|
Packit |
90a5c9 |
++rc;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (rc) {
|
|
Packit |
90a5c9 |
fifo->elems[nth_index(fifo, i-rc)] = e;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (rc) {
|
|
Packit |
90a5c9 |
fifo->count -= rc;
|
|
Packit |
90a5c9 |
if (fifo->count + rc == fifo->nelems) {
|
|
Packit |
90a5c9 |
apr_thread_cond_broadcast(fifo->not_full);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
rv = APR_SUCCESS;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
rv = APR_EAGAIN;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_thread_mutex_unlock(fifo->lock);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return rv;
|
|
Packit |
90a5c9 |
}
|