Blame modules/http2/h2_util.h

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
#ifndef __mod_h2__h2_util__
Packit 90a5c9
#define __mod_h2__h2_util__
Packit 90a5c9
Packit 90a5c9
#include <nghttp2/nghttp2.h>
Packit 90a5c9
Packit 90a5c9
/*******************************************************************************
Packit 90a5c9
 * some debugging/format helpers
Packit 90a5c9
 ******************************************************************************/
Packit 90a5c9
struct h2_request;
Packit 90a5c9
struct nghttp2_frame;
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 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
void h2_util_camel_case_header(char *s, size_t len);
Packit 90a5c9
Packit 90a5c9
int h2_util_frame_print(const nghttp2_frame *frame, char *buffer, size_t maxlen);
Packit 90a5c9
Packit 90a5c9
/*******************************************************************************
Packit 90a5c9
 * ihash - hash for structs with int identifier
Packit 90a5c9
 ******************************************************************************/
Packit 90a5c9
typedef struct h2_ihash_t h2_ihash_t;
Packit 90a5c9
typedef int h2_ihash_iter_t(void *ctx, void *val);
Packit 90a5c9
Packit 90a5c9
/**
Packit 90a5c9
 * Create a hash for structures that have an identifying int member.
Packit 90a5c9
 * @param pool the pool to use
Packit 90a5c9
 * @param offset_of_int the offsetof() the int member in the struct
Packit 90a5c9
 */
Packit 90a5c9
h2_ihash_t *h2_ihash_create(apr_pool_t *pool, size_t offset_of_int);
Packit 90a5c9
Packit 90a5c9
size_t h2_ihash_count(h2_ihash_t *ih);
Packit 90a5c9
int h2_ihash_empty(h2_ihash_t *ih);
Packit 90a5c9
void *h2_ihash_get(h2_ihash_t *ih, int id);
Packit 90a5c9
Packit 90a5c9
/**
Packit 90a5c9
 * Iterate over the hash members (without defined order) and invoke
Packit 90a5c9
 * fn for each member until 0 is returned.
Packit 90a5c9
 * @param ih the hash to iterate over
Packit 90a5c9
 * @param fn the function to invoke on each member
Packit 90a5c9
 * @param ctx user supplied data passed into each iteration call
Packit 90a5c9
 * @return 0 if one iteration returned 0, otherwise != 0
Packit 90a5c9
 */
Packit 90a5c9
int h2_ihash_iter(h2_ihash_t *ih, h2_ihash_iter_t *fn, void *ctx);
Packit 90a5c9
Packit 90a5c9
void h2_ihash_add(h2_ihash_t *ih, void *val);
Packit 90a5c9
void h2_ihash_remove(h2_ihash_t *ih, int id);
Packit 90a5c9
void h2_ihash_remove_val(h2_ihash_t *ih, void *val);
Packit 90a5c9
void h2_ihash_clear(h2_ihash_t *ih);
Packit 90a5c9
Packit 90a5c9
size_t h2_ihash_shift(h2_ihash_t *ih, void **buffer, size_t max);
Packit 90a5c9
Packit 90a5c9
/*******************************************************************************
Packit 90a5c9
 * iqueue - sorted list of int with user defined ordering
Packit 90a5c9
 ******************************************************************************/
Packit 90a5c9
typedef struct h2_iqueue {
Packit 90a5c9
    int *elts;
Packit 90a5c9
    int head;
Packit 90a5c9
    int nelts;
Packit 90a5c9
    int nalloc;
Packit 90a5c9
    apr_pool_t *pool;
Packit 90a5c9
} h2_iqueue;
Packit 90a5c9
Packit 90a5c9
/**
Packit 90a5c9
 * Comparator for two int to determine their order.
Packit 90a5c9
 *
Packit 90a5c9
 * @param i1 first int to compare
Packit 90a5c9
 * @param i2 second int to compare
Packit 90a5c9
 * @param ctx provided user data
Packit 90a5c9
 * @return value is the same as for strcmp() and has the effect:
Packit 90a5c9
 *    == 0: s1 and s2 are treated equal in ordering
Packit 90a5c9
 *     < 0: s1 should be sorted before s2
Packit 90a5c9
 *     > 0: s2 should be sorted before s1
Packit 90a5c9
 */
