454 lines
11 KiB
C++
454 lines
11 KiB
C++
/*************************************************************************
|
|
> File Name: http2_common.cpp
|
|
> Author:
|
|
> Mail:
|
|
> Created Time: 2018年09月21日 星期五 13时59分03秒
|
|
************************************************************************/
|
|
|
|
#include <iostream>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdint.h>
|
|
|
|
#include <tfe_utils.h>
|
|
#include <tfe_stream.h>
|
|
#include <event2/buffer.h>
|
|
|
|
#include <http2_common.h>
|
|
|
|
RTLogInit2Data logging_sc_lid = {
|
|
.run_log_level = 1,
|
|
};
|
|
|
|
RTLogInit2Data *logger()
|
|
{
|
|
return &logging_sc_lid;
|
|
};
|
|
|
|
Http2Plugin g_http2_plugin = {
|
|
|
|
};
|
|
|
|
Http2Plugin *http2_plugin()
|
|
{
|
|
return &g_http2_plugin;
|
|
}
|
|
|
|
int
|
|
http2_header_str_to_val(const char *str, size_t slen, const char * map[], unsigned int map_size)
|
|
{
|
|
size_t normlen = 0;
|
|
for (unsigned int i = 2; i < map_size; i++)
|
|
{
|
|
normlen = strlen(map[i]);
|
|
if ( (slen == normlen) && !strncasecmp(str, map[i], normlen))
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
|
|
// in http [TFE_HTTP_UNKNOWN_FIELD] = NULL; [TFE_HTTP_HOST] = "Host",
|
|
// in http2 [TFE_HTTP_UNKNOWN_FIELD] = "unknown"; [TFE_HTTP_HOST] = ":authority"
|
|
normlen = strlen(":authority");
|
|
if ( (slen == normlen) && !strncasecmp(str, ":authority", normlen))
|
|
{
|
|
return TFE_HTTP_HOST;
|
|
} else {
|
|
return TFE_HTTP_UNKNOWN_FIELD;
|
|
}
|
|
}
|
|
|
|
const char*
|
|
http2_header_val_to_str(unsigned int val, const char * map[], unsigned int map_size)
|
|
{
|
|
const static char * host = ":authority";
|
|
const static char * unknown = "unknown";
|
|
|
|
if (val < map_size && val != TFE_HTTP_HOST && val != TFE_HTTP_UNKNOWN_FIELD)
|
|
{
|
|
return map[val];
|
|
}
|
|
|
|
// in http [TFE_HTTP_UNKNOWN_FIELD] = NULL; [TFE_HTTP_HOST] = "Host",
|
|
// in http2 [TFE_HTTP_UNKNOWN_FIELD] = "unknown"; [TFE_HTTP_HOST] = ":authority"
|
|
if (val == TFE_HTTP_HOST)
|
|
{
|
|
return host;
|
|
}
|
|
else
|
|
{
|
|
return unknown;
|
|
}
|
|
}
|
|
|
|
const char *
|
|
try_val_to_str_idx(const unsigned int val, const struct value_string *vs, int *idx)
|
|
{
|
|
int i = 0;
|
|
if (idx == NULL){
|
|
goto finish;
|
|
}
|
|
|
|
if(vs) {
|
|
while (vs[i].strptr) {
|
|
if (vs[i].value == val) {
|
|
*idx = i;
|
|
return(vs[i].strptr);
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
|
|
finish:
|
|
*idx = -1;
|
|
return NULL;
|
|
}
|
|
|
|
/* Find the index of a string in a value_string, or -1 when not present */
|
|
int
|
|
str_to_val_idx(const char *val, const struct value_string *vs)
|
|
{
|
|
int i = 0;
|
|
|
|
if(vs) {
|
|
while (vs[i].strptr) {
|
|
if (strcmp(vs[i].strptr, val) == 0) {
|
|
return i;
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
const char*
|
|
val_to_str(unsigned int val, const struct value_string *vs)
|
|
{
|
|
int ignore_me;
|
|
|
|
return try_val_to_str_idx(val, vs, &ignore_me);
|
|
}
|
|
|
|
int
|
|
str_to_val(const char *val, const struct value_string *vs)
|
|
{
|
|
return str_to_val_idx(val, vs);
|
|
}
|
|
|
|
int inflate_init(struct z_stream_st **strm, int gzip)
|
|
{
|
|
if (*strm != NULL)
|
|
return Z_OK;
|
|
|
|
*strm = ALLOC(struct z_stream_st, 1);
|
|
assert(*strm);
|
|
|
|
/* ZSTREAM */
|
|
(*strm)->zst.zalloc = NULL;
|
|
(*strm)->zst.zfree = NULL;
|
|
(*strm)->zst.opaque = NULL;
|
|
(*strm)->zst.avail_in = 0;
|
|
(*strm)->zst.next_in = Z_NULL;
|
|
|
|
// Z_OK stand for 0; Z_ERRNO stand for -1.
|
|
int ret = Z_ERRNO;
|
|
if (gzip == HTTP2_CONTENT_ENCODING_GZIP)
|
|
ret = inflateInit2(&((*strm)->zst), MAX_WBITS + 16);
|
|
else if (gzip == HTTP2_CONTENT_ENCODING_DEFLATE)
|
|
ret = inflateInit2(&((*strm)->zst), -MAX_WBITS);
|
|
else if (gzip == HTTP2_CONTENT_ENCODING_BR){
|
|
(*strm)->brdec_state = BrotliDecoderCreateInstance(NULL, NULL, NULL);
|
|
if ((*strm)->brdec_state != NULL)
|
|
ret = Z_OK;
|
|
}
|
|
|
|
if (ret != Z_OK)
|
|
FREE(strm);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int inflate_br_read(struct z_stream_st **strm, const uint8_t *source, int len,
|
|
char **dest, int *outlen)
|
|
{
|
|
#define CHUNK (1024 * 1024 * 4)
|
|
unsigned char out[CHUNK];
|
|
int totalsize = 0 ,ret = -1;
|
|
size_t available_out;
|
|
unsigned char * next_out;
|
|
|
|
size_t available_in = len;
|
|
const unsigned char * next_in = source;
|
|
|
|
for ( ; ; ){
|
|
available_out = CHUNK;
|
|
next_out = out;
|
|
|
|
ret = BrotliDecoderDecompressStream((*strm)->brdec_state, &available_in, &next_in,
|
|
&available_out, &next_out, 0);
|
|
|
|
size_t have = CHUNK - available_out;
|
|
if (have > 0){
|
|
totalsize += have;
|
|
*dest = (char *)realloc(*dest,totalsize);
|
|
memcpy(*dest + totalsize - have, out, have);
|
|
*outlen = have;
|
|
}
|
|
|
|
if (ret == BROTLI_DECODER_RESULT_SUCCESS || ret == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT){
|
|
ret = 1;
|
|
goto finish;
|
|
}
|
|
|
|
if (ret == BROTLI_DECODER_RESULT_ERROR){
|
|
ret = -1;
|
|
goto finish;
|
|
}
|
|
assert(ret == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT);
|
|
}
|
|
finish:
|
|
return ret;
|
|
}
|
|
|
|
static int inflate_gzip_read(struct z_stream_st **strm, char **dest, int *outlen)
|
|
{
|
|
#define CHUNK (1024 * 1024 * 4)
|
|
int ret = -1;
|
|
unsigned have;
|
|
unsigned char out[CHUNK];
|
|
int totalsize = 0;
|
|
|
|
/* run inflate() on input until output buffer not full */
|
|
do {
|
|
(*strm)->zst.avail_out = CHUNK;
|
|
(*strm)->zst.next_out = out;
|
|
ret = inflate(&((*strm)->zst), Z_NO_FLUSH);
|
|
switch (ret) {
|
|
case Z_STREAM_ERROR:
|
|
ret = Z_STREAM_ERROR;
|
|
case Z_NEED_DICT:
|
|
ret = Z_DATA_ERROR; /* and fall through */
|
|
case Z_DATA_ERROR:
|
|
case Z_MEM_ERROR:
|
|
inflateEnd(&((*strm)->zst));
|
|
return ret;
|
|
}
|
|
have = CHUNK - (*strm)->zst.avail_out;
|
|
totalsize += have;
|
|
*dest = (char *)realloc(*dest,totalsize);
|
|
memcpy(*dest + totalsize - have,out,have);
|
|
*outlen = have;
|
|
} while ((*strm)->zst.avail_out == 0);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int inflate_read(const uint8_t *source,int len,char **dest, int *outlen,
|
|
struct z_stream_st **strm, int encode)
|
|
{
|
|
int ret = -1;
|
|
|
|
ret = inflate_init(strm, encode);
|
|
if (ret != Z_OK){
|
|
return ret;
|
|
}
|
|
|
|
if (encode == HTTP2_CONTENT_ENCODING_GZIP ||
|
|
encode == HTTP2_CONTENT_ENCODING_DEFLATE){
|
|
(*strm)->zst.avail_in = len;
|
|
(*strm)->zst.next_in = (Bytef *)source;
|
|
ret = inflate_gzip_read(strm, dest, outlen);
|
|
}
|
|
if (encode == HTTP2_CONTENT_ENCODING_BR){
|
|
ret = inflate_br_read(strm, source, len, dest, outlen);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int deflate_init(struct z_stream_st **strm, int gzip)
|
|
{
|
|
if (*strm != NULL)
|
|
return Z_OK;
|
|
|
|
int ret = 0; // 0 stand for Z_OK
|
|
|
|
*strm = ALLOC(struct z_stream_st, 1);
|
|
assert(*strm);
|
|
|
|
if (gzip == HTTP2_CONTENT_ENCODING_GZIP ||
|
|
gzip == HTTP2_CONTENT_ENCODING_DEFLATE){
|
|
(*strm)->zst.zalloc = (alloc_func)0;
|
|
(*strm)->zst.zfree = (free_func)0;
|
|
(*strm)->zst.opaque = (voidpf)0;
|
|
(*strm)->zst.avail_in = 0;
|
|
(*strm)->zst.next_in = Z_NULL;
|
|
|
|
int wbits = 0;
|
|
if (gzip == HTTP2_CONTENT_ENCODING_GZIP){
|
|
wbits = MAX_WBITS + 16;
|
|
}
|
|
if (gzip == HTTP2_CONTENT_ENCODING_DEFLATE){
|
|
wbits = -MAX_WBITS;
|
|
}
|
|
ret = deflateInit2(&((*strm)->zst), Z_DEFAULT_COMPRESSION,
|
|
Z_DEFLATED, wbits, 8, Z_DEFAULT_STRATEGY);
|
|
|
|
}
|
|
if (gzip == HTTP2_CONTENT_ENCODING_BR){
|
|
(*strm)->brenc_state = BrotliEncoderCreateInstance(NULL, NULL, NULL);
|
|
if ( (*strm)->brenc_state == NULL)
|
|
ret = -1;
|
|
}
|
|
if (ret != Z_OK)
|
|
FREE(strm);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int deflate_br_write(struct z_stream_st **strm,
|
|
const unsigned char * source, size_t slen,
|
|
struct evbuffer * evbuf, int end)
|
|
{
|
|
struct evbuffer_iovec v[1];
|
|
|
|
size_t __sz_reserve_chunk = slen > 8192 ? slen : 8192;
|
|
int iov_count = evbuffer_reserve_space(evbuf, __sz_reserve_chunk, v, 1);
|
|
if (iov_count != 1) return -1;
|
|
|
|
const unsigned char * next_in = source;
|
|
size_t avail_in = slen;
|
|
|
|
unsigned char * next_out = (unsigned char *)v[0].iov_base;
|
|
size_t avail_out = v[0].iov_len;
|
|
|
|
enum BrotliEncoderOperation op = end ? BROTLI_OPERATION_FINISH : BROTLI_OPERATION_PROCESS;
|
|
int ret = 0;
|
|
do
|
|
{
|
|
ret = BrotliEncoderCompressStream((*strm)->brenc_state, op,
|
|
&avail_in, &next_in, &avail_out, &next_out, NULL);
|
|
|
|
if(unlikely(ret == BROTLI_FALSE)){
|
|
return ret;
|
|
}
|
|
|
|
if (avail_out == 0 || avail_in == 0)
|
|
{
|
|
v[0].iov_len = v[0].iov_len - avail_out;
|
|
ret = evbuffer_commit_space(evbuf, v, iov_count);
|
|
if(ret < 0)
|
|
return -2;
|
|
|
|
if(avail_out == 0){
|
|
iov_count = evbuffer_reserve_space(evbuf, __sz_reserve_chunk, v, 1);
|
|
if(unlikely(iov_count != 1))
|
|
return -3;
|
|
|
|
next_out = (unsigned char *) v[0].iov_base;
|
|
avail_out = (unsigned int) v[0].iov_len;
|
|
}
|
|
}
|
|
}
|
|
while (avail_in > 0);
|
|
return 0;
|
|
|
|
}
|
|
|
|
static int defalta_gzip_write(struct z_stream_st **strm, const uint8_t *source, int slen,
|
|
struct evbuffer * evbuf, int end)
|
|
{
|
|
#define SZ_IOVEC 2
|
|
int ret = 0;
|
|
unsigned int i = 0;
|
|
struct evbuffer_iovec io[SZ_IOVEC];
|
|
|
|
size_t max = slen > 8192 ? slen : 8192;
|
|
int iov_count = evbuffer_reserve_space(evbuf, max, io, SZ_IOVEC);
|
|
if (iov_count < 1 || iov_count > SZ_IOVEC)
|
|
return -1;
|
|
|
|
(*strm)->zst.next_in = (unsigned char *) source;
|
|
(*strm)->zst.avail_in = (unsigned int) slen;
|
|
(*strm)->zst.next_out = (unsigned char *) io[i].iov_base;
|
|
(*strm)->zst.avail_out = (unsigned int) io[i].iov_len;
|
|
|
|
int flush = end ? Z_FINISH : Z_NO_FLUSH;
|
|
do
|
|
{
|
|
ret = deflate(&((*strm)->zst), flush);
|
|
assert(ret != Z_STREAM_ERROR);
|
|
assert(i < SZ_IOVEC);
|
|
|
|
if ((*strm)->zst.avail_out == 0 || (*strm)->zst.avail_in == 0)
|
|
{
|
|
unsigned int len = (unsigned int) io[i].iov_len - (*strm)->zst.avail_out;
|
|
io[i].iov_len = (size_t) len;
|
|
|
|
i++;
|
|
(*strm)->zst.next_out = (unsigned char *) io[i].iov_base;
|
|
(*strm)->zst.avail_out = (unsigned int) io[i].iov_len;
|
|
}
|
|
} while ((*strm)->zst.avail_in > 0);
|
|
|
|
assert(end == 0 || ret == Z_STREAM_END);
|
|
|
|
(void)ret;
|
|
return evbuffer_commit_space(evbuf, io, iov_count);
|
|
}
|
|
|
|
int deflate_write(struct z_stream_st **strm, const uint8_t *source,
|
|
int slen, struct evbuffer * evbuf, int gzip, int end)
|
|
{
|
|
int ret = 0;
|
|
|
|
ret = deflate_init(strm, gzip);
|
|
if (ret != Z_OK){
|
|
return ret;
|
|
}
|
|
|
|
if (gzip == HTTP2_CONTENT_ENCODING_GZIP ||
|
|
gzip == HTTP2_CONTENT_ENCODING_DEFLATE){
|
|
ret = defalta_gzip_write(strm, source, slen, evbuf, end);
|
|
}
|
|
if (gzip == HTTP2_CONTENT_ENCODING_BR){
|
|
ret = deflate_br_write(strm, source, slen, evbuf, end);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
void inflate_finished(struct z_stream_st **strm)
|
|
{
|
|
if (*strm != NULL){
|
|
if ((*strm)->brdec_state)
|
|
{
|
|
BrotliDecoderDestroyInstance((*strm)->brdec_state);
|
|
(*strm)->brdec_state = NULL;
|
|
goto finish;
|
|
}
|
|
(void)inflateEnd(&((*strm)->zst));
|
|
finish:
|
|
free(*strm);
|
|
*strm = NULL;
|
|
}
|
|
}
|
|
void deflate_finished(struct z_stream_st **strm)
|
|
{
|
|
if (*strm != NULL)
|
|
{
|
|
if ((*strm)->brenc_state)
|
|
{
|
|
BrotliEncoderDestroyInstance((*strm)->brenc_state);
|
|
(*strm)->brenc_state = NULL;
|
|
goto finish;
|
|
|
|
}
|
|
(void) deflateEnd(&((*strm)->zst));
|
|
finish:
|
|
free(*strm);
|
|
*strm = NULL;
|
|
}
|
|
}
|
|
|