增加对GZIP压缩编码的解压缩功能及单元测试用例
This commit is contained in:
121
plugin/protocol/http/src/http_convert.cpp
Normal file
121
plugin/protocol/http/src/http_convert.cpp
Normal file
@@ -0,0 +1,121 @@
|
||||
#include <zlib.h>
|
||||
#include <http_common.h>
|
||||
#include <http_half.h>
|
||||
#include <http_convert.h>
|
||||
|
||||
struct hf_content_converter
|
||||
{
|
||||
/* MODE AND CALLBACKS */
|
||||
enum hf_content_conv_work_mode mode;
|
||||
unsigned int content_encode;
|
||||
hf_private_cb * data_cb;
|
||||
void * data_cb_user;
|
||||
|
||||
/* ZLIB STREAM */
|
||||
z_stream * z_stream_ptr;
|
||||
unsigned char * chunk;
|
||||
size_t sz_chunk;
|
||||
};
|
||||
|
||||
void hf_content_converter_destroy(struct hf_content_converter * cv_object)
|
||||
{
|
||||
if (cv_object->z_stream_ptr && cv_object->mode == HF_CONTENT_CONV_COMPRASS)
|
||||
{
|
||||
(void)deflateEnd(cv_object->z_stream_ptr);
|
||||
free(cv_object->z_stream_ptr);
|
||||
}
|
||||
|
||||
if (cv_object->z_stream_ptr && cv_object->mode == HF_CONTENT_CONV_UNCOMPRASS)
|
||||
{
|
||||
(void)inflateEnd(cv_object->z_stream_ptr);
|
||||
free(cv_object->z_stream_ptr);
|
||||
}
|
||||
|
||||
cv_object->z_stream_ptr = NULL;
|
||||
free(cv_object);
|
||||
}
|
||||
|
||||
struct hf_content_converter * hf_content_converter_create(enum hf_content_conv_work_mode mode,
|
||||
unsigned int content_encode, hf_private_cb * data_cb, void * data_cb_user)
|
||||
{
|
||||
struct hf_content_converter * cv_object = ALLOC(struct hf_content_converter, 1);
|
||||
assert(data_cb != NULL);
|
||||
|
||||
cv_object->mode = mode;
|
||||
cv_object->content_encode = content_encode;
|
||||
cv_object->data_cb = data_cb;
|
||||
cv_object->data_cb_user = data_cb_user;
|
||||
|
||||
/* ZSTREAM */
|
||||
cv_object->z_stream_ptr = ALLOC(z_stream, 1);
|
||||
cv_object->z_stream_ptr->zalloc = NULL;
|
||||
cv_object->z_stream_ptr->zfree = NULL;
|
||||
cv_object->z_stream_ptr->opaque = NULL;
|
||||
cv_object->z_stream_ptr->avail_in = 0;
|
||||
cv_object->z_stream_ptr->next_in = Z_NULL;
|
||||
|
||||
/* CHUNK, 4K */
|
||||
#define CHUNK_SIZE (1024 * 1024 * 4)
|
||||
cv_object->chunk = (unsigned char *)malloc(CHUNK_SIZE);
|
||||
cv_object->sz_chunk = CHUNK_SIZE;
|
||||
|
||||
int ret = 0;
|
||||
if (content_encode == HTTP_ACCEPT_ENCODING_GZIP)
|
||||
{
|
||||
ret = inflateInit2(cv_object->z_stream_ptr, MAX_WBITS + 16);
|
||||
}
|
||||
else if (content_encode == HTTP_ACCEPT_ENCODING_DEFLATE)
|
||||
{
|
||||
ret = inflateInit(cv_object->z_stream_ptr);
|
||||
}
|
||||
|
||||
if (ret != Z_OK) goto __errout;
|
||||
return cv_object;
|
||||
|
||||
__errout:
|
||||
free(cv_object->z_stream_ptr);
|
||||
free(cv_object->chunk);
|
||||
free(cv_object);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int hf_content_converter_write(struct hf_content_converter * cv_object,
|
||||
struct http_half_private * hf_private, tfe_http_event http_ev, const unsigned char * data, size_t datalen)
|
||||
{
|
||||
z_stream * z_stream_ptr = cv_object->z_stream_ptr;
|
||||
z_stream_ptr->avail_in = (unsigned int)datalen;
|
||||
z_stream_ptr->next_in = (unsigned char *)data;
|
||||
|
||||
if (z_stream_ptr->avail_in == 0)
|
||||
{
|
||||
(void)inflateEnd(z_stream_ptr);
|
||||
return Z_ERRNO;
|
||||
}
|
||||
|
||||
int ret = 0;
|
||||
do
|
||||
{
|
||||
z_stream_ptr->avail_out = (unsigned int) cv_object->sz_chunk;
|
||||
z_stream_ptr->next_out = cv_object->chunk;
|
||||
|
||||
ret = inflate(z_stream_ptr, Z_NO_FLUSH);
|
||||
assert(ret != Z_STREAM_ERROR); /* state not clobbered */
|
||||
|
||||
if (ret == Z_NEED_DICT || ret == Z_DATA_ERROR || ret == Z_MEM_ERROR)
|
||||
{
|
||||
goto __error;
|
||||
}
|
||||
|
||||
unsigned int have = (unsigned int) cv_object->sz_chunk - z_stream_ptr->avail_out;
|
||||
if (have > 0 && cv_object->data_cb != NULL)
|
||||
{
|
||||
cv_object->data_cb(hf_private, http_ev, cv_object->chunk, (size_t) have, cv_object->data_cb_user);
|
||||
}
|
||||
|
||||
} while (z_stream_ptr->avail_out == 0);
|
||||
return ret;
|
||||
|
||||
__error:
|
||||
(void)inflateEnd(z_stream_ptr);
|
||||
return ret;
|
||||
}
|
||||
@@ -61,6 +61,36 @@ static enum tfe_http_std_field __str_header_field_to_std_field_id(const char * s
|
||||
return TFE_HTTP_UNKNOWN_FIELD;
|
||||
}
|
||||
|
||||
uint16_t __hf_content_encoding_parse(const char * str_content_encoding)
|
||||
{
|
||||
if (strcasestr(str_content_encoding, "gzip") != NULL)
|
||||
{
|
||||
return HTTP_ACCEPT_ENCODING_GZIP;
|
||||
}
|
||||
|
||||
if (strcasestr(str_content_encoding, "x-gzip") != NULL)
|
||||
{
|
||||
return HTTP_ACCEPT_ENCODING_X_GZIP;
|
||||
}
|
||||
|
||||
if (strcasestr(str_content_encoding, "deflate") != NULL)
|
||||
{
|
||||
return HTTP_ACCEPT_ENCODING_DEFLATE;
|
||||
}
|
||||
|
||||
if (strcasestr(str_content_encoding, "bzip2") != NULL)
|
||||
{
|
||||
return HTTP_ACCEPT_ENCODING_BZIP2;
|
||||
}
|
||||
|
||||
if (strcasestr(str_content_encoding, "x-bzip2") != NULL)
|
||||
{
|
||||
return HTTP_ACCEPT_ENCODING_X_BZIP2;
|
||||
}
|
||||
|
||||
return HTTP_ACCEPT_ENCODING_IDENTITY;
|
||||
}
|
||||
|
||||
/* To flush header field and value which stash in evbuffer */
|
||||
static void __http_half_header_kv_complete(struct http_half_private * hf_private)
|
||||
{
|
||||
@@ -120,12 +150,7 @@ void __hf_public_req_fill_from_private(struct http_half_private * hf_private, st
|
||||
|
||||
/* accept-encoding, host is located in header's K-V structure */
|
||||
hf_req_spec->method = (enum tfe_http_std_method) parser->method;
|
||||
const static struct http_field_name __host_field_name =
|
||||
{
|
||||
.field_id = TFE_HTTP_HOST,
|
||||
.field_name = NULL
|
||||
};
|
||||
|
||||
const static struct http_field_name __host_field_name = {TFE_HTTP_HOST, NULL};
|
||||
hf_req_spec->host = (char *) tfe_http_field_read(hf_public, &__host_field_name);
|
||||
|
||||
/* uri is stored in underlay evbuffer, we need to append a terminal zero */
|
||||
@@ -157,31 +182,25 @@ void __hf_public_resp_fill_from_private(struct http_half_private * hf_private, s
|
||||
hf_resp_spec->resp_code = parser->status_code;
|
||||
|
||||
/* Content Type */
|
||||
const static struct http_field_name __cont_encoding_type_name =
|
||||
{
|
||||
.field_id = TFE_HTTP_CONT_TYPE,
|
||||
.field_name = NULL
|
||||
};
|
||||
|
||||
const static struct http_field_name __cont_encoding_type_name = {TFE_HTTP_CONT_TYPE, NULL};
|
||||
hf_resp_spec->content_type = (char *) tfe_http_field_read(hf_public, &__cont_encoding_type_name);
|
||||
|
||||
/* Content Length */
|
||||
const static struct http_field_name __cont_encoding_length_name =
|
||||
{
|
||||
.field_id = TFE_HTTP_CONT_LENGTH,
|
||||
.field_name = NULL
|
||||
};
|
||||
|
||||
const static struct http_field_name __cont_encoding_length_name = {TFE_HTTP_CONT_LENGTH, NULL};
|
||||
hf_resp_spec->content_length = (char *) tfe_http_field_read(hf_public, &__cont_encoding_length_name);
|
||||
|
||||
/* Content Encoding */
|
||||
const static struct http_field_name __cont_encoding_field_name =
|
||||
{
|
||||
.field_id = TFE_HTTP_CONT_ENCODING,
|
||||
.field_name = NULL
|
||||
};
|
||||
|
||||
const static struct http_field_name __cont_encoding_field_name = {TFE_HTTP_CONT_ENCODING, NULL};
|
||||
hf_resp_spec->content_encoding = (char *) tfe_http_field_read(hf_public, &__cont_encoding_field_name);
|
||||
|
||||
if (hf_resp_spec->content_encoding != NULL)
|
||||
{
|
||||
hf_private->content_encoding = __hf_content_encoding_parse(hf_resp_spec->content_encoding);
|
||||
}
|
||||
else
|
||||
{
|
||||
hf_private->content_encoding = HTTP_ACCEPT_ENCODING_IDENTITY;
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================================================================================
|
||||
@@ -656,7 +675,7 @@ struct tfe_http_session_ops __http_session_ops =
|
||||
|
||||
void __construct_request_line(struct http_half_private * hf_private)
|
||||
{
|
||||
enum tfe_http_std_method __std_method = (enum tfe_http_std_method ) hf_private->method_or_status;
|
||||
enum tfe_http_std_method __std_method = (enum tfe_http_std_method) hf_private->method_or_status;
|
||||
const char * __str_method = http_std_method_to_string(__std_method);
|
||||
if (__str_method == NULL)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user