Packit 90a5c9
typedef int h2_iq_cmp(int i1, int i2, void *ctx);
Packit 90a5c9
Packit 90a5c9
/**
Packit 90a5c9
 * Allocate a new queue from the pool and initialize.
Packit 90a5c9
 * @param id the identifier of the queue
Packit 90a5c9
 * @param pool the memory pool
Packit 90a5c9
 */
Packit 90a5c9
h2_iqueue *h2_iq_create(apr_pool_t *pool, int capacity);
Packit 90a5c9
Packit 90a5c9
/**
Packit 90a5c9
 * Return != 0 iff there are no tasks in the queue.
Packit 90a5c9
 * @param q the queue to check
Packit 90a5c9
 */
Packit 90a5c9
int h2_iq_empty(h2_iqueue *q);
Packit 90a5c9
Packit 90a5c9
/**
Packit 90a5c9
 * Return the number of int in the queue.
Packit 90a5c9
 * @param q the queue to get size on
Packit 90a5c9
 */
Packit 90a5c9
int h2_iq_count(h2_iqueue *q);
Packit 90a5c9
Packit 90a5c9
/**
Packit 90a5c9
 * Add a stream id to the queue. 
Packit 90a5c9
 *
Packit 90a5c9
 * @param q the queue to append the id to
Packit 90a5c9
 * @param sid the stream id to add
Packit 90a5c9
 * @param cmp the comparator for sorting
Packit 90a5c9
 * @param ctx user data for comparator
Packit 90a5c9
 * @return != 0 iff id was not already there 
Packit 90a5c9
 */
Packit 90a5c9
int h2_iq_add(h2_iqueue *q, int sid, h2_iq_cmp *cmp, void *ctx);
Packit 90a5c9
Packit 90a5c9
/**
Packit 90a5c9
 * Append the id to the queue if not already present. 
Packit 90a5c9
 *
Packit 90a5c9
 * @param q the queue to append the id to
Packit 90a5c9
 * @param sid the id to append
Packit 90a5c9
 * @return != 0 iff id was not already there 
Packit 90a5c9
 */
Packit 90a5c9
int h2_iq_append(h2_iqueue *q, int sid);
Packit 90a5c9
Packit 90a5c9
/**
Packit 90a5c9
 * Remove the stream id from the queue. Return != 0 iff task
Packit 90a5c9
 * was found in queue.
Packit 90a5c9
 * @param q the task queue
Packit 90a5c9
 * @param sid the stream id to remove
Packit 90a5c9
 * @return != 0 iff task was found in queue
Packit 90a5c9
 */
Packit 90a5c9
int h2_iq_remove(h2_iqueue *q, int sid);
Packit 90a5c9
Packit 90a5c9
/**
Packit 90a5c9
 * Remove all entries in the queue.
Packit 90a5c9
 */
Packit 90a5c9
void h2_iq_clear(h2_iqueue *q);
Packit 90a5c9
Packit 90a5c9
/**
Packit 90a5c9
 * Sort the stream idqueue again. Call if the task ordering
Packit 90a5c9
 * has changed.
Packit 90a5c9
 *
Packit 90a5c9
 * @param q the queue to sort
Packit 90a5c9
 * @param cmp the comparator for sorting
Packit 90a5c9
 * @param ctx user data for the comparator 
Packit 90a5c9
 */
Packit 90a5c9
void h2_iq_sort(h2_iqueue *q, h2_iq_cmp *cmp, void *ctx);
Packit 90a5c9
Packit 90a5c9
/**
Packit 90a5c9
 * Get the first id from the queue or 0 if the queue is empty. 
Packit 90a5c9
 * The id is being removed.
Packit 90a5c9
 *
Packit 90a5c9
 * @param q the queue to get the first id from
Packit 90a5c9
 * @return the first id of the queue, 0 if empty
Packit 90a5c9
 */
