TSG-20527 http2解析层支持zstd编解码
This commit is contained in:
@@ -136,43 +136,97 @@ 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)
|
||||
static int gzip_decompress_init(struct http2_codec_ctx **codec_ctx, int encode)
|
||||
{
|
||||
if (*strm != NULL)
|
||||
if (*codec_ctx != NULL)
|
||||
{
|
||||
return Z_OK;
|
||||
|
||||
*strm = ALLOC(struct z_stream_st, 1);
|
||||
assert(*strm);
|
||||
|
||||
}
|
||||
|
||||
*codec_ctx = ALLOC(struct http2_codec_ctx, 1);
|
||||
if(*codec_ctx == NULL)
|
||||
{
|
||||
*codec_ctx=NULL;
|
||||
return -1;
|
||||
}
|
||||
/* ZSTREAM */
|
||||
(*strm)->zst.zalloc = NULL;
|
||||
(*strm)->zst.zfree = NULL;
|
||||
(*strm)->zst.opaque = NULL;
|
||||
(*strm)->zst.avail_in = 0;
|
||||
(*strm)->zst.next_in = Z_NULL;
|
||||
(*codec_ctx)->zst.zalloc = NULL;
|
||||
(*codec_ctx)->zst.zfree = NULL;
|
||||
(*codec_ctx)->zst.opaque = NULL;
|
||||
(*codec_ctx)->zst.avail_in = 0;
|
||||
(*codec_ctx)->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 (encode == HTTP2_CONTENT_ENCODING_GZIP)
|
||||
{
|
||||
ret = inflateInit2(&((*codec_ctx)->zst), MAX_WBITS + 16);
|
||||
}
|
||||
if (encode == HTTP2_CONTENT_ENCODING_DEFLATE)
|
||||
{
|
||||
ret = inflateInit2(&((*codec_ctx)->zst), -MAX_WBITS);
|
||||
}
|
||||
|
||||
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)
|
||||
static int gzip_decompress_decode(struct http2_codec_ctx **strm, char **dest, int *outlen)
|
||||
{
|
||||
#define CHUNK (1024 * 1024 * 4)
|
||||
#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;
|
||||
}
|
||||
|
||||
static int brotli_decompress_init(struct http2_codec_ctx **codec_ctx)
|
||||
{
|
||||
int ret = Z_ERRNO;
|
||||
|
||||
if (*codec_ctx != NULL)
|
||||
{
|
||||
return Z_OK;
|
||||
}
|
||||
|
||||
*codec_ctx = ALLOC(struct http2_codec_ctx, 1);
|
||||
if(*codec_ctx == NULL)
|
||||
{
|
||||
*codec_ctx=NULL;
|
||||
return -1;
|
||||
}
|
||||
(*codec_ctx)->brdec_state = BrotliDecoderCreateInstance(NULL, NULL, NULL);
|
||||
if ((*codec_ctx)->brdec_state != NULL)
|
||||
{
|
||||
return Z_OK;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int brotli_decompress_decode(struct http2_codec_ctx **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;
|
||||
@@ -211,109 +265,171 @@ finish:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int inflate_gzip_read(struct z_stream_st **strm, char **dest, int *outlen)
|
||||
static int zstd_decompress_init(struct http2_codec_ctx **codec_ctx)
|
||||
{
|
||||
#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)
|
||||
int ret = Z_ERRNO;
|
||||
|
||||
if (*codec_ctx != 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;
|
||||
|
||||
BrotliEncoderSetParameter((*strm)->brenc_state, BROTLI_PARAM_QUALITY, 3);
|
||||
|
||||
*codec_ctx = ALLOC(struct http2_codec_ctx, 1);
|
||||
if(*codec_ctx == NULL)
|
||||
{
|
||||
*codec_ctx=NULL;
|
||||
return -1;
|
||||
}
|
||||
(*codec_ctx)->dctx = ZSTD_createDCtx();
|
||||
if((*codec_ctx)->dctx != NULL)
|
||||
{
|
||||
ret = Z_OK;
|
||||
}
|
||||
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)
|
||||
static int zstd_decompress_decode(struct http2_codec_ctx **strm, const uint8_t *source, int len, char **dest, int *outlen)
|
||||
{
|
||||
struct evbuffer_iovec v[1];
|
||||
int chunk_sz = 1024 * 1024 * 4;
|
||||
unsigned char out[chunk_sz];
|
||||
int totalsize = 0 ,ret = -1;
|
||||
size_t available_out;
|
||||
unsigned char * next_out=NULL;
|
||||
|
||||
size_t available_in = len;
|
||||
const unsigned char * next_in = source;
|
||||
|
||||
ZSTD_inBuffer input = {next_in, available_in, 0 };
|
||||
for ( ; ; ){
|
||||
available_out = CHUNK;
|
||||
next_out = out;
|
||||
ZSTD_outBuffer output = {next_out, available_out, 0 };
|
||||
|
||||
ret = ZSTD_decompressStream((*strm)->dctx, &output, &input);
|
||||
//printf("error name = %s\n", ZSTD_getErrorName(ret));
|
||||
|
||||
size_t have = CHUNK - (output.size - output.pos);
|
||||
if (have > 0)
|
||||
{
|
||||
totalsize += have;
|
||||
*dest = (char *)realloc(*dest,totalsize);
|
||||
memcpy(*dest + totalsize - have, out, have);
|
||||
*outlen = have;
|
||||
}
|
||||
if(ret >= 0)
|
||||
{
|
||||
ret=1;
|
||||
goto finish;
|
||||
}
|
||||
if(ret < 0)
|
||||
{
|
||||
ret = -1;
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
finish:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int gzip_compress_init(struct http2_codec_ctx **codec_ctx, int encode)
|
||||
{
|
||||
if (*codec_ctx != NULL)
|
||||
{
|
||||
return Z_OK;
|
||||
}
|
||||
|
||||
*codec_ctx = ALLOC(struct http2_codec_ctx, 1);
|
||||
if(*codec_ctx == NULL)
|
||||
{
|
||||
*codec_ctx=NULL;
|
||||
return -1;
|
||||
}
|
||||
(*codec_ctx)->zst.zalloc = (alloc_func)0;
|
||||
(*codec_ctx)->zst.zfree = (free_func)0;
|
||||
(*codec_ctx)->zst.opaque = (voidpf)0;
|
||||
(*codec_ctx)->zst.avail_in = 0;
|
||||
(*codec_ctx)->zst.next_in = Z_NULL;
|
||||
|
||||
int wbits = 0;
|
||||
if (encode == HTTP2_CONTENT_ENCODING_GZIP)
|
||||
{
|
||||
wbits = MAX_WBITS + 16;
|
||||
}
|
||||
if (encode == HTTP2_CONTENT_ENCODING_DEFLATE)
|
||||
{
|
||||
wbits = -MAX_WBITS;
|
||||
}
|
||||
return deflateInit2(&((*codec_ctx)->zst), Z_DEFAULT_COMPRESSION, Z_DEFLATED, wbits, 8, Z_DEFAULT_STRATEGY);
|
||||
}
|
||||
|
||||
static int gzip_compress_encode(struct http2_codec_ctx **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);
|
||||
}
|
||||
|
||||
static int brotli_compress_init(struct http2_codec_ctx **codec_ctx)
|
||||
{
|
||||
if (*codec_ctx != NULL)
|
||||
{
|
||||
return Z_OK;
|
||||
}
|
||||
|
||||
*codec_ctx = ALLOC(struct http2_codec_ctx, 1);
|
||||
if(*codec_ctx == NULL)
|
||||
{
|
||||
*codec_ctx=NULL;
|
||||
return -1;
|
||||
}
|
||||
(*codec_ctx)->brenc_state = BrotliEncoderCreateInstance(NULL, NULL, NULL);
|
||||
if ((*codec_ctx)->brenc_state == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
BrotliEncoderSetParameter((*codec_ctx)->brenc_state, BROTLI_PARAM_QUALITY, 3);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int brotli_compress_encode(struct http2_codec_ctx **strm, const uint8_t *source, int 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;
|
||||
@@ -351,105 +467,247 @@ static int deflate_br_write(struct z_stream_st **strm,
|
||||
avail_out = (unsigned int) v[0].iov_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (avail_in > 0);
|
||||
}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)
|
||||
static int zstd_compress_init(struct http2_codec_ctx **codec_ctx)
|
||||
{
|
||||
#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
|
||||
if (*codec_ctx != NULL)
|
||||
{
|
||||
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);
|
||||
return Z_OK;
|
||||
}
|
||||
|
||||
*codec_ctx = ALLOC(struct http2_codec_ctx, 1);
|
||||
if(*codec_ctx == NULL)
|
||||
{
|
||||
*codec_ctx=NULL;
|
||||
return -1;
|
||||
}
|
||||
(*codec_ctx)->cctx = ZSTD_createCCtx();
|
||||
if((*codec_ctx)->cctx == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
ZSTD_CCtx_setParameter((*codec_ctx)->cctx, ZSTD_c_compressionLevel, 1);
|
||||
ZSTD_CCtx_setParameter((*codec_ctx)->cctx, ZSTD_c_checksumFlag, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int deflate_write(struct z_stream_st **strm, const uint8_t *source,
|
||||
int slen, struct evbuffer * evbuf, int gzip, int end)
|
||||
static int zstd_compress_encode(struct http2_codec_ctx **strm, const uint8_t *source, int slen, struct evbuffer * evbuf, int end)
|
||||
{
|
||||
int ret = 0;
|
||||
size_t toRead = 0;
|
||||
struct evbuffer_iovec v[1] = {0};
|
||||
ZSTD_outBuffer output = {0};
|
||||
const unsigned char *next_in = NULL;
|
||||
size_t remaining=0;
|
||||
|
||||
ret = deflate_init(strm, gzip);
|
||||
if (ret != Z_OK){
|
||||
return ret;
|
||||
size_t const buffInSize = slen;
|
||||
size_t const buffOutSize = ZSTD_CStreamOutSize();
|
||||
|
||||
//printf("slen = %d\n", slen);
|
||||
size_t __sz_reserve_chunk = (size_t)slen > buffOutSize ? (size_t)slen : buffOutSize;
|
||||
|
||||
int iov_count = evbuffer_reserve_space(evbuf, __sz_reserve_chunk, v, 1);
|
||||
if (iov_count != 1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
unsigned char * next_out = (unsigned char *)v[0].iov_base;
|
||||
size_t avail_out = v[0].iov_len;
|
||||
output = (ZSTD_outBuffer){next_out, avail_out, 0};
|
||||
|
||||
ZSTD_EndDirective const mode = end ? ZSTD_e_end : ZSTD_e_continue;
|
||||
//ZSTD_EndDirective const mode = end ? ZSTD_e_flush : ZSTD_e_continue;
|
||||
if (source != NULL)
|
||||
{
|
||||
next_in = source;
|
||||
while (next_in < source + slen)
|
||||
{
|
||||
toRead = (next_in + buffInSize < source + slen) ? buffInSize : (source + slen - next_in);
|
||||
ZSTD_inBuffer input = {next_in, toRead, 0};
|
||||
|
||||
if (output.pos == output.size && output.pos != 0 && output.size != 0)
|
||||
{
|
||||
if (evbuffer_reserve_space(evbuf, __sz_reserve_chunk, v, 1) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
next_out = (unsigned char *)v[0].iov_base;
|
||||
avail_out = v[0].iov_len;
|
||||
output = (ZSTD_outBuffer){next_out, avail_out, 0};
|
||||
}
|
||||
remaining = ZSTD_compressStream2((*strm)->cctx, &output, &input, mode);
|
||||
if (ZSTD_isError(remaining))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (output.pos > 0)
|
||||
{
|
||||
v[0].iov_len = output.pos;
|
||||
if (evbuffer_commit_space(evbuf, v, 1) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
output.pos = 0;
|
||||
}
|
||||
next_in += toRead;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ZSTD_inBuffer input = {source, (size_t)slen, 0};
|
||||
remaining = ZSTD_compressStream2((*strm)->cctx, &output, &input, mode);
|
||||
if (ZSTD_isError(remaining))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (output.pos > 0)
|
||||
{
|
||||
v[0].iov_len = output.pos;
|
||||
if (evbuffer_commit_space(evbuf, v, 1) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int http2_decompress_stream(const uint8_t *source, int len, char **dest, int *outlen, struct http2_codec_ctx **codec_ctx, int encode)
|
||||
{
|
||||
int ret = -1; // Z_OK stand for 0; Z_ERRNO stand for -1.
|
||||
|
||||
switch(encode)
|
||||
{
|
||||
case HTTP2_CONTENT_ENCODING_GZIP:
|
||||
case HTTP2_CONTENT_ENCODING_DEFLATE:
|
||||
ret = gzip_decompress_init(codec_ctx, encode);
|
||||
if(ret != Z_OK)
|
||||
{
|
||||
goto finish;
|
||||
}
|
||||
(*codec_ctx)->zst.avail_in = len;
|
||||
(*codec_ctx)->zst.next_in = (Bytef *)source;
|
||||
ret = gzip_decompress_decode(codec_ctx, dest, outlen);
|
||||
break;
|
||||
case HTTP2_CONTENT_ENCODING_BR:
|
||||
ret = brotli_decompress_init(codec_ctx);
|
||||
if(ret != Z_OK)
|
||||
{
|
||||
goto finish;
|
||||
}
|
||||
ret =brotli_decompress_decode(codec_ctx, source, len, dest, outlen);
|
||||
break;
|
||||
case HTTP2_CONTENT_ENCODING_ZSTD:
|
||||
ret = zstd_decompress_init(codec_ctx);
|
||||
if(ret != Z_OK)
|
||||
{
|
||||
goto finish;
|
||||
}
|
||||
ret = zstd_decompress_decode(codec_ctx, source, len, dest, outlen);;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
finish:
|
||||
if(*codec_ctx)
|
||||
{
|
||||
FREE(codec_ctx);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void inflate_finished(struct z_stream_st **strm)
|
||||
int http2_compress_stream(struct http2_codec_ctx **codec_ctx, const uint8_t *source, int slen, struct evbuffer * evbuf, int encode, int mode)
|
||||
{
|
||||
if (*strm != NULL){
|
||||
if ((*strm)->brdec_state)
|
||||
int ret = -1; // Z_OK stand for 0; Z_ERRNO stand for -1.
|
||||
|
||||
switch(encode)
|
||||
{
|
||||
case HTTP2_CONTENT_ENCODING_GZIP:
|
||||
case HTTP2_CONTENT_ENCODING_DEFLATE:
|
||||
ret = gzip_compress_init(codec_ctx, encode);
|
||||
if(ret != Z_OK)
|
||||
{
|
||||
goto finish;
|
||||
}
|
||||
ret = gzip_compress_encode(codec_ctx, source, slen, evbuf, mode);
|
||||
break;
|
||||
case HTTP2_CONTENT_ENCODING_BR:
|
||||
ret = brotli_compress_init(codec_ctx);
|
||||
if(ret != Z_OK)
|
||||
{
|
||||
goto finish;
|
||||
}
|
||||
ret = brotli_compress_encode(codec_ctx, source, slen, evbuf, mode);
|
||||
break;
|
||||
case HTTP2_CONTENT_ENCODING_ZSTD:
|
||||
ret = zstd_compress_init(codec_ctx);
|
||||
if(ret != Z_OK)
|
||||
{
|
||||
goto finish;
|
||||
}
|
||||
ret = zstd_compress_encode(codec_ctx, source, slen, evbuf, mode);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
|
||||
finish:
|
||||
if(*codec_ctx)
|
||||
{
|
||||
FREE(codec_ctx);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void http2_decompress_finished(struct http2_codec_ctx **codec_ctx)
|
||||
{
|
||||
if (*codec_ctx != NULL)
|
||||
{
|
||||
if ((*codec_ctx)->brdec_state)
|
||||
{
|
||||
BrotliDecoderDestroyInstance((*strm)->brdec_state);
|
||||
(*strm)->brdec_state = NULL;
|
||||
BrotliDecoderDestroyInstance((*codec_ctx)->brdec_state);
|
||||
(*codec_ctx)->brdec_state = NULL;
|
||||
goto finish;
|
||||
}
|
||||
(void)inflateEnd(&((*strm)->zst));
|
||||
if ((*codec_ctx)->dctx)
|
||||
{
|
||||
ZSTD_freeDCtx((*codec_ctx)->dctx);
|
||||
(*codec_ctx)->dctx = NULL;
|
||||
goto finish;
|
||||
}
|
||||
(void)inflateEnd(&((*codec_ctx)->zst));
|
||||
finish:
|
||||
free(*strm);
|
||||
*strm = NULL;
|
||||
free(*codec_ctx);
|
||||
*codec_ctx = NULL;
|
||||
}
|
||||
}
|
||||
void deflate_finished(struct z_stream_st **strm)
|
||||
|
||||
void http2_compress_finished(struct http2_codec_ctx **codec_ctx)
|
||||
{
|
||||
if (*strm != NULL)
|
||||
if (*codec_ctx != NULL)
|
||||
{
|
||||
if ((*strm)->brenc_state)
|
||||
if ((*codec_ctx)->brenc_state)
|
||||
{
|
||||
BrotliEncoderDestroyInstance((*strm)->brenc_state);
|
||||
(*strm)->brenc_state = NULL;
|
||||
BrotliEncoderDestroyInstance((*codec_ctx)->brenc_state);
|
||||
(*codec_ctx)->brenc_state = NULL;
|
||||
goto finish;
|
||||
|
||||
}
|
||||
(void) deflateEnd(&((*strm)->zst));
|
||||
if ((*codec_ctx)->cctx)
|
||||
{
|
||||
ZSTD_freeCCtx((*codec_ctx)->cctx);
|
||||
(*codec_ctx)->cctx = NULL;
|
||||
goto finish;
|
||||
}
|
||||
(void) deflateEnd(&((*codec_ctx)->zst));
|
||||
finish:
|
||||
free(*strm);
|
||||
*strm = NULL;
|
||||
free(*codec_ctx);
|
||||
*codec_ctx = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -142,6 +142,7 @@ const char * method_idx_to_str(int encode)
|
||||
case HTTP2_CONTENT_ENCODING_BZIP2: return "bzip2";
|
||||
case HTTP2_CONTENT_ENCODING_X_BZIP2: return "x-bzip2";
|
||||
case HTTP2_CONTENT_ENCODING_BR: return "br";
|
||||
case HTTP2_CONTENT_ENCODING_ZSTD: return "zstd";
|
||||
default: return "";
|
||||
}
|
||||
}
|
||||
@@ -162,9 +163,13 @@ static int method_to_str_idx(const char * method)
|
||||
|
||||
if (strcasestr(method, "x-bzip2") != NULL)
|
||||
return HTTP2_CONTENT_ENCODING_X_BZIP2;
|
||||
|
||||
if (strcasestr(method, "br") != NULL)
|
||||
return HTTP2_CONTENT_ENCODING_BR;
|
||||
|
||||
if (strcasestr(method, "zstd") != NULL)
|
||||
return HTTP2_CONTENT_ENCODING_ZSTD;
|
||||
|
||||
return HTTP2_CONTENT_ENCODING_NONE;
|
||||
}
|
||||
|
||||
@@ -352,8 +357,8 @@ static int h2_half_ops_append_body(struct tfe_http_half * half, char * buff, siz
|
||||
struct tfe_h2_payload *body = &resp->h2_payload;
|
||||
|
||||
if (buff == NULL || size == 0){
|
||||
if (body->gzip != HTTP2_CONTENT_ENCODING_NONE){
|
||||
xret = deflate_write(&body->deflate, NULL, 0, resp->h2_payload.evbuf_body, body->gzip, 1);
|
||||
if (body->encode_type != HTTP2_CONTENT_ENCODING_NONE){
|
||||
xret = http2_compress_stream(&body->deflate, NULL, 0, resp->h2_payload.evbuf_body, body->encode_type, 1);
|
||||
}
|
||||
resp->message_state = H2_READ_STATE_COMPLETE;
|
||||
goto finish;
|
||||
@@ -363,9 +368,9 @@ static int h2_half_ops_append_body(struct tfe_http_half * half, char * buff, siz
|
||||
resp->h2_payload.evbuf_body = evbuffer_new();
|
||||
}
|
||||
|
||||
if (body->gzip != HTTP2_CONTENT_ENCODING_NONE){
|
||||
xret = deflate_write(&body->deflate, (const uint8_t *)buff, size,
|
||||
resp->h2_payload.evbuf_body, body->gzip, 0);
|
||||
if (body->encode_type != HTTP2_CONTENT_ENCODING_NONE){
|
||||
xret = http2_compress_stream(&body->deflate, (const uint8_t *)buff, size,
|
||||
resp->h2_payload.evbuf_body, body->encode_type, 0);
|
||||
}else{
|
||||
xret = evbuffer_add(resp->h2_payload.evbuf_body, buff, size);
|
||||
}
|
||||
@@ -401,8 +406,8 @@ void delete_stream_half_data(struct tfe_h2_half_private **data,
|
||||
|
||||
struct tfe_h2_payload *body = &((*data)->h2_payload);
|
||||
|
||||
inflate_finished(&body->inflate);
|
||||
deflate_finished(&body->deflate);
|
||||
http2_compress_finished(&body->inflate);
|
||||
http2_decompress_finished(&body->deflate);
|
||||
if (body->evbuf_body && body_flag){
|
||||
evbuffer_free(body->evbuf_body);
|
||||
body->evbuf_body = NULL;
|
||||
@@ -449,13 +454,13 @@ int h2_half_ops_body_begin(struct tfe_http_half * half, int by_stream)
|
||||
if (by_stream)
|
||||
{
|
||||
if (body->inflate){
|
||||
inflate_finished(&body->inflate);
|
||||
http2_compress_finished(&body->inflate);
|
||||
}
|
||||
if (body->deflate){
|
||||
deflate_finished(&body->deflate);
|
||||
http2_decompress_finished(&body->deflate);
|
||||
}
|
||||
|
||||
body->gzip = HTTP2_CONTENT_ENCODING_NONE;
|
||||
body->encode_type = HTTP2_CONTENT_ENCODING_NONE;
|
||||
resp->message_state = H2_READ_STATE_READING;
|
||||
resp->by_stream = by_stream;
|
||||
}
|
||||
@@ -476,10 +481,10 @@ int h2_half_ops_body_data(struct tfe_http_half * h2_response, const unsigned cha
|
||||
struct tfe_h2_half_private * h2_resp_priv = nghttp2_to_half_private(h2_response);
|
||||
struct tfe_h2_payload *body = &h2_resp_priv->h2_payload;
|
||||
|
||||
if (body->gzip != HTTP2_CONTENT_ENCODING_NONE){
|
||||
if (body->encode_type != HTTP2_CONTENT_ENCODING_NONE){
|
||||
|
||||
xret = deflate_write(&body->deflate, (const uint8_t *)data, sz_data,
|
||||
h2_resp_priv->h2_payload.evbuf_body, body->gzip, 0);
|
||||
xret = http2_compress_stream(&body->deflate, (const uint8_t *)data, sz_data,
|
||||
h2_resp_priv->h2_payload.evbuf_body, body->encode_type, 0);
|
||||
}else{
|
||||
xret = evbuffer_add(h2_resp_priv->h2_payload.evbuf_body, data, sz_data);
|
||||
}
|
||||
@@ -583,7 +588,7 @@ static struct tfe_h2_half_private* tfe_half_private_init(enum tfe_http_direction
|
||||
half_private->h2_payload.inflate = NULL;
|
||||
half_private->h2_payload.deflate = NULL;
|
||||
half_private->h2_payload.evbuf_body = evbuffer_new();
|
||||
half_private->h2_payload.gzip = HTTP2_CONTENT_ENCODING_NONE;
|
||||
half_private->h2_payload.encode_type = HTTP2_CONTENT_ENCODING_NONE;
|
||||
half_private->h2_payload.padlen = 0;
|
||||
|
||||
half_private->stream_id = stream_id;
|
||||
@@ -613,7 +618,7 @@ struct tfe_http_half * h2_ops_response_create(struct tfe_http_session * session,
|
||||
resp->method_or_status = resp_code;
|
||||
|
||||
if (stream->resp)
|
||||
resp->h2_payload.gzip = stream->resp->h2_payload.gzip;
|
||||
resp->h2_payload.encode_type = stream->resp->h2_payload.encode_type;
|
||||
|
||||
return &resp->half_public;
|
||||
}
|
||||
@@ -759,10 +764,10 @@ static enum tfe_stream_action http2_frame_submit_built_resp(struct tfe_h2_stream
|
||||
tfe_http_field_write(&pangu_resp->half_public, &cont_field, NULL);
|
||||
tfe_http_field_write(&pangu_resp->half_public, &cont_field, str_sz_evbuf_body);
|
||||
|
||||
if (body->gzip != HTTP2_CONTENT_ENCODING_NONE)
|
||||
if (body->encode_type != HTTP2_CONTENT_ENCODING_NONE)
|
||||
{
|
||||
const static struct http_field_name encoding_field = {TFE_HTTP_CONT_ENCODING, NULL};
|
||||
const char *content_encoding = method_idx_to_str(body->gzip);
|
||||
const char *content_encoding = method_idx_to_str(body->encode_type);
|
||||
tfe_http_field_write(&pangu_resp->half_public, &encoding_field, NULL);
|
||||
tfe_http_field_write(&pangu_resp->half_public, &encoding_field, content_encoding);
|
||||
}
|
||||
@@ -1859,7 +1864,7 @@ static int http2_fill_up_header(nghttp2_session *ngh2_session, const nghttp2_fra
|
||||
}
|
||||
if (field.field_id == TFE_HTTP_CONT_ENCODING)
|
||||
{
|
||||
half->h2_payload.gzip = method_to_str_idx((const char *)value);
|
||||
half->h2_payload.encode_type = method_to_str_idx((const char *)value);
|
||||
}
|
||||
h2_header = &half->header;
|
||||
tfe_h2_header_add_field(h2_header, &field, (const char *)value, 1);
|
||||
@@ -1892,7 +1897,7 @@ static int http2_fill_up_promise(nghttp2_session *ngh2_session, const nghttp2_fr
|
||||
}
|
||||
if (field.field_id == TFE_HTTP_CONT_ENCODING)
|
||||
{
|
||||
resp->h2_payload.gzip = method_to_str_idx((const char *)value);
|
||||
resp->h2_payload.encode_type = method_to_str_idx((const char *)value);
|
||||
}
|
||||
headers = &resp->promised;
|
||||
tfe_h2_header_add_field(headers, &field, (const char *)value, 1);
|
||||
@@ -2062,9 +2067,9 @@ static int http2_client_on_data_chunk_recv(nghttp2_session *session, uint8_t fla
|
||||
}
|
||||
|
||||
evbuffer_add(resp->h2_payload.evbuf_body, input, input_len);
|
||||
if (resp->h2_payload.gzip != HTTP2_CONTENT_ENCODING_NONE)
|
||||
if (resp->h2_payload.encode_type != HTTP2_CONTENT_ENCODING_NONE)
|
||||
{
|
||||
ret = inflate_read(input, input_len, &uncompr, &uncompr_len, &resp->h2_payload.inflate, resp->h2_payload.gzip);
|
||||
ret = http2_decompress_stream(input, input_len, &uncompr, &uncompr_len, &resp->h2_payload.inflate, resp->h2_payload.encode_type);
|
||||
if (((ret == Z_STREAM_END) || (ret == Z_OK)) && uncompr_len > 0)
|
||||
{
|
||||
input = (const uint8_t*)uncompr;
|
||||
@@ -2395,9 +2400,9 @@ static int http2_server_on_data_chunk_recv(nghttp2_session *session, uint8_t fla
|
||||
req->h2_payload.flags = flags;
|
||||
evbuffer_add(req->h2_payload.evbuf_body, input, input_len);
|
||||
|
||||
if (req->h2_payload.gzip != HTTP2_CONTENT_ENCODING_NONE){
|
||||
ret = inflate_read(input, input_len, &uncompr, &uncompr_len,
|
||||
&req->h2_payload.inflate, req->h2_payload.gzip);
|
||||
if (req->h2_payload.encode_type != HTTP2_CONTENT_ENCODING_NONE){
|
||||
ret = http2_decompress_stream(input, input_len, &uncompr, &uncompr_len,
|
||||
&req->h2_payload.inflate, req->h2_payload.encode_type);
|
||||
if (((ret == Z_STREAM_END) || (ret == Z_OK)) && uncompr > 0){
|
||||
input = (const uint8_t*)uncompr;
|
||||
input_len = uncompr_len;
|
||||
|
||||
Reference in New Issue
Block a user