|
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_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 |
|
|
Packit |
90a5c9 |
#include <nghttp2/nghttp2.h>
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#include "h2.h"
|
|
Packit |
90a5c9 |
#include "h2_util.h"
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* h2_log2(n) iff n is a power of 2 */
|
|
Packit |
90a5c9 |
unsigned char h2_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 |
size_t h2_util_hex_dump(char *buffer, size_t maxlen,
|
|
Packit |
90a5c9 |
const char *data, size_t datalen)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
size_t offset = 0;
|
|
Packit |
90a5c9 |
size_t maxoffset = (maxlen-4);
|
|
Packit |
90a5c9 |
size_t i;
|
|
Packit |
90a5c9 |
for (i = 0; i < datalen && offset < maxoffset; ++i) {
|
|
Packit |
90a5c9 |
const char *sep = (i && i % 16 == 0)? "\n" : " ";
|
|
Packit |
90a5c9 |
int n = apr_snprintf(buffer+offset, maxoffset-offset,
|
|
Packit |
90a5c9 |
"%2x%s", ((unsigned int)data[i]&0xff), sep);
|
|
Packit |
90a5c9 |
offset += n;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
strcpy(buffer+offset, (i
|
|
Packit |
90a5c9 |
return strlen(buffer);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
size_t h2_util_header_print(char *buffer, size_t maxlen,
|
|
Packit |
90a5c9 |
const char *name, size_t namelen,
|
|
Packit |
90a5c9 |
const char *value, size_t valuelen)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
size_t offset = 0;
|
|
Packit |
90a5c9 |
size_t i;
|
|
Packit |
90a5c9 |
for (i = 0; i < namelen && offset < maxlen; ++i, ++offset) {
|
|
Packit |
90a5c9 |
buffer[offset] = name[i];
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
for (i = 0; i < 2 && offset < maxlen; ++i, ++offset) {
|
|
Packit |
90a5c9 |
buffer[offset] = ": "[i];
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
for (i = 0; i < valuelen && offset < maxlen; ++i, ++offset) {
|
|
Packit |
90a5c9 |
buffer[offset] = value[i];
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
buffer[offset] = '\0';
|
|
Packit |
90a5c9 |
return offset;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
void h2_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 |
/* base64 url encoding ****************************************************************************/
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#define N6 (unsigned int)-1
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static const unsigned int BASE64URL_UINT6[] = {
|
|
Packit |
90a5c9 |
/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
|
|
Packit |
90a5c9 |
N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, /* 0 */
|
|
Packit |
90a5c9 |
N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, /* 1 */
|
|
Packit |
90a5c9 |
N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, 62, N6, N6, /* 2 */
|
|
Packit |
90a5c9 |
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, N6, N6, N6, N6, N6, N6, /* 3 */
|
|
Packit |
90a5c9 |
N6, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 4 */
|
|
Packit |
90a5c9 |
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, N6, N6, N6, N6, 63, /* 5 */
|
|
Packit |
90a5c9 |
N6, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 6 */
|
|
Packit |
90a5c9 |
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, N6, N6, N6, N6, N6, /* 7 */
|
|
Packit |
90a5c9 |
N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, /* 8 */
|
|
Packit |
90a5c9 |
N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, /* 9 */
|
|
Packit |
90a5c9 |
N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, /* a */
|
|
Packit |
90a5c9 |
N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, /* b */
|
|
Packit |
90a5c9 |
N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, /* c */
|
|
Packit |
90a5c9 |
N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, /* d */
|
|
Packit |
90a5c9 |
N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, /* e */
|
|
Packit |
90a5c9 |
N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6 /* f */
|
|
Packit |
90a5c9 |
};
|
|
Packit |
90a5c9 |
static const unsigned char BASE64URL_CHARS[] = {
|
|
Packit |
90a5c9 |
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', /* 0 - 9 */
|
|
Packit |
90a5c9 |
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', /* 10 - 19 */
|
|
Packit |
90a5c9 |
'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', /* 20 - 29 */
|
|
Packit |
90a5c9 |
'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', /* 30 - 39 */
|
|
Packit |
90a5c9 |
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', /* 40 - 49 */
|
|
Packit |
90a5c9 |
'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', /* 50 - 59 */
|
|
Packit |
90a5c9 |
'8', '9', '-', '_', ' ', ' ', ' ', ' ', ' ', ' ', /* 60 - 69 */
|
|
Packit |
90a5c9 |
};
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#define BASE64URL_CHAR(x) BASE64URL_CHARS[ (unsigned int)(x) & 0x3fu ]
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_size_t h2_util_base64url_decode(const char **decoded, const char *encoded,
|
|
Packit |
90a5c9 |
apr_pool_t *pool)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
const unsigned char *e = (const unsigned char *)encoded;
|
|
Packit |
90a5c9 |
const unsigned char *p = e;
|
|
Packit |
90a5c9 |
unsigned char *d;
|
|
Packit |
90a5c9 |
unsigned int n;
|
|
Packit |
90a5c9 |
long len, mlen, remain, i;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
while (*p && BASE64URL_UINT6[ *p ] != N6) {
|
|
Packit |
90a5c9 |
++p;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
len = (int)(p - e);
|
|
Packit |
90a5c9 |
mlen = (len/4)*4;
|
|
Packit |
90a5c9 |
*decoded = apr_pcalloc(pool, (apr_size_t)len + 1);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
i = 0;
|
|
Packit |
90a5c9 |
d = (unsigned char*)*decoded;
|
|
Packit |
90a5c9 |
for (; i < mlen; i += 4) {
|
|
Packit |
90a5c9 |
n = ((BASE64URL_UINT6[ e[i+0] ] << 18) +
|
|
Packit |
90a5c9 |
(BASE64URL_UINT6[ e[i+1] ] << 12) +
|
|
Packit |
90a5c9 |
(BASE64URL_UINT6[ e[i+2] ] << 6) +
|
|
Packit |
90a5c9 |
(BASE64URL_UINT6[ e[i+3] ]));
|
|
Packit |
90a5c9 |
*d++ = (unsigned char)(n >> 16);
|
|
Packit |
90a5c9 |
*d++ = (unsigned char)(n >> 8 & 0xffu);
|
|
Packit |
90a5c9 |
*d++ = (unsigned char)(n & 0xffu);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
remain = len - mlen;
|
|
Packit |
90a5c9 |
switch (remain) {
|
|
Packit |
90a5c9 |
case 2:
|
|
Packit |
90a5c9 |
n = ((BASE64URL_UINT6[ e[mlen+0] ] << 18) +
|
|
Packit |
90a5c9 |
(BASE64URL_UINT6[ e[mlen+1] ] << 12));
|
|
Packit |
90a5c9 |
*d++ = (unsigned char)(n >> 16);
|
|
Packit |
90a5c9 |
remain = 1;
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
case 3:
|
|
Packit |
90a5c9 |
n = ((BASE64URL_UINT6[ e[mlen+0] ] << 18) +
|
|
Packit |
90a5c9 |
(BASE64URL_UINT6[ e[mlen+1] ] << 12) +
|
|
Packit |
90a5c9 |
(BASE64URL_UINT6[ e[mlen+2] ] << 6));
|
|
Packit |
90a5c9 |
*d++ = (unsigned char)(n >> 16);
|
|
Packit |
90a5c9 |
*d++ = (unsigned char)(n >> 8 & 0xffu);
|
|
Packit |
90a5c9 |
remain = 2;
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
default: /* do nothing */
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return (apr_size_t)(mlen/4*3 + remain);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
const char *h2_util_base64url_encode(const char *data,
|
|
Packit |
90a5c9 |
apr_size_t dlen, apr_pool_t *pool)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
int i, len = (int)dlen;
|
|
Packit |
90a5c9 |
apr_size_t slen = ((dlen+2)/3)*4 + 1; /* 0 terminated */
|
|
Packit |
90a5c9 |
const unsigned char *udata = (const unsigned char*)data;
|
|
Packit |
90a5c9 |
unsigned char *enc, *p = apr_pcalloc(pool, slen);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
enc = p;
|
|
Packit |
90a5c9 |
for (i = 0; i < len-2; i+= 3) {
|
|
Packit |
90a5c9 |
*p++ = BASE64URL_CHAR( (udata[i] >> 2) );
|
|
Packit |
90a5c9 |
*p++ = BASE64URL_CHAR( (udata[i] << 4) + (udata[i+1] >> 4) );
|
|
Packit |
90a5c9 |
*p++ = BASE64URL_CHAR( (udata[i+1] << 2) + (udata[i+2] >> 6) );
|
|
Packit |
90a5c9 |
*p++ = BASE64URL_CHAR( (udata[i+2]) );
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (i < len) {
|
|
Packit |
90a5c9 |
*p++ = BASE64URL_CHAR( (udata[i] >> 2) );
|
|
Packit |
90a5c9 |
if (i == (len - 1)) {
|
|
Packit |
90a5c9 |
*p++ = BASE64URL_CHARS[ ((unsigned int)udata[i] << 4) & 0x3fu ];
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
*p++ = BASE64URL_CHAR( (udata[i] << 4) + (udata[i+1] >> 4) );
|
|
Packit |
90a5c9 |
*p++ = BASE64URL_CHAR( (udata[i+1] << 2) );
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
*p++ = '\0';
|
|
Packit |
90a5c9 |
return (char *)enc;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/*******************************************************************************
|
|
Packit |
90a5c9 |
* ihash - hash for structs with int identifier
|
|
Packit |
90a5c9 |
******************************************************************************/
|
|
Packit |
90a5c9 |
struct h2_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_ihash_t *h2_ihash_create(apr_pool_t *pool, size_t offset_of_int)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
h2_ihash_t *ih = apr_pcalloc(pool, sizeof(h2_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_ihash_count(h2_ihash_t *ih)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return apr_hash_count(ih->hash);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
int h2_ihash_empty(h2_ihash_t *ih)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return apr_hash_count(ih->hash) == 0;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
void *h2_ihash_get(h2_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_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_ihash_iter(h2_ihash_t *ih, h2_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_ihash_add(h2_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_ihash_remove(h2_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_ihash_remove_val(h2_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_ihash_clear(h2_ihash_t *ih)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_hash_clear(ih->hash);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
typedef struct {
|
|
Packit |
90a5c9 |
h2_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_ihash_shift(h2_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_ihash_iter(ih, collect_iter, &ctx;;
|
|
Packit |
90a5c9 |
for (i = 0; i < ctx.len; ++i) {
|
|
Packit |
90a5c9 |
h2_ihash_remove_val(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_iqueue *q, int nlen);
|
|
Packit |
90a5c9 |
static void iq_swap(h2_iqueue *q, int i, int j);
|
|
Packit |
90a5c9 |
static int iq_bubble_up(h2_iqueue *q, int i, int top,
|
|
Packit |
90a5c9 |
h2_iq_cmp *cmp, void *ctx);
|
|
Packit |
90a5c9 |
static int iq_bubble_down(h2_iqueue *q, int i, int bottom,
|
|
Packit |
90a5c9 |
h2_iq_cmp *cmp, void *ctx);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
h2_iqueue *h2_iq_create(apr_pool_t *pool, int capacity)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
h2_iqueue *q = apr_pcalloc(pool, sizeof(h2_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_iq_empty(h2_iqueue *q)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return q->nelts == 0;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
int h2_iq_count(h2_iqueue *q)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return q->nelts;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
int h2_iq_add(h2_iqueue *q, int sid, h2_iq_cmp *cmp, void *ctx)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
int i;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (h2_iq_contains(q, sid)) {
|
|
Packit |
90a5c9 |
return 0;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (q->nelts >= q->nalloc) {
|
|
Packit |
90a5c9 |
iq_grow(q, q->nalloc * 2);
|
|
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 |
return 1;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
int h2_iq_append(h2_iqueue *q, int sid)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return h2_iq_add(q, sid, NULL, NULL);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
int h2_iq_remove(h2_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_iq_clear(h2_iqueue *q)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
q->nelts = 0;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
void h2_iq_sort(h2_iqueue *q, h2_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 comparisions 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_iq_shift(h2_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 |
size_t h2_iq_mshift(h2_iqueue *q, int *pint, size_t max)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
int i;
|
|
Packit |
90a5c9 |
for (i = 0; i < max; ++i) {
|
|
Packit |
90a5c9 |
pint[i] = h2_iq_shift(q);
|
|
Packit |
90a5c9 |
if (pint[i] == 0) {
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return i;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static void iq_grow(h2_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_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_iqueue *q, int i, int top,
|
|
Packit |
90a5c9 |
h2_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_iqueue *q, int i, int bottom,
|
|
Packit |
90a5c9 |
h2_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 |
int h2_iq_contains(h2_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 |
return 1;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return 0;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/*******************************************************************************
|
|
Packit |
90a5c9 |
* FIFO queue
|
|
Packit |
90a5c9 |
******************************************************************************/
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
struct h2_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_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_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_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_fifo **pfifo, apr_pool_t *pool,
|
|
Packit |
90a5c9 |
int capacity, int as_set)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_status_t rv;
|
|
Packit |
90a5c9 |
h2_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_fifo_create(h2_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_fifo_set_create(h2_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_fifo_term(h2_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_fifo_interrupt(h2_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_fifo_count(h2_fifo *fifo)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return fifo->count;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static apr_status_t check_not_empty(h2_fifo *fifo, int block)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
while (fifo->count == 0) {
|
|
Packit |
90a5c9 |
if (!block) {
|
|
Packit |
90a5c9 |
return APR_EAGAIN;
|
|
Packit |
90a5c9 |
}
|
|
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 |
return APR_SUCCESS;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static apr_status_t fifo_push_int(h2_fifo *fifo, void *elem, int block)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
if (fifo->aborted) {
|
|
Packit |
90a5c9 |
return APR_EOF;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (fifo->set && index_of(fifo, elem) >= 0) {
|
|
Packit |
90a5c9 |
/* set mode, elem already member */
|
|
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 |
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 |
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 |
return APR_SUCCESS;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static apr_status_t fifo_push(h2_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 |
rv = fifo_push_int(fifo, elem, block);
|
|
Packit |
90a5c9 |
apr_thread_mutex_unlock(fifo->lock);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return rv;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t h2_fifo_push(h2_fifo *fifo, void *elem)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return fifo_push(fifo, elem, 1);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t h2_fifo_try_push(h2_fifo *fifo, void *elem)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return fifo_push(fifo, elem, 0);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static apr_status_t pull_head(h2_fifo *fifo, void **pelem, int block)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_status_t rv;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if ((rv = check_not_empty(fifo, block)) != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
*pelem = NULL;
|
|
Packit |
90a5c9 |
return rv;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
*pelem = 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 APR_SUCCESS;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static apr_status_t fifo_pull(h2_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 |
rv = pull_head(fifo, pelem, block);
|
|
Packit |
90a5c9 |
apr_thread_mutex_unlock(fifo->lock);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return rv;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t h2_fifo_pull(h2_fifo *fifo, void **pelem)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return fifo_pull(fifo, pelem, 1);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t h2_fifo_try_pull(h2_fifo *fifo, void **pelem)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return fifo_pull(fifo, pelem, 0);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static apr_status_t fifo_peek(h2_fifo *fifo, h2_fifo_peek_fn *fn, void *ctx, int block)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_status_t rv;
|
|
Packit |
90a5c9 |
void *elem;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (fifo->aborted) {
|
|
Packit |
90a5c9 |
return APR_EOF;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (APR_SUCCESS == (rv = apr_thread_mutex_lock(fifo->lock))) {
|
|
Packit |
90a5c9 |
if (APR_SUCCESS == (rv = pull_head(fifo, &elem, block))) {
|
|
Packit |
90a5c9 |
switch (fn(elem, ctx)) {
|
|
Packit |
90a5c9 |
case H2_FIFO_OP_PULL:
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
case H2_FIFO_OP_REPUSH:
|
|
Packit |
90a5c9 |
rv = fifo_push_int(fifo, elem, block);
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
}
|
|
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_fifo_peek(h2_fifo *fifo, h2_fifo_peek_fn *fn, void *ctx)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return fifo_peek(fifo, fn, ctx, 1);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t h2_fifo_try_peek(h2_fifo *fifo, h2_fifo_peek_fn *fn, void *ctx)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return fifo_peek(fifo, fn, ctx, 0);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t h2_fifo_remove(h2_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 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/*******************************************************************************
|
|
Packit |
90a5c9 |
* FIFO int queue
|
|
Packit |
90a5c9 |
******************************************************************************/
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
struct h2_ififo {
|
|
Packit |
90a5c9 |
int *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 inth_index(h2_ififo *fifo, int n)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return (fifo->head + n) % fifo->nelems;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static apr_status_t ififo_destroy(void *data)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
h2_ififo *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 iindex_of(h2_ififo *fifo, int id)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
int i;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
for (i = 0; i < fifo->count; ++i) {
|
|
Packit |
90a5c9 |
if (id == fifo->elems[inth_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 icreate_int(h2_ififo **pfifo, apr_pool_t *pool,
|
|
Packit |
90a5c9 |
int capacity, int as_set)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_status_t rv;
|
|
Packit |
90a5c9 |
h2_ififo *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(int));
|
|
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, ififo_destroy, apr_pool_cleanup_null);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return APR_SUCCESS;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t h2_ififo_create(h2_ififo **pfifo, apr_pool_t *pool, int capacity)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return icreate_int(pfifo, pool, capacity, 0);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t h2_ififo_set_create(h2_ififo **pfifo, apr_pool_t *pool, int capacity)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return icreate_int(pfifo, pool, capacity, 1);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t h2_ififo_term(h2_ififo *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_ififo_interrupt(h2_ififo *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_ififo_count(h2_ififo *fifo)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return fifo->count;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static apr_status_t icheck_not_empty(h2_ififo *fifo, int block)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
while (fifo->count == 0) {
|
|
Packit |
90a5c9 |
if (!block) {
|
|
Packit |
90a5c9 |
return APR_EAGAIN;
|
|
Packit |
90a5c9 |
}
|
|
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 |
return APR_SUCCESS;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static apr_status_t ififo_push_int(h2_ififo *fifo, int id, int block)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
if (fifo->aborted) {
|
|
Packit |
90a5c9 |
return APR_EOF;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (fifo->set && iindex_of(fifo, id) >= 0) {
|
|
Packit |
90a5c9 |
/* set mode, elem already member */
|
|
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 |
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 |
return APR_EAGAIN;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
ap_assert(fifo->count < fifo->nelems);
|
|
Packit |
90a5c9 |
fifo->elems[inth_index(fifo, fifo->count)] = id;
|
|
Packit |
90a5c9 |
++fifo->count;
|
|
Packit |
90a5c9 |
if (fifo->count == 1) {
|
|
Packit |
90a5c9 |
apr_thread_cond_broadcast(fifo->not_empty);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return APR_SUCCESS;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static apr_status_t ififo_push(h2_ififo *fifo, int id, 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 |
rv = ififo_push_int(fifo, id, block);
|
|
Packit |
90a5c9 |
apr_thread_mutex_unlock(fifo->lock);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return rv;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t h2_ififo_push(h2_ififo *fifo, int id)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return ififo_push(fifo, id, 1);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t h2_ififo_try_push(h2_ififo *fifo, int id)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return ififo_push(fifo, id, 0);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static apr_status_t ipull_head(h2_ififo *fifo, int *pi, int block)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_status_t rv;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if ((rv = icheck_not_empty(fifo, block)) != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
*pi = 0;
|
|
Packit |
90a5c9 |
return rv;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
*pi = fifo->elems[fifo->head];
|
|
Packit |
90a5c9 |
--fifo->count;
|
|
Packit |
90a5c9 |
if (fifo->count > 0) {
|
|
Packit |
90a5c9 |
fifo->head = inth_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 APR_SUCCESS;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static apr_status_t ififo_pull(h2_ififo *fifo, int *pi, 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 |
rv = ipull_head(fifo, pi, block);
|
|
Packit |
90a5c9 |
apr_thread_mutex_unlock(fifo->lock);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return rv;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t h2_ififo_pull(h2_ififo *fifo, int *pi)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return ififo_pull(fifo, pi, 1);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t h2_ififo_try_pull(h2_ififo *fifo, int *pi)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return ififo_pull(fifo, pi, 0);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static apr_status_t ififo_peek(h2_ififo *fifo, h2_ififo_peek_fn *fn, void *ctx, int block)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_status_t rv;
|
|
Packit |
90a5c9 |
int id;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (fifo->aborted) {
|
|
Packit |
90a5c9 |
return APR_EOF;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (APR_SUCCESS == (rv = apr_thread_mutex_lock(fifo->lock))) {
|
|
Packit |
90a5c9 |
if (APR_SUCCESS == (rv = ipull_head(fifo, &id, block))) {
|
|
Packit |
90a5c9 |
switch (fn(id, ctx)) {
|
|
Packit |
90a5c9 |
case H2_FIFO_OP_PULL:
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
case H2_FIFO_OP_REPUSH:
|
|
Packit |
90a5c9 |
rv = ififo_push_int(fifo, id, block);
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
}
|
|
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_ififo_peek(h2_ififo *fifo, h2_ififo_peek_fn *fn, void *ctx)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return ififo_peek(fifo, fn, ctx, 1);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t h2_ififo_try_peek(h2_ififo *fifo, h2_ififo_peek_fn *fn, void *ctx)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return ififo_peek(fifo, fn, ctx, 0);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t h2_ififo_remove(h2_ififo *fifo, int id)
|
|
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 |
int e;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
rc = 0;
|
|
Packit |
90a5c9 |
for (i = 0; i < fifo->count; ++i) {
|
|
Packit |
90a5c9 |
e = fifo->elems[inth_index(fifo, i)];
|
|
Packit |
90a5c9 |
if (e == id) {
|
|
Packit |
90a5c9 |
++rc;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (rc) {
|
|
Packit |
90a5c9 |
fifo->elems[inth_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 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/*******************************************************************************
|
|
Packit |
90a5c9 |
* h2_util for apt_table_t
|
|
Packit |
90a5c9 |
******************************************************************************/
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
typedef struct {
|
|
Packit |
90a5c9 |
apr_size_t bytes;
|
|
Packit |
90a5c9 |
apr_size_t pair_extra;
|
|
Packit |
90a5c9 |
} table_bytes_ctx;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int count_bytes(void *x, const char *key, const char *value)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
table_bytes_ctx *ctx = x;
|
|
Packit |
90a5c9 |
if (key) {
|
|
Packit |
90a5c9 |
ctx->bytes += strlen(key);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (value) {
|
|
Packit |
90a5c9 |
ctx->bytes += strlen(value);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
ctx->bytes += ctx->pair_extra;
|
|
Packit |
90a5c9 |
return 1;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_size_t h2_util_table_bytes(apr_table_t *t, apr_size_t pair_extra)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
table_bytes_ctx ctx;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
ctx.bytes = 0;
|
|
Packit |
90a5c9 |
ctx.pair_extra = pair_extra;
|
|
Packit |
90a5c9 |
apr_table_do(count_bytes, &ctx, t, NULL);
|
|
Packit |
90a5c9 |
return ctx.bytes;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/*******************************************************************************
|
|
Packit |
90a5c9 |
* h2_util for bucket brigades
|
|
Packit |
90a5c9 |
******************************************************************************/
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static apr_status_t last_not_included(apr_bucket_brigade *bb,
|
|
Packit |
90a5c9 |
apr_off_t maxlen,
|
|
Packit |
90a5c9 |
int same_alloc,
|
|
Packit |
90a5c9 |
apr_size_t *pfile_buckets_allowed,
|
|
Packit |
90a5c9 |
apr_bucket **pend)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_bucket *b;
|
|
Packit |
90a5c9 |
apr_status_t status = APR_SUCCESS;
|
|
Packit |
90a5c9 |
int files_allowed = pfile_buckets_allowed? (int)*pfile_buckets_allowed : 0;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (maxlen >= 0) {
|
|
Packit |
90a5c9 |
/* Find the bucket, up to which we reach maxlen/mem bytes */
|
|
Packit |
90a5c9 |
for (b = APR_BRIGADE_FIRST(bb);
|
|
Packit |
90a5c9 |
(b != APR_BRIGADE_SENTINEL(bb));
|
|
Packit |
90a5c9 |
b = APR_BUCKET_NEXT(b)) {
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (APR_BUCKET_IS_METADATA(b)) {
|
|
Packit |
90a5c9 |
/* included */
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
if (b->length == ((apr_size_t)-1)) {
|
|
Packit |
90a5c9 |
const char *ign;
|
|
Packit |
90a5c9 |
apr_size_t ilen;
|
|
Packit |
90a5c9 |
status = apr_bucket_read(b, &ign, &ilen, APR_BLOCK_READ);
|
|
Packit |
90a5c9 |
if (status != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
return status;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (maxlen == 0 && b->length > 0) {
|
|
Packit |
90a5c9 |
*pend = b;
|
|
Packit |
90a5c9 |
return status;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (same_alloc && APR_BUCKET_IS_FILE(b)) {
|
|
Packit |
90a5c9 |
/* we like it move it, always */
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (files_allowed > 0 && APR_BUCKET_IS_FILE(b)) {
|
|
Packit |
90a5c9 |
/* this has no memory footprint really unless
|
|
Packit |
90a5c9 |
* it is read, disregard it in length count,
|
|
Packit |
90a5c9 |
* unless we do not move the file buckets */
|
|
Packit |
90a5c9 |
--files_allowed;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (maxlen < (apr_off_t)b->length) {
|
|
Packit |
90a5c9 |
apr_bucket_split(b, (apr_size_t)maxlen);
|
|
Packit |
90a5c9 |
maxlen = 0;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
maxlen -= b->length;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
*pend = APR_BRIGADE_SENTINEL(bb);
|
|
Packit |
90a5c9 |
return status;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t h2_brigade_concat_length(apr_bucket_brigade *dest,
|
|
Packit |
90a5c9 |
apr_bucket_brigade *src,
|
|
Packit |
90a5c9 |
apr_off_t length)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_bucket *b;
|
|
Packit |
90a5c9 |
apr_off_t remain = length;
|
|
Packit |
90a5c9 |
apr_status_t status = APR_SUCCESS;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
while (!APR_BRIGADE_EMPTY(src)) {
|
|
Packit |
90a5c9 |
b = APR_BRIGADE_FIRST(src);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (APR_BUCKET_IS_METADATA(b)) {
|
|
Packit |
90a5c9 |
APR_BUCKET_REMOVE(b);
|
|
Packit |
90a5c9 |
APR_BRIGADE_INSERT_TAIL(dest, b);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
if (remain == b->length) {
|
|
Packit |
90a5c9 |
/* fall through */
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (remain <= 0) {
|
|
Packit |
90a5c9 |
return status;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
if (b->length == ((apr_size_t)-1)) {
|
|
Packit |
90a5c9 |
const char *ign;
|
|
Packit |
90a5c9 |
apr_size_t ilen;
|
|
Packit |
90a5c9 |
status = apr_bucket_read(b, &ign, &ilen, APR_BLOCK_READ);
|
|
Packit |
90a5c9 |
if (status != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
return status;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (remain < b->length) {
|
|
Packit |
90a5c9 |
apr_bucket_split(b, remain);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
APR_BUCKET_REMOVE(b);
|
|
Packit |
90a5c9 |
APR_BRIGADE_INSERT_TAIL(dest, b);
|
|
Packit |
90a5c9 |
remain -= b->length;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return status;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t h2_brigade_copy_length(apr_bucket_brigade *dest,
|
|
Packit |
90a5c9 |
apr_bucket_brigade *src,
|
|
Packit |
90a5c9 |
apr_off_t length)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_bucket *b, *next;
|
|
Packit |
90a5c9 |
apr_off_t remain = length;
|
|
Packit |
90a5c9 |
apr_status_t status = APR_SUCCESS;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
for (b = APR_BRIGADE_FIRST(src);
|
|
Packit |
90a5c9 |
b != APR_BRIGADE_SENTINEL(src);
|
|
Packit |
90a5c9 |
b = next) {
|
|
Packit |
90a5c9 |
next = APR_BUCKET_NEXT(b);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (APR_BUCKET_IS_METADATA(b)) {
|
|
Packit |
90a5c9 |
/* fall through */
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
if (remain == b->length) {
|
|
Packit |
90a5c9 |
/* fall through */
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (remain <= 0) {
|
|
Packit |
90a5c9 |
return status;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
if (b->length == ((apr_size_t)-1)) {
|
|
Packit |
90a5c9 |
const char *ign;
|
|
Packit |
90a5c9 |
apr_size_t ilen;
|
|
Packit |
90a5c9 |
status = apr_bucket_read(b, &ign, &ilen, APR_BLOCK_READ);
|
|
Packit |
90a5c9 |
if (status != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
return status;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (remain < b->length) {
|
|
Packit |
90a5c9 |
apr_bucket_split(b, remain);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
status = apr_bucket_copy(b, &b);
|
|
Packit |
90a5c9 |
if (status != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
return status;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
APR_BRIGADE_INSERT_TAIL(dest, b);
|
|
Packit |
90a5c9 |
remain -= b->length;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return status;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
int h2_util_has_eos(apr_bucket_brigade *bb, apr_off_t len)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_bucket *b, *end;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t status = last_not_included(bb, len, 0, 0, &end;;
|
|
Packit |
90a5c9 |
if (status != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
return status;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
for (b = APR_BRIGADE_FIRST(bb);
|
|
Packit |
90a5c9 |
b != APR_BRIGADE_SENTINEL(bb) && b != end;
|
|
Packit |
90a5c9 |
b = APR_BUCKET_NEXT(b))
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
if (APR_BUCKET_IS_EOS(b)) {
|
|
Packit |
90a5c9 |
return 1;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return 0;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t h2_util_bb_avail(apr_bucket_brigade *bb,
|
|
Packit |
90a5c9 |
apr_off_t *plen, int *peos)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_status_t status;
|
|
Packit |
90a5c9 |
apr_off_t blen = 0;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* test read to determine available length */
|
|
Packit |
90a5c9 |
status = apr_brigade_length(bb, 1, &blen);
|
|
Packit |
90a5c9 |
if (status != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
return status;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (blen == 0) {
|
|
Packit |
90a5c9 |
/* brigade without data, does it have an EOS bucket somwhere? */
|
|
Packit |
90a5c9 |
*plen = 0;
|
|
Packit |
90a5c9 |
*peos = h2_util_has_eos(bb, -1);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
/* data in the brigade, limit the length returned. Check for EOS
|
|
Packit |
90a5c9 |
* bucket only if we indicate data. This is required since plen == 0
|
|
Packit |
90a5c9 |
* means "the whole brigade" for h2_util_hash_eos()
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
if (blen < *plen || *plen < 0) {
|
|
Packit |
90a5c9 |
*plen = blen;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
*peos = h2_util_has_eos(bb, *plen);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return APR_SUCCESS;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t h2_util_bb_readx(apr_bucket_brigade *bb,
|
|
Packit |
90a5c9 |
h2_util_pass_cb *cb, void *ctx,
|
|
Packit |
90a5c9 |
apr_off_t *plen, int *peos)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_status_t status = APR_SUCCESS;
|
|
Packit |
90a5c9 |
int consume = (cb != NULL);
|
|
Packit |
90a5c9 |
apr_off_t written = 0;
|
|
Packit |
90a5c9 |
apr_off_t avail = *plen;
|
|
Packit |
90a5c9 |
apr_bucket *next, *b;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* Pass data in our brigade through the callback until the length
|
|
Packit |
90a5c9 |
* is satisfied or we encounter an EOS.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
*peos = 0;
|
|
Packit |
90a5c9 |
for (b = APR_BRIGADE_FIRST(bb);
|
|
Packit |
90a5c9 |
(status == APR_SUCCESS) && (b != APR_BRIGADE_SENTINEL(bb));
|
|
Packit |
90a5c9 |
b = next) {
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (APR_BUCKET_IS_METADATA(b)) {
|
|
Packit |
90a5c9 |
if (APR_BUCKET_IS_EOS(b)) {
|
|
Packit |
90a5c9 |
*peos = 1;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
/* ignore */
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (avail <= 0) {
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
const char *data = NULL;
|
|
Packit |
90a5c9 |
apr_size_t data_len;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (b->length == ((apr_size_t)-1)) {
|
|
Packit |
90a5c9 |
/* read to determine length */
|
|
Packit |
90a5c9 |
status = apr_bucket_read(b, &data, &data_len, APR_NONBLOCK_READ);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
data_len = b->length;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (data_len > avail) {
|
|
Packit |
90a5c9 |
apr_bucket_split(b, avail);
|
|
Packit |
90a5c9 |
data_len = (apr_size_t)avail;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (consume) {
|
|
Packit |
90a5c9 |
if (!data) {
|
|
Packit |
90a5c9 |
status = apr_bucket_read(b, &data, &data_len,
|
|
Packit |
90a5c9 |
APR_NONBLOCK_READ);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (status == APR_SUCCESS) {
|
|
Packit |
90a5c9 |
status = cb(ctx, data, data_len);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
data_len = b->length;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
avail -= data_len;
|
|
Packit |
90a5c9 |
written += data_len;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
next = APR_BUCKET_NEXT(b);
|
|
Packit |
90a5c9 |
if (consume) {
|
|
Packit |
90a5c9 |
apr_bucket_delete(b);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
*plen = written;
|
|
Packit |
90a5c9 |
if (status == APR_SUCCESS && !*peos && !*plen) {
|
|
Packit |
90a5c9 |
return APR_EAGAIN;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return status;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_size_t h2_util_bucket_print(char *buffer, apr_size_t bmax,
|
|
Packit |
90a5c9 |
apr_bucket *b, const char *sep)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_size_t off = 0;
|
|
Packit |
90a5c9 |
if (sep && *sep) {
|
|
Packit |
90a5c9 |
off += apr_snprintf(buffer+off, bmax-off, "%s", sep);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (bmax <= off) {
|
|
Packit |
90a5c9 |
return off;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (APR_BUCKET_IS_METADATA(b)) {
|
|
Packit |
90a5c9 |
off += apr_snprintf(buffer+off, bmax-off, "%s", b->type->name);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (bmax > off) {
|
|
Packit |
90a5c9 |
off += apr_snprintf(buffer+off, bmax-off, "%s[%ld]",
|
|
Packit |
90a5c9 |
b->type->name,
|
|
Packit |
90a5c9 |
(long)(b->length == ((apr_size_t)-1)?
|
|
Packit |
90a5c9 |
-1 : b->length));
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return off;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_size_t h2_util_bb_print(char *buffer, apr_size_t bmax,
|
|
Packit |
90a5c9 |
const char *tag, const char *sep,
|
|
Packit |
90a5c9 |
apr_bucket_brigade *bb)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_size_t off = 0;
|
|
Packit |
90a5c9 |
const char *sp = "";
|
|
Packit |
90a5c9 |
apr_bucket *b;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (bmax > 1) {
|
|
Packit |
90a5c9 |
if (bb) {
|
|
Packit |
90a5c9 |
memset(buffer, 0, bmax--);
|
|
Packit |
90a5c9 |
off += apr_snprintf(buffer+off, bmax-off, "%s(", tag);
|
|
Packit |
90a5c9 |
for (b = APR_BRIGADE_FIRST(bb);
|
|
Packit |
90a5c9 |
(bmax > off) && (b != APR_BRIGADE_SENTINEL(bb));
|
|
Packit |
90a5c9 |
b = APR_BUCKET_NEXT(b)) {
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
off += h2_util_bucket_print(buffer+off, bmax-off, b, sp);
|
|
Packit |
90a5c9 |
sp = " ";
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (bmax > off) {
|
|
Packit |
90a5c9 |
off += apr_snprintf(buffer+off, bmax-off, ")%s", sep);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
off += apr_snprintf(buffer+off, bmax-off, "%s(null)%s", tag, sep);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return off;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t h2_append_brigade(apr_bucket_brigade *to,
|
|
Packit |
90a5c9 |
apr_bucket_brigade *from,
|
|
Packit |
90a5c9 |
apr_off_t *plen,
|
|
Packit |
90a5c9 |
int *peos,
|
|
Packit |
90a5c9 |
h2_bucket_gate *should_append)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_bucket *e;
|
|
Packit |
90a5c9 |
apr_off_t len = 0, remain = *plen;
|
|
Packit |
90a5c9 |
apr_status_t rv;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
*peos = 0;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
while (!APR_BRIGADE_EMPTY(from)) {
|
|
Packit |
90a5c9 |
e = APR_BRIGADE_FIRST(from);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (!should_append(e)) {
|
|
Packit |
90a5c9 |
goto leave;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (APR_BUCKET_IS_METADATA(e)) {
|
|
Packit |
90a5c9 |
if (APR_BUCKET_IS_EOS(e)) {
|
|
Packit |
90a5c9 |
*peos = 1;
|
|
Packit |
90a5c9 |
apr_bucket_delete(e);
|
|
Packit |
90a5c9 |
continue;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
if (remain > 0 && e->length == ((apr_size_t)-1)) {
|
|
Packit |
90a5c9 |
const char *ign;
|
|
Packit |
90a5c9 |
apr_size_t ilen;
|
|
Packit |
90a5c9 |
rv = apr_bucket_read(e, &ign, &ilen, APR_BLOCK_READ);
|
|
Packit |
90a5c9 |
if (rv != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
return rv;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (remain < e->length) {
|
|
Packit |
90a5c9 |
if (remain <= 0) {
|
|
Packit |
90a5c9 |
goto leave;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
apr_bucket_split(e, (apr_size_t)remain);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
APR_BUCKET_REMOVE(e);
|
|
Packit |
90a5c9 |
APR_BRIGADE_INSERT_TAIL(to, e);
|
|
Packit |
90a5c9 |
len += e->length;
|
|
Packit |
90a5c9 |
remain -= e->length;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
leave:
|
|
Packit |
90a5c9 |
*plen = len;
|
|
Packit |
90a5c9 |
return APR_SUCCESS;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_off_t h2_brigade_mem_size(apr_bucket_brigade *bb)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_bucket *b;
|
|
Packit |
90a5c9 |
apr_off_t total = 0;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
for (b = APR_BRIGADE_FIRST(bb);
|
|
Packit |
90a5c9 |
b != APR_BRIGADE_SENTINEL(bb);
|
|
Packit |
90a5c9 |
b = APR_BUCKET_NEXT(b))
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
total += sizeof(*b);
|
|
Packit |
90a5c9 |
if (b->length > 0) {
|
|
Packit |
90a5c9 |
if (APR_BUCKET_IS_HEAP(b)
|
|
Packit |
90a5c9 |
|| APR_BUCKET_IS_POOL(b)) {
|
|
Packit |
90a5c9 |
total += b->length;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return total;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/*******************************************************************************
|
|
Packit |
90a5c9 |
* h2_ngheader
|
|
Packit |
90a5c9 |
******************************************************************************/
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
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 |
static const char *inv_field_name_chr(const char *token)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
const char *p = ap_scan_http_token(token);
|
|
Packit |
90a5c9 |
if (p == token && *p == ':') {
|
|
Packit |
90a5c9 |
p = ap_scan_http_token(++p);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return (p && *p)? p : NULL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static const char *inv_field_value_chr(const char *token)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
const char *p = ap_scan_http_field_content(token);
|
|
Packit |
90a5c9 |
return (p && *p)? p : NULL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
typedef struct ngh_ctx {
|
|
Packit |
90a5c9 |
apr_pool_t *p;
|
|
Packit |
90a5c9 |
int unsafe;
|
|
Packit |
90a5c9 |
h2_ngheader *ngh;
|
|
Packit |
90a5c9 |
apr_status_t status;
|
|
Packit |
90a5c9 |
} ngh_ctx;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int add_header(ngh_ctx *ctx, const char *key, const char *value)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
nghttp2_nv *nv = &(ctx->ngh)->nv[(ctx->ngh)->nvlen++];
|
|
Packit |
90a5c9 |
const char *p;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (!ctx->unsafe) {
|
|
Packit |
90a5c9 |
if ((p = inv_field_name_chr(key))) {
|
|
Packit |
90a5c9 |
ap_log_perror(APLOG_MARK, APLOG_TRACE1, APR_EINVAL, ctx->p,
|
|
Packit |
90a5c9 |
"h2_request: head field '%s: %s' has invalid char %s",
|
|
Packit |
90a5c9 |
key, value, p);
|
|
Packit |
90a5c9 |
ctx->status = APR_EINVAL;
|
|
Packit |
90a5c9 |
return 0;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if ((p = inv_field_value_chr(value))) {
|
|
Packit |
90a5c9 |
ap_log_perror(APLOG_MARK, APLOG_TRACE1, APR_EINVAL, ctx->p,
|
|
Packit |
90a5c9 |
"h2_request: head field '%s: %s' has invalid char %s",
|
|
Packit |
90a5c9 |
key, value, p);
|
|
Packit |
90a5c9 |
ctx->status = APR_EINVAL;
|
|
Packit |
90a5c9 |
return 0;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
nv->name = (uint8_t*)key;
|
|
Packit |
90a5c9 |
nv->namelen = strlen(key);
|
|
Packit |
90a5c9 |
nv->value = (uint8_t*)value;
|
|
Packit |
90a5c9 |
nv->valuelen = strlen(value);
|
|
Packit |
90a5c9 |
|
|
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, value);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return 1;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static apr_status_t ngheader_create(h2_ngheader **ph, apr_pool_t *p,
|
|
Packit |
90a5c9 |
int unsafe, size_t key_count,
|
|
Packit |
90a5c9 |
const char *keys[], const char *values[],
|
|
Packit |
90a5c9 |
apr_table_t *headers)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
ngh_ctx ctx;
|
|
Packit |
90a5c9 |
size_t n, i;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
ctx.p = p;
|
|
Packit |
90a5c9 |
ctx.unsafe = unsafe;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
n = key_count;
|
|
Packit |
90a5c9 |
apr_table_do(count_header, &n, headers, NULL);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
*ph = ctx.ngh = apr_pcalloc(p, sizeof(h2_ngheader));
|
|
Packit |
90a5c9 |
if (!ctx.ngh) {
|
|
Packit |
90a5c9 |
return APR_ENOMEM;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
ctx.ngh->nv = apr_pcalloc(p, n * sizeof(nghttp2_nv));
|
|
Packit |
90a5c9 |
if (!ctx.ngh->nv) {
|
|
Packit |
90a5c9 |
return APR_ENOMEM;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
ctx.status = APR_SUCCESS;
|
|
Packit |
90a5c9 |
for (i = 0; i < key_count; ++i) {
|
|
Packit |
90a5c9 |
if (!add_header(&ctx, keys[i], values[i])) {
|
|
Packit |
90a5c9 |
return ctx.status;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_table_do(add_table_header, &ctx, headers, NULL);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return ctx.status;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int is_unsafe(h2_headers *h)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
const char *v = apr_table_get(h->notes, H2_HDR_CONFORMANCE);
|
|
Packit |
90a5c9 |
return (v && !strcmp(v, H2_HDR_CONFORMANCE_UNSAFE));
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t h2_res_create_ngtrailer(h2_ngheader **ph, apr_pool_t *p,
|
|
Packit |
90a5c9 |
h2_headers *headers)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return ngheader_create(ph, p, is_unsafe(headers),
|
|
Packit |
90a5c9 |
0, NULL, NULL, headers->headers);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t h2_res_create_ngheader(h2_ngheader **ph, apr_pool_t *p,
|
|
Packit |
90a5c9 |
h2_headers *headers)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
const char *keys[] = {
|
|
Packit |
90a5c9 |
":status"
|
|
Packit |
90a5c9 |
};
|
|
Packit |
90a5c9 |
const char *values[] = {
|
|
Packit |
90a5c9 |
apr_psprintf(p, "%d", headers->status)
|
|
Packit |
90a5c9 |
};
|
|
Packit |
90a5c9 |
return ngheader_create(ph, p, is_unsafe(headers),
|
|
Packit |
90a5c9 |
H2_ALEN(keys), keys, values, headers->headers);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t h2_req_create_ngheader(h2_ngheader **ph, apr_pool_t *p,
|
|
Packit |
90a5c9 |
const struct h2_request *req)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
const char *keys[] = {
|
|
Packit |
90a5c9 |
":scheme",
|
|
Packit |
90a5c9 |
":authority",
|
|
Packit |
90a5c9 |
":path",
|
|
Packit |
90a5c9 |
":method",
|
|
Packit |
90a5c9 |
};
|
|
Packit |
90a5c9 |
const char *values[] = {
|
|
Packit |
90a5c9 |
req->scheme,
|
|
Packit |
90a5c9 |
req->authority,
|
|
Packit |
90a5c9 |
req->path,
|
|
Packit |
90a5c9 |
req->method,
|
|
Packit |
90a5c9 |
};
|
|
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 |
return ngheader_create(ph, p, 0, H2_ALEN(keys), keys, values, req->headers);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/*******************************************************************************
|
|
Packit |
90a5c9 |
* header HTTP/1 <-> HTTP/2 conversions
|
|
Packit |
90a5c9 |
******************************************************************************/
|
|
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 IgnoredRequestTrailers[] = { /* Ignore, see rfc7230, ch. 4.1.2 */
|
|
Packit |
90a5c9 |
H2_DEF_LITERAL("te"),
|
|
Packit |
90a5c9 |
H2_DEF_LITERAL("host"),
|
|
Packit |
90a5c9 |
H2_DEF_LITERAL("range"),
|
|
Packit |
90a5c9 |
H2_DEF_LITERAL("cookie"),
|
|
Packit |
90a5c9 |
H2_DEF_LITERAL("expect"),
|
|
Packit |
90a5c9 |
H2_DEF_LITERAL("pragma"),
|
|
Packit |
90a5c9 |
H2_DEF_LITERAL("max-forwards"),
|
|
Packit |
90a5c9 |
H2_DEF_LITERAL("cache-control"),
|
|
Packit |
90a5c9 |
H2_DEF_LITERAL("authorization"),
|
|
Packit |
90a5c9 |
H2_DEF_LITERAL("content-length"),
|
|
Packit |
90a5c9 |
H2_DEF_LITERAL("proxy-authorization"),
|
|
Packit |
90a5c9 |
};
|
|
Packit |
90a5c9 |
static literal IgnoredResponseTrailers[] = {
|
|
Packit |
90a5c9 |
H2_DEF_LITERAL("age"),
|
|
Packit |
90a5c9 |
H2_DEF_LITERAL("date"),
|
|
Packit |
90a5c9 |
H2_DEF_LITERAL("vary"),
|
|
Packit |
90a5c9 |
H2_DEF_LITERAL("cookie"),
|
|
Packit |
90a5c9 |
H2_DEF_LITERAL("expires"),
|
|
Packit |
90a5c9 |
H2_DEF_LITERAL("warning"),
|
|
Packit |
90a5c9 |
H2_DEF_LITERAL("location"),
|
|
Packit |
90a5c9 |
H2_DEF_LITERAL("retry-after"),
|
|
Packit |
90a5c9 |
H2_DEF_LITERAL("cache-control"),
|
|
Packit |
90a5c9 |
H2_DEF_LITERAL("www-authenticate"),
|
|
Packit |
90a5c9 |
H2_DEF_LITERAL("proxy-authenticate"),
|
|
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 |
size_t 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 |
int h2_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_req_ignore_trailer(const char *name, size_t len)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return (h2_req_ignore_header(name, len)
|
|
Packit |
90a5c9 |
|| ignore_header(H2_LIT_ARGS(IgnoredRequestTrailers), name, len));
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
int h2_res_ignore_trailer(const char *name, size_t len)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return ignore_header(H2_LIT_ARGS(IgnoredResponseTrailers), name, len);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t h2_req_add_header(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_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_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 |
/*******************************************************************************
|
|
Packit |
90a5c9 |
* h2 request handling
|
|
Packit |
90a5c9 |
******************************************************************************/
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
h2_request *h2_req_create(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, int serialize)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
h2_request *req = apr_pcalloc(pool, sizeof(h2_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 |
/*******************************************************************************
|
|
Packit |
90a5c9 |
* frame logging
|
|
Packit |
90a5c9 |
******************************************************************************/
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
int h2_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 |
* push policy
|
|
Packit |
90a5c9 |
******************************************************************************/
|
|
Packit |
90a5c9 |
int h2_push_policy_determine(apr_table_t *headers, apr_pool_t *p, int push_enabled)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
h2_push_policy policy = H2_PUSH_NONE;
|
|
Packit |
90a5c9 |
if (push_enabled) {
|
|
Packit |
90a5c9 |
const char *val = apr_table_get(headers, "accept-push-policy");
|
|
Packit |
90a5c9 |
if (val) {
|
|
Packit |
90a5c9 |
if (ap_find_token(p, val, "fast-load")) {
|
|
Packit |
90a5c9 |
policy = H2_PUSH_FAST_LOAD;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (ap_find_token(p, val, "head")) {
|
|
Packit |
90a5c9 |
policy = H2_PUSH_HEAD;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (ap_find_token(p, val, "default")) {
|
|
Packit |
90a5c9 |
policy = H2_PUSH_DEFAULT;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (ap_find_token(p, val, "none")) {
|
|
Packit |
90a5c9 |
policy = H2_PUSH_NONE;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
/* nothing known found in this header, go by default */
|
|
Packit |
90a5c9 |
policy = H2_PUSH_DEFAULT;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
policy = H2_PUSH_DEFAULT;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return policy;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|