Packit 90a5c9
int h2_iq_shift(h2_iqueue *q);
Packit 90a5c9
Packit 90a5c9
/**
Packit 90a5c9
 * Get the first max ids from the queue. All these ids will be removed.
Packit 90a5c9
 *
Packit 90a5c9
 * @param q the queue to get the first task from
Packit 90a5c9
 * @param pint the int array to receive the values
Packit 90a5c9
 * @param max the maximum number of ids to shift
Packit 90a5c9
 * @return the actual number of ids shifted
Packit 90a5c9
 */
Packit 90a5c9
size_t h2_iq_mshift(h2_iqueue *q, int *pint, size_t max);
Packit 90a5c9
Packit 90a5c9
/**
Packit 90a5c9
 * Determine if int is in the queue already
Packit 90a5c9
 *
Packit 90a5c9
 * @parm q the queue
Packit 90a5c9
 * @param sid the integer id to check for
Packit 90a5c9
 * @return != 0 iff sid is already in the queue
Packit 90a5c9
 */
Packit 90a5c9
int h2_iq_contains(h2_iqueue *q, int sid);
Packit 90a5c9
Packit 90a5c9
/*******************************************************************************
Packit 90a5c9
 * FIFO queue (void* elements)
Packit 90a5c9
 ******************************************************************************/
Packit 90a5c9
Packit 90a5c9
/**
Packit 90a5c9
 * A thread-safe FIFO queue with some extra bells and whistles, if you
Packit 90a5c9
 * do not need anything special, better use 'apr_queue'.
Packit 90a5c9
 */
Packit 90a5c9
typedef struct h2_fifo h2_fifo;
Packit 90a5c9
Packit 90a5c9
/**
Packit 90a5c9
 * Create a FIFO queue that can hold up to capacity elements. Elements can
Packit 90a5c9
 * appear several times.
Packit 90a5c9
 */
Packit 90a5c9
apr_status_t h2_fifo_create(h2_fifo **pfifo, apr_pool_t *pool, int capacity);
Packit 90a5c9
Packit 90a5c9
/**
Packit 90a5c9
 * Create a FIFO set that can hold up to capacity elements. Elements only
Packit 90a5c9
 * appear once. Pushing an element already present does not change the
Packit 90a5c9
 * queue and is successful.
Packit 90a5c9
 */
Packit 90a5c9
apr_status_t h2_fifo_set_create(h2_fifo **pfifo, apr_pool_t *pool, int capacity);
Packit 90a5c9
Packit 90a5c9
apr_status_t h2_fifo_term(h2_fifo *fifo);
Packit 90a5c9
apr_status_t h2_fifo_interrupt(h2_fifo *fifo);
Packit 90a5c9
Packit 90a5c9
int h2_fifo_count(h2_fifo *fifo);
Packit 90a5c9
Packit 90a5c9
/**
Packit 90a5c9
 * Push en element into the queue. Blocks if there is no capacity left.
Packit 90a5c9
 * 
Packit 90a5c9
 * @param fifo the FIFO queue
Packit 90a5c9
 * @param elem the element to push
Packit 90a5c9
 * @return APR_SUCCESS on push, APR_EAGAIN on try_push on a full queue,
Packit 90a5c9
 *         APR_EEXIST when in set mode and elem already there.
Packit 90a5c9
 */
Packit 90a5c9
apr_status_t h2_fifo_push(h2_fifo *fifo, void *elem);
Packit 90a5c9
apr_status_t h2_fifo_try_push(h2_fifo *fifo, void *elem);
Packit 90a5c9
Packit 90a5c9
apr_status_t h2_fifo_pull(h2_fifo *fifo, void **pelem);
Packit 90a5c9
apr_status_t h2_fifo_try_pull(h2_fifo *fifo, void **pelem);
Packit 90a5c9
Packit 90a5c9
typedef enum {
Packit 90a5c9
    H2_FIFO_OP_PULL,   /* pull the element from the queue, ie discard it */
Packit 90a5c9
    H2_FIFO_OP_REPUSH, /* pull and immediatley re-push it */
Packit 90a5c9
} h2_fifo_op_t;
Packit 90a5c9
Packit 90a5c9
typedef h2_fifo_op_t h2_fifo_peek_fn(void *head, void *ctx);
Packit 90a5c9
Packit 90a5c9
/**
Packit 90a5c9
 * Call given function on the head of the queue, once it exists, and
Packit 90a5c9
 * perform the returned operation on it. The queue will hold its lock during
Packit 90a5c9
 * this time, so no other operations on the queue are possible.
Packit 90a5c9
 * @param fifo the queue to peek at
Packit 90a5c9
 * @param fn   the function to call on the head, once available
Packit 90a5c9
 * @param ctx  context to pass in call to function
Packit 90a5c9
 */
Packit 90a5c9
apr_status_t h2_fifo_peek(h2_fifo *fifo, h2_fifo_peek_fn *fn, void *ctx);
Packit 90a5c9
Packit 90a5c9
/**
Packit 90a5c9
 * Non-blocking version of h2_fifo_peek.
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
/**
Packit 90a5c9
 * Remove the elem from the queue, will remove multiple appearances.
Packit 90a5c9
 * @param elem  the element to remove
Packit 90a5c9
 * @return APR_SUCCESS iff > 0 elems were removed, APR_EAGAIN otherwise.
Packit 90a5c9
 */
Packit 90a5c9
apr_status_t h2_fifo_remove(h2_fifo *fifo, void *elem);
Packit 90a5c9
Packit 90a5c9
/*******************************************************************************
Packit 90a5c9
 * iFIFO queue (int elements)
Packit 90a5c9
 ******************************************************************************/
Packit 90a5c9
Packit 90a5c9
/**
Packit 90a5c9
 * A thread-safe FIFO queue with some extra bells and whistles, if you
Packit 90a5c9
 * do not need anything special, better use 'apr_queue'.
Packit 90a5c9
 */
Packit 90a5c9
typedef struct h2_ififo h2_ififo;
Packit 90a5c9
Packit 90a5c9
/**
Packit 90a5c9
 * Create a FIFO queue that can hold up to capacity int. ints can
Packit 90a5c9
 * appear several times.
Packit 90a5c9
 */
Packit 90a5c9
apr_status_t h2_ififo_create(h2_ififo **pfifo, apr_pool_t *pool, int capacity);
Packit 90a5c9
Packit 90a5c9
/**
Packit 90a5c9
 * Create a FIFO set that can hold up to capacity integers. Ints only
Packit 90a5c9
 * appear once. Pushing an int already present does not change the
Packit 90a5c9
 * queue and is successful.
Packit 90a5c9
 */
Packit 90a5c9
apr_status_t h2_ififo_set_create(h2_ififo **pfifo, apr_pool_t *pool, int capacity);
Packit 90a5c9
Packit 90a5c9
apr_status_t h2_ififo_term(h2_ififo *fifo);
Packit 90a5c9
apr_status_t h2_ififo_interrupt(h2_ififo *fifo);
Packit 90a5c9
Packit 90a5c9
int h2_ififo_count(h2_ififo *fifo);
Packit 90a5c9
Packit 90a5c9
/**
Packit 90a5c9
 * Push an int into the queue. Blocks if there is no capacity left.
Packit 90a5c9
 * 
Packit 90a5c9
 * @param fifo the FIFO queue
Packit 90a5c9
 * @param id  the int to push
Packit 90a5c9
 * @return APR_SUCCESS on push, APR_EAGAIN on try_push on a full queue,
Packit 90a5c9
 *         APR_EEXIST when in set mode and elem already there.
Packit 90a5c9
 */
Packit 90a5c9
apr_status_t h2_ififo_push(h2_ififo *fifo, int id);
Packit 90a5c9
apr_status_t h2_ififo_try_push(h2_ififo *fifo, int id);
Packit 90a5c9
Packit 90a5c9
apr_status_t h2_ififo_pull(h2_ififo *fifo, int *pi);
Packit 90a5c9
apr_status_t h2_ififo_try_pull(h2_ififo *fifo, int *pi);
Packit 90a5c9
Packit 90a5c9
typedef h2_fifo_op_t h2_ififo_peek_fn(int head, void *ctx);
Packit 90a5c9
Packit 90a5c9
/**
Packit 90a5c9
 * Call given function on the head of the queue, once it exists, and
Packit 90a5c9
 * perform the returned operation on it. The queue will hold its lock during
Packit 90a5c9
 * this time, so no other operations on the queue are possible.
Packit 90a5c9
 * @param fifo the queue to peek at
Packit 90a5c9
 * @param fn   the function to call on the head, once available
Packit 90a5c9
 * @param ctx  context to pass in call to function
Packit 90a5c9
 */
Packit 90a5c9
apr_status_t h2_ififo_peek(h2_ififo *fifo, h2_ififo_peek_fn *fn, void *ctx);
Packit 90a5c9
Packit 90a5c9
/**
Packit 90a5c9
 * Non-blocking version of h2_fifo_peek.
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
/**
Packit 90a5c9
 * Remove the integer from the queue, will remove multiple appearances.
Packit 90a5c9
 * @param id  the integer to remove
Packit 90a5c9
 * @return APR_SUCCESS iff > 0 ints were removed, APR_EAGAIN otherwise.
Packit 90a5c9
 */
Packit 90a5c9
apr_status_t h2_ififo_remove(h2_ififo *fifo, int id);
Packit 90a5c9
Packit 90a5c9
/*******************************************************************************
Packit 90a5c9
 * common helpers
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
/**
Packit 90a5c9
 * Count the bytes that all key/value pairs in a table have
Packit 90a5c9
 * in length (exlucding terminating 0s), plus additional extra per pair.
Packit 90a5c9
 *
Packit 90a5c9
 * @param t the table to inspect
Packit 90a5c9
 * @param pair_extra the extra amount to add per pair
Packit 90a5c9
 * @return the number of bytes all key/value pairs have
Packit 90a5c9
 */
Packit 90a5c9
apr_size_t h2_util_table_bytes(apr_table_t *t, apr_size_t pair_extra);
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
/*******************************************************************************
Packit 90a5c9
 * HTTP/2 header helpers
Packit 90a5c9
 ******************************************************************************/
Packit 90a5c9
int h2_req_ignore_header(const char *name, size_t len);
Packit 90a5c9
int h2_req_ignore_trailer(const char *name, size_t len);
Packit 90a5c9
int h2_res_ignore_trailer(const char *name, size_t len);
Packit 90a5c9
Packit 90a5c9
/**
Packit 90a5c9
 * Set the push policy for the given request. Takes request headers into 
Packit 90a5c9
 * account, see draft https://tools.ietf.org/html/draft-ruellan-http-accept-push-policy-00
Packit 90a5c9
 * for details.
Packit 90a5c9
 * 
Packit 90a5c9
 * @param headers the http headers to inspect
Packit 90a5c9
 * @param p the pool to use
Packit 90a5c9
 * @param push_enabled if HTTP/2 server push is generally enabled for this request
Packit 90a5c9
 * @return the push policy desired
Packit 90a5c9
 */
Packit 90a5c9
int h2_push_policy_determine(apr_table_t *headers, apr_pool_t *p, int push_enabled);
Packit 90a5c9
Packit 90a5c9
/*******************************************************************************
Packit 90a5c9
 * base64 url encoding, different table from normal base64
Packit 90a5c9
 ******************************************************************************/
Packit 90a5c9
/**
Packit 90a5c9
 * I always wanted to write my own base64url decoder...not. See 
Packit 90a5c9
 * https://tools.ietf.org/html/rfc4648#section-5 for description.
Packit 90a5c9
 */
Packit 90a5c9
apr_size_t h2_util_base64url_decode(const char **decoded, 
Packit 90a5c9
                                    const char *encoded, 
Packit 90a5c9
                                    apr_pool_t *pool);
Packit 90a5c9
const char *h2_util_base64url_encode(const char *data, 
Packit 90a5c9
                                     apr_size_t len, apr_pool_t *pool);
Packit 90a5c9
Packit 90a5c9
/*******************************************************************************
Packit 90a5c9
 * nghttp2 helpers
Packit 90a5c9
 ******************************************************************************/
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
#define H2_CREATE_NV_LIT_CS(nv, NAME, VALUE) nv->name = (uint8_t *)NAME;      \
Packit 90a5c9
                                             nv->namelen = sizeof(NAME) - 1;  \
Packit 90a5c9
                                             nv->value = (uint8_t *)VALUE;    \
Packit 90a5c9
                                             nv->valuelen = strlen(VALUE)
Packit 90a5c9
Packit 90a5c9
#define H2_CREATE_NV_CS_LIT(nv, NAME, VALUE) nv->name = (uint8_t *)NAME;      \
Packit 90a5c9
                                             nv->namelen = strlen(NAME);      \
Packit 90a5c9
                                             nv->value = (uint8_t *)VALUE;    \
Packit 90a5c9
                                             nv->valuelen = sizeof(VALUE) - 1
Packit 90a5c9
Packit 90a5c9
#define H2_CREATE_NV_CS_CS(nv, NAME, VALUE) nv->name = (uint8_t *)NAME;       \
Packit 90a5c9
                                            nv->namelen = strlen(NAME);       \
Packit 90a5c9
                                            nv->value = (uint8_t *)VALUE;     \
Packit 90a5c9
                                            nv->valuelen = strlen(VALUE)
Packit 90a5c9
Packit 90a5c9
int h2_util_ignore_header(const char *name);
Packit 90a5c9
Packit 90a5c9
struct h2_headers;
Packit 90a5c9
Packit 90a5c9
typedef struct h2_ngheader {
Packit 90a5c9
    nghttp2_nv *nv;
Packit 90a5c9
    apr_size_t nvlen;
Packit 90a5c9
} h2_ngheader;
Packit 90a5c9
Packit 90a5c9
apr_status_t h2_res_create_ngtrailer(h2_ngheader **ph, apr_pool_t *p, 
Packit 90a5c9
                                     struct h2_headers *headers); 
Packit 90a5c9
apr_status_t h2_res_create_ngheader(h2_ngheader **ph, apr_pool_t *p, 
Packit 90a5c9
                                    struct h2_headers *headers); 
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
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
/*******************************************************************************
Packit 90a5c9
 * h2_request helpers
Packit 90a5c9
 ******************************************************************************/
Packit 90a5c9
Packit 90a5c9
struct 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,
Packit 90a5c9
                                 int serialize);
Packit 90a5c9
Packit 90a5c9
/*******************************************************************************
Packit 90a5c9
 * apr brigade helpers
Packit 90a5c9
 ******************************************************************************/
Packit 90a5c9
Packit 90a5c9
/**
Packit 90a5c9
 * Concatenate at most length bytes from src to dest brigade, splitting
Packit 90a5c9
 * buckets if necessary and reading buckets of indeterminate length.
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
/**
Packit 90a5c9
 * Copy at most length bytes from src to dest brigade, splitting
Packit 90a5c9
 * buckets if necessary and reading buckets of indeterminate length.
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
/**
Packit 90a5c9
 * Return != 0 iff there is a FLUSH or EOS bucket in the brigade.
Packit 90a5c9
 * @param bb the brigade to check on
Packit 90a5c9
 * @return != 0 iff brigade holds FLUSH or EOS bucket (or both)
Packit 90a5c9
 */
Packit 90a5c9
int h2_util_has_eos(apr_bucket_brigade *bb, apr_off_t len);
Packit 90a5c9
Packit 90a5c9
/**
Packit 90a5c9
 * Check how many bytes of the desired amount are available and if the
Packit 90a5c9
 * end of stream is reached by that amount.
Packit 90a5c9
 * @param bb the brigade to check
Packit 90a5c9
 * @param plen the desired length and, on return, the available length
Packit 90a5c9
 * @param on return, if eos has been reached
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
typedef apr_status_t h2_util_pass_cb(void *ctx, 
Packit 90a5c9
                                     const char *data, apr_off_t len);
Packit 90a5c9
Packit 90a5c9
/**
Packit 90a5c9
 * Read at most *plen bytes from the brigade and pass them into the
Packit 90a5c9
 * given callback. If cb is NULL, just return the amount of data that
Packit 90a5c9
 * could have been read.
Packit 90a5c9
 * If an EOS was/would be encountered, set *peos != 0.
Packit 90a5c9
 * @param bb the brigade to read from
Packit 90a5c9
 * @param cb the callback to invoke for the read data
Packit 90a5c9
 * @param ctx optional data passed to callback
Packit 90a5c9
 * @param plen inout, as input gives the maximum number of bytes to read,
Packit 90a5c9
 *    on return specifies the actual/would be number of bytes
Packit 90a5c9
 * @param peos != 0 iff an EOS bucket was/would be encountered.
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
/**
Packit 90a5c9
 * Print a bucket's meta data (type and length) to the buffer.
Packit 90a5c9
 * @return number of characters printed
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
/**
Packit 90a5c9
 * Prints the brigade bucket types and lengths into the given buffer
Packit 90a5c9
 * up to bmax.
Packit 90a5c9
 * @return number of characters printed
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
 * Logs the bucket brigade (which bucket types with what length)
Packit 90a5c9
 * to the log at the given level.
Packit 90a5c9
 * @param c the connection to log for
Packit 90a5c9
 * @param sid the stream identifier this brigade belongs to
Packit 90a5c9
 * @param level the log level (as in APLOG_*)
Packit 90a5c9
 * @param tag a short message text about the context
Packit 90a5c9
 * @param bb the brigade to log
Packit 90a5c9
 */
Packit 90a5c9
#define h2_util_bb_log(c, sid, level, tag, bb) \
Packit 90a5c9
do { \
Packit 90a5c9
    char buffer[4 * 1024]; \
Packit 90a5c9
    const char *line = "(null)"; \
Packit 90a5c9
    apr_size_t len, bmax = sizeof(buffer)/sizeof(buffer[0]); \
Packit 90a5c9
    len = h2_util_bb_print(buffer, bmax, (tag), "", (bb)); \
Packit 90a5c9
    ap_log_cerror(APLOG_MARK, level, 0, (c), "bb_dump(%ld): %s", \
Packit 90a5c9
        ((c)->master? (c)->master->id : (c)->id), (len? buffer : line)); \
Packit 90a5c9
} while(0)
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
typedef int h2_bucket_gate(apr_bucket *b);
Packit 90a5c9
/**
Packit 90a5c9
 * Transfer buckets from one brigade to another with a limit on the 
Packit 90a5c9
 * maximum amount of bytes transferred. Does no setaside magic, lifetime
Packit 90a5c9
 * of brigades must fit. 
Packit 90a5c9
 * @param to   brigade to transfer buckets to
Packit 90a5c9
 * @param from brigades to remove buckets from
Packit 90a5c9
 * @param plen maximum bytes to transfer, actual bytes transferred
Packit 90a5c9
 * @param peos if an EOS bucket was transferred
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
/**
Packit 90a5c9
 * Get an approximnation of the memory footprint of the given
Packit 90a5c9
 * brigade. This varies from apr_brigade_length as
Packit 90a5c9
 * - no buckets are ever read
Packit 90a5c9
 * - only buckets known to allocate memory (HEAP+POOL) are counted
Packit 90a5c9
 * - the bucket struct itself is counted
Packit 90a5c9
 */
Packit 90a5c9
apr_off_t h2_brigade_mem_size(apr_bucket_brigade *bb);
Packit 90a5c9
Packit 90a5c9
#endif /* defined(__mod_h2__h2_util__) */