*由于git rebase冲突删除原tfe-new-http2分支
*提交包括http2数据替换,转发,截断,缓存代码 *合并最新develop-tfe3a后,http2验证代码提交 *http2重构验证代码提交 *http2添加br压缩解压缩接口和测试用例 *http2定时删除session信息代码提交 *修复bug,访问二级链接时由于nghttp2库收到control ping后,自发control ping包 造成链接断开后重连现象 *修复bug, 链接建立后服务端优先发送control包,未处理此数据包,造成页面访问失败
This commit is contained in:
@@ -27,6 +27,7 @@ option(ENABLE_SANITIZE_THREAD "Enable ThreadSanitizer" FALSE)
|
||||
option(ENABLE_PLUGIN_HTTP "Enable HTTP support" TRUE)
|
||||
option(ENABLE_PLUGIN_DECRYPT_MIRRORING "Enable decrypt mirroring" TRUE)
|
||||
option(ENABLE_PLUGIN_PANGU_HTTP "Enable Pangu-HTTP business" TRUE)
|
||||
option(ENABLE_PLUGIN_HTTP2 "Enable HTTP2 business" TRUE)
|
||||
|
||||
if(ENABLE_PIC)
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE 1)
|
||||
|
||||
@@ -33,6 +33,10 @@ if(ENABLE_PLUGIN_PANGU_HTTP)
|
||||
target_link_libraries(tfe -Wl,--whole-archive pangu-http -Wl,--no-whole-archive)
|
||||
endif()
|
||||
|
||||
if(ENABLE_PLUGIN_HTTP2)
|
||||
target_link_libraries(tfe -Wl,--whole-archive http2 -Wl,--no-whole-archive)
|
||||
endif()
|
||||
|
||||
install(TARGETS tfe RUNTIME DESTINATION bin COMPONENT Program)
|
||||
|
||||
#### test_key_keeper
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
add_subdirectory(http)
|
||||
add_subdirectory(http2)
|
||||
|
||||
18
plugin/protocol/http2/CMakeLists.txt
Normal file
18
plugin/protocol/http2/CMakeLists.txt
Normal file
@@ -0,0 +1,18 @@
|
||||
### PLUGIN
|
||||
add_library(http2 src/http2_stream.cpp src/http2_plugin.cpp src/http2_common.cpp)
|
||||
target_include_directories(http2 PRIVATE include/internal)
|
||||
target_include_directories(http2 PUBLIC incluce/external)
|
||||
|
||||
target_link_libraries(http2 common)
|
||||
target_link_libraries(http2 nghttp2-static)
|
||||
target_link_libraries(http2 libevent-static)
|
||||
target_link_libraries(http2 z)
|
||||
target_link_libraries(http2 brotlienc-static brotlidec-static)
|
||||
|
||||
### UNITTEST CASE
|
||||
add_executable(test-http2-stream test/test_http2_stream.cpp)
|
||||
target_include_directories(test-http2-stream PRIVATE include/internal)
|
||||
target_link_libraries(test-http2-stream gtest http2 common)
|
||||
|
||||
include(GoogleTest)
|
||||
gtest_discover_tests(test-http2-stream)
|
||||
85
plugin/protocol/http2/include/internal/http2_common.h
Normal file
85
plugin/protocol/http2/include/internal/http2_common.h
Normal file
@@ -0,0 +1,85 @@
|
||||
/*************************************************************************
|
||||
> File Name: http2_common.h
|
||||
> Author:
|
||||
> Mail:
|
||||
> Created Time: 2018年09月21日 星期五 13时59分12秒
|
||||
************************************************************************/
|
||||
|
||||
#ifndef _HTTP2_STRING_H
|
||||
#define _HTTP2_STRING_H
|
||||
|
||||
#include <zlib.h>
|
||||
#include <sys/queue.h>
|
||||
#include <brotli/encode.h>
|
||||
#include <brotli/decode.h>
|
||||
#include <http2_stream.h>
|
||||
|
||||
typedef struct RTLogInit2Data_ {
|
||||
int run_log_level;
|
||||
|
||||
char run_log_path[256];
|
||||
|
||||
void *run_log_handle;
|
||||
} RTLogInit2Data;
|
||||
|
||||
typedef struct Http2Plugin_{
|
||||
struct event * event[TFE_THREAD_MAX];
|
||||
struct tfe_session_info_t session_info[TFE_THREAD_MAX];
|
||||
} Http2Plugin;
|
||||
|
||||
typedef enum {
|
||||
NGHTTP2_METHOD_DELETE = 0,
|
||||
NGHTTP2_METHOD_GET = 1,
|
||||
NGHTTP2_METHOD_HEAD = 2,
|
||||
NGHTTP2_METHOD_POST = 3,
|
||||
NGHTTP2_METHOD_PUT = 4,
|
||||
NGHTTP2_METHOD_CONNECT = 5,
|
||||
NGHTTP2_METHOD_UNKNOWN,
|
||||
}nghttp2_method;
|
||||
|
||||
struct value_string {
|
||||
unsigned int value;
|
||||
const char *strptr;
|
||||
};
|
||||
|
||||
const char*
|
||||
val_to_str(unsigned int val, const struct value_string *vs);
|
||||
|
||||
int
|
||||
str_to_val(const char *val, const struct value_string *vs);
|
||||
|
||||
#define BV(x) (1 << x)
|
||||
#define HTTP2_CONTENT_ENCODING_NONE 0
|
||||
#define HTTP2_CONTENT_ENCODING_GZIP BV(1)
|
||||
#define HTTP2_CONTENT_ENCODING_DEFLATE BV(2)
|
||||
#define HTTP2_CONTENT_ENCODING_COMPRESS BV(3)
|
||||
#define HTTP2_CONTENT_ENCODING_BZIP2 BV(4)
|
||||
#define HTTP2_CONTENT_ENCODING_X_GZIP BV(5)
|
||||
#define HTTP2_CONTENT_ENCODING_X_BZIP2 BV(6)
|
||||
#define HTTP2_CONTENT_ENCODING_BR BV(7)
|
||||
|
||||
struct z_stream_st{
|
||||
int gip;
|
||||
z_stream zst;
|
||||
int8_t finished;
|
||||
BrotliDecoderState *brdec_state;
|
||||
BrotliEncoderState *brenc_state;
|
||||
};
|
||||
|
||||
RTLogInit2Data *rt_log_data();
|
||||
|
||||
Http2Plugin *http2_plugin();
|
||||
|
||||
int inflate_read(const uint8_t *source,int len,char **dest, int *outlen,
|
||||
struct z_stream_st **strm, int encode);
|
||||
|
||||
int deflate_write(struct z_stream_st **strm, const uint8_t *source,
|
||||
int slen, struct evbuffer * evbuf, int gzip, int end);
|
||||
|
||||
void inflate_finished(struct z_stream_st **strm);
|
||||
|
||||
void deflate_finished(struct z_stream_st **strm);
|
||||
|
||||
void frame_display(const uint8_t *payload, uint16_t payload_len);
|
||||
|
||||
#endif
|
||||
182
plugin/protocol/http2/include/internal/http2_stream.h
Normal file
182
plugin/protocol/http2/include/internal/http2_stream.h
Normal file
@@ -0,0 +1,182 @@
|
||||
/*************************************************************************
|
||||
> File Name: http_stream.h
|
||||
> Author:
|
||||
> Mail:
|
||||
> Created Time: 2018年09月12日 星期三 15时56分05秒
|
||||
************************************************************************/
|
||||
|
||||
#ifndef _HTTP_STREAM_H
|
||||
#define _HTTP_STREAM_H
|
||||
|
||||
#include <tfe_http.h>
|
||||
#include <tfe_stream.h>
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
typedef int (*event_cb)(struct http2_half_private * hf_private,
|
||||
tfe_http_event ev, const unsigned char * data,
|
||||
size_t len, void * user);
|
||||
|
||||
enum nghttp2_manage_stage
|
||||
{
|
||||
MANAGE_STAGE_INIT,
|
||||
MANAGE_STAGE_READING,
|
||||
MANAGE_STAGE_COMPLETE,
|
||||
};
|
||||
|
||||
struct data_t
|
||||
{
|
||||
int gzip;
|
||||
uint8_t flags;
|
||||
struct z_stream_st *inflater;
|
||||
struct z_stream_st *deflate;
|
||||
struct evbuffer * evbuf_body;
|
||||
};
|
||||
|
||||
struct header_data{
|
||||
nghttp2_nv nv;
|
||||
struct http_field_name field;
|
||||
struct header_data *prev, *next;
|
||||
};
|
||||
|
||||
struct http2_headers{
|
||||
int nvlen;
|
||||
uint8_t flag;
|
||||
struct header_data *head, *tail;
|
||||
};
|
||||
|
||||
struct http2_half_private
|
||||
{
|
||||
/* PUBLIC STRUCTURE */
|
||||
struct tfe_http_half half_public;
|
||||
|
||||
struct http_frame_session_ctx *frame_ctx;
|
||||
|
||||
/* UNDERLAY BUFFER */
|
||||
int method_or_status;
|
||||
|
||||
char * url_storage;
|
||||
struct data_t body;
|
||||
struct http2_headers headers;
|
||||
|
||||
enum nghttp2_manage_stage body_state;
|
||||
enum nghttp2_manage_stage message_state;
|
||||
|
||||
/* Callback Function */
|
||||
int (*event_cb)(struct http2_half_private * half_private, tfe_http_event ev,
|
||||
const unsigned char * data, size_t len, void * user);
|
||||
/* Callback Function User Pointer */
|
||||
void * event_cb_user;
|
||||
/* Callback Function User Pointer Deleter */
|
||||
void (* event_cb_user_deleter)(void *);
|
||||
};
|
||||
|
||||
struct h2_stream_data_t{
|
||||
struct tfe_http_session tfe_session;
|
||||
TAILQ_ENTRY(h2_stream_data_t) next;
|
||||
|
||||
int32_t stream_id;
|
||||
uint16_t frame_type;
|
||||
|
||||
int spd_set;
|
||||
int spd_valid;
|
||||
int rse_set;
|
||||
tfe_http_event spd_event;
|
||||
|
||||
struct http_frame_session_ctx *frame_ctx;
|
||||
struct http2_half_private *req, *pangu_req;
|
||||
struct http2_half_private *resp, *pangu_resp;
|
||||
};
|
||||
|
||||
struct h2_run_id
|
||||
{
|
||||
int num;
|
||||
int32_t id[128];
|
||||
};
|
||||
|
||||
struct tfe_session_info_t
|
||||
{
|
||||
TAILQ_HEAD(list_head, h2_stream_data_t) list;
|
||||
|
||||
/* stream type**/
|
||||
int state;
|
||||
unsigned int thread_id;
|
||||
struct h2_run_id h2_id;
|
||||
/** for down stream as server */
|
||||
nghttp2_session *as_server;
|
||||
/** for up stream as client*/
|
||||
nghttp2_session *as_client;
|
||||
|
||||
const struct tfe_stream *tf_stream;
|
||||
};
|
||||
|
||||
struct stream_tap_info_t
|
||||
{
|
||||
/** IS PREEMPTED */
|
||||
unsigned int preempted;
|
||||
/** sess manage */
|
||||
struct tfe_session_info_t *session_info;
|
||||
};
|
||||
|
||||
/*STREAM STATE **/
|
||||
#define TFE_NGHTTP2_DATA 0x00000001
|
||||
#define TFE_NGHTTP2_HEADERS 0x00000002
|
||||
#define TFE_NGHTTP2_PRIORITY 0x00000020
|
||||
#define TFE_NGHTTP2_RST_STREAM 0x00000040
|
||||
#define TFE_NGHTTP2_SETTINGS 0x00000080
|
||||
#define TFE_NGHTTP2_PUSH_PROMISE 0x00000100
|
||||
#define TFE_NGHTTP2_PING 0x00000200
|
||||
#define TFE_NGHTTP2_GOAWAY 0x00000400
|
||||
#define TFE_NGHTTP2_WINDOW_UPDATE 0x00000800
|
||||
#define TFE_NGHTTP2_CONTINUATION 0x00001000
|
||||
#define TFE_NGHTTP2_ALTSVC 0x00002000
|
||||
#define TFE_NGHTTP2_RESPONSE 0x00004000
|
||||
|
||||
#define ACTION_USER_DATA 3
|
||||
|
||||
static inline const struct http2_half_private *
|
||||
nghttp2_to_half_private(const struct tfe_http_half * half_public)
|
||||
{
|
||||
if(!half_public)
|
||||
return NULL;
|
||||
return container_of(half_public, struct http2_half_private, half_public);
|
||||
}
|
||||
|
||||
static inline struct http2_half_private *
|
||||
nghttp2_to_half_private(struct tfe_http_half * half_public)
|
||||
{
|
||||
if(!half_public)
|
||||
return NULL;
|
||||
return container_of(half_public, struct http2_half_private, half_public);
|
||||
}
|
||||
|
||||
static inline struct h2_stream_data_t *
|
||||
nghttp2_to_stream_data(struct tfe_http_session * hs_public)
|
||||
{
|
||||
if (hs_public == NULL)
|
||||
return NULL;
|
||||
return container_of(hs_public, struct h2_stream_data_t, tfe_session);
|
||||
}
|
||||
|
||||
extern struct tfe_session_info_t* tfe_session_info_init();
|
||||
extern void sess_data_ctx_fini(struct tfe_session_info_t *session_info, const struct tfe_stream * stream,
|
||||
unsigned int thread_id);
|
||||
|
||||
extern enum tfe_stream_action
|
||||
detect_down_stream_protocol(struct tfe_session_info_t *session_info, const struct tfe_stream *tfe_stream,
|
||||
unsigned int thread_id, const unsigned char *data, size_t len);
|
||||
|
||||
extern enum tfe_stream_action
|
||||
detect_up_stream_protocol(struct tfe_session_info_t *session_info, const struct tfe_stream *tfe_stream,
|
||||
unsigned int thread_id, const unsigned char *data, size_t len);
|
||||
|
||||
enum tfe_stream_action
|
||||
nghttp2_client_mem_send(struct tfe_session_info_t *session_info);
|
||||
|
||||
enum tfe_stream_action
|
||||
nghttp2_server_mem_send(struct tfe_session_info_t *session_info);
|
||||
|
||||
/*for test **/
|
||||
|
||||
#endif
|
||||
409
plugin/protocol/http2/src/http2_common.cpp
Normal file
409
plugin/protocol/http2/src/http2_common.cpp
Normal file
@@ -0,0 +1,409 @@
|
||||
/*************************************************************************
|
||||
> 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 *rt_log_data()
|
||||
{
|
||||
return &logging_sc_lid;
|
||||
};
|
||||
|
||||
Http2Plugin g_http2_plugin = {
|
||||
|
||||
};
|
||||
|
||||
Http2Plugin *http2_plugin()
|
||||
{
|
||||
return &g_http2_plugin;
|
||||
}
|
||||
|
||||
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 -1;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
int ret = 0;
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
assert(ret != Z_STREAM_ERROR); /* state not clobbered */
|
||||
switch (ret) {
|
||||
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;
|
||||
|
||||
*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;
|
||||
}
|
||||
|
||||
int defalta_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;
|
||||
|
||||
}
|
||||
|
||||
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 = defalta_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;
|
||||
return;
|
||||
}
|
||||
(void)inflateEnd(&((*strm)->zst));
|
||||
free(*strm);
|
||||
*strm = NULL;
|
||||
}
|
||||
}
|
||||
void deflate_finished(struct z_stream_st **strm)
|
||||
{
|
||||
if (*strm != NULL){
|
||||
(void) deflateEnd(&((*strm)->zst));
|
||||
free(*strm);
|
||||
*strm = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void frame_display(const uint8_t *payload, uint16_t payload_len)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
printf("context:(%d)\n", payload_len);
|
||||
for(i=0; i < (int)payload_len; ++i){
|
||||
printf(" 0x%02x,", payload[i]);
|
||||
if( (i + 1) % 16 == 0)
|
||||
printf("\n");
|
||||
if ( i > 500)
|
||||
break;
|
||||
}
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
|
||||
207
plugin/protocol/http2/src/http2_plugin.cpp
Normal file
207
plugin/protocol/http2/src/http2_plugin.cpp
Normal file
@@ -0,0 +1,207 @@
|
||||
/*************************************************************************
|
||||
> File Name: detect_http2_plugin.cpp
|
||||
> Author:
|
||||
> Mail:
|
||||
> Created Time: 2018年09月11日 星期二 15时38分54秒
|
||||
************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <event.h>
|
||||
|
||||
#include <tfe_stream.h>
|
||||
#include <tfe_utils.h>
|
||||
#include <tfe_plugin.h>
|
||||
#include <tfe_proxy.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#include <http2_stream.h>
|
||||
#include <http2_common.h>
|
||||
|
||||
#include <MESA/MESA_prof_load.h>
|
||||
|
||||
/* Magic Header : PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n */
|
||||
static const uint8_t kMagicHello[] = {
|
||||
0x50, 0x52, 0x49, 0x20, 0x2a, 0x20, 0x48, 0x54,
|
||||
0x54, 0x50, 0x2f, 0x32, 0x2e, 0x30, 0x0d, 0x0a,
|
||||
0x0d, 0x0a, 0x53, 0x4d, 0x0d, 0x0a, 0x0d, 0x0a
|
||||
};
|
||||
|
||||
#define get_u_int8_t(X,O) (*(u_int8_t *)(((u_int8_t *)X) + O))
|
||||
|
||||
#define TFE_BASIC_CFG "conf/tfe/tfe.conf"
|
||||
|
||||
#define MAGIC_FRAME_LENGTH 24
|
||||
#define SET_FRAME_LENGTH 18
|
||||
|
||||
struct event_timer_ctx
|
||||
{
|
||||
Http2Plugin *plugin;
|
||||
unsigned int thread_id;
|
||||
};
|
||||
|
||||
void load_logging_conf(const char *config)
|
||||
{
|
||||
RTLogInit2Data *logging_sc_lid = rt_log_data();
|
||||
|
||||
MESA_load_profile_int_def(config, (const char *)"http",(const char *)"loglevel",
|
||||
&logging_sc_lid->run_log_level, 10);
|
||||
MESA_load_profile_string_def(config, (const char *)"http",(const char *)"logfile",
|
||||
logging_sc_lid->run_log_path, 128, "log/http2.log");
|
||||
|
||||
logging_sc_lid->run_log_handle = MESA_create_runtime_log_handle(logging_sc_lid->run_log_path, logging_sc_lid->run_log_level);
|
||||
if(logging_sc_lid->run_log_handle == NULL){
|
||||
TFE_LOG_ERROR(logging_sc_lid->run_log_handle, "Create log runtime_log_handle error, init failed!");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static void http2_plugin_timer_gc_cb(evutil_socket_t fd, short what, void * arg)
|
||||
{
|
||||
struct tfe_session_info_t *session_info = (struct tfe_session_info_t *)arg;
|
||||
sess_data_ctx_fini(session_info, NULL, session_info->thread_id);
|
||||
}
|
||||
|
||||
static int
|
||||
http2_plugin_init(struct tfe_proxy * proxy)
|
||||
{
|
||||
Http2Plugin *plugin = http2_plugin();
|
||||
|
||||
unsigned int thread_nu = tfe_proxy_get_work_thread_count();
|
||||
|
||||
load_logging_conf(TFE_BASIC_CFG);
|
||||
|
||||
for (unsigned int thread_id = 0; thread_id < thread_nu; thread_id++){
|
||||
#if 0
|
||||
struct tfe_session_info_t session_info = plugin->session_info[thread_id];
|
||||
TAILQ_INIT(&(session_info.list));
|
||||
session_info.thread_id = thread_id;
|
||||
session_info.as_client = 0;
|
||||
|
||||
struct event_base * ev_base = tfe_proxy_get_work_thread_evbase(thread_id);
|
||||
|
||||
struct timeval timer = {0, 500 * 1000};
|
||||
struct event * event = event_new(ev_base, -1, EV_PERSIST, http2_plugin_timer_gc_cb, &session_info);
|
||||
|
||||
if (unlikely(event == NULL)){
|
||||
TFE_LOG_ERROR(rt_log_data()->run_log_handle, "Create timer error, init failed!");
|
||||
}
|
||||
|
||||
evtimer_add(event, &timer);
|
||||
plugin->event[thread_id] = event;
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
http2_plugin_deinit(struct tfe_proxy * proxy)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static int
|
||||
http2_stream_open(const struct tfe_stream *stream, unsigned int thread_id,
|
||||
enum tfe_conn_dir dir, void ** pme)
|
||||
{
|
||||
struct stream_tap_info_t *tapinfo = ALLOC(struct stream_tap_info_t, 1);
|
||||
assert(tapinfo);
|
||||
|
||||
memset(tapinfo, 0, sizeof(struct stream_tap_info_t));
|
||||
tapinfo->preempted = 0;
|
||||
tapinfo->session_info = tfe_session_info_init();
|
||||
|
||||
*pme = (void *)tapinfo;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum tfe_stream_action
|
||||
http2_stream_data(const struct tfe_stream * stream, unsigned int thread_id,
|
||||
enum tfe_conn_dir dir, const unsigned char * data, size_t len, void ** pme)
|
||||
{
|
||||
static unsigned int defer_bytes = 0;
|
||||
struct stream_tap_info_t *tapinfo = (struct stream_tap_info_t *)(*pme);
|
||||
|
||||
if (tapinfo->preempted == 0){
|
||||
|
||||
if (dir == CONN_DIR_UPSTREAM){
|
||||
if (len < SET_FRAME_LENGTH){
|
||||
defer_bytes = SET_FRAME_LENGTH;
|
||||
tfe_stream_action_set_opt(stream, ACTION_OPT_DEFER_BYTES, (void *) &defer_bytes, sizeof(defer_bytes));
|
||||
return ACTION_DEFER_DATA;
|
||||
}
|
||||
/*setting frame: 00 00 12 04 00 00 00 00 00 00 03 00 00 00 80 00 04 7f ff ff ff 00 05 00 ff ff ff 00 00 04 08 00
|
||||
00 00 00 00 7f ff 00 00 ***/
|
||||
|
||||
if (get_u_int8_t(data, 3) == 0x4
|
||||
&& ((get_u_int8_t(data, 9) == 0x00 && get_u_int8_t(data, 10) == 0x03)
|
||||
|| (get_u_int8_t(data, 15) == 0x00 && get_u_int8_t(data, 16) == 0x04)
|
||||
|| (get_u_int8_t(data, 21) == 0x00 && get_u_int8_t(data, 22) == 0x05))){
|
||||
}else{
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
if (dir == CONN_DIR_DOWNSTREAM){
|
||||
/* Protocol Identification, we need 24 bytes at least to tell it is HTTP2 or not */
|
||||
if (len < MAGIC_FRAME_LENGTH){
|
||||
defer_bytes = MAGIC_FRAME_LENGTH;
|
||||
tfe_stream_action_set_opt(stream, ACTION_OPT_DEFER_BYTES, (void *) &defer_bytes, sizeof(defer_bytes));
|
||||
return ACTION_DEFER_DATA;
|
||||
}
|
||||
if (memcmp(data, kMagicHello, MAGIC_FRAME_LENGTH) != 0){
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
if (tfe_stream_preempt(stream) != 0)
|
||||
goto detach;
|
||||
|
||||
tapinfo->preempted = 1;
|
||||
}
|
||||
|
||||
return (dir == CONN_DIR_DOWNSTREAM) ? detect_down_stream_protocol(tapinfo->session_info, stream, thread_id,
|
||||
data, len) : detect_up_stream_protocol(tapinfo->session_info, stream, thread_id, data, len);
|
||||
|
||||
detach:
|
||||
tfe_stream_detach(stream);
|
||||
finish:
|
||||
return ACTION_FORWARD_DATA;
|
||||
}
|
||||
|
||||
static void
|
||||
http2_stream_close(const struct tfe_stream * stream, unsigned int thread_id,
|
||||
enum tfe_stream_close_reason reason, void ** pme)
|
||||
{
|
||||
struct stream_tap_info_t *tapinfo = (struct stream_tap_info_t *)(*pme);
|
||||
|
||||
sess_data_ctx_fini(tapinfo->session_info, stream, thread_id);
|
||||
|
||||
free(tapinfo->session_info);
|
||||
tapinfo->session_info = NULL;
|
||||
|
||||
free(tapinfo);
|
||||
tapinfo = NULL;
|
||||
|
||||
*pme = NULL;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static struct tfe_plugin __nghttp2_plugin_info =
|
||||
{
|
||||
.symbol = "HTTP2",
|
||||
.type = TFE_PLUGIN_TYPE_PROTOCOL,
|
||||
.on_init = http2_plugin_init,
|
||||
.on_deinit = http2_plugin_deinit,
|
||||
.on_open = http2_stream_open,
|
||||
.on_data = http2_stream_data,
|
||||
.on_close = http2_stream_close
|
||||
};
|
||||
|
||||
TFE_PLUGIN_REGISTER(HTTP2, __nghttp2_plugin_info)
|
||||
|
||||
2000
plugin/protocol/http2/src/http2_stream.cpp
Normal file
2000
plugin/protocol/http2/src/http2_stream.cpp
Normal file
File diff suppressed because it is too large
Load Diff
496
plugin/protocol/http2/test/test_http2_stream.cpp
Normal file
496
plugin/protocol/http2/test/test_http2_stream.cpp
Normal file
@@ -0,0 +1,496 @@
|
||||
#include <stdlib.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <http2_stream.h>
|
||||
#include <http2_common.h>
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
#include <event2/buffer.h>
|
||||
|
||||
#include "test_http2_stream.h"
|
||||
|
||||
/********* stub function ******************************/
|
||||
const char * tfe_version()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void tfe_stream_resume(const struct tfe_stream * stream)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void tfe_stream_suspend(const struct tfe_stream * stream, enum tfe_conn_dir by)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int tfe_stream_write(const struct tfe_stream * stream, enum tfe_conn_dir dir, const unsigned char * data, size_t size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tfe_stream_action_set_opt(const struct tfe_stream * stream, enum tfe_stream_action_opt type,
|
||||
void * value, size_t size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tfe_stream_detach(const struct tfe_stream * stream)
|
||||
{
|
||||
return;
|
||||
}
|
||||
/********* stub function ******************************/
|
||||
|
||||
/* Magic Header : PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n */
|
||||
static uint8_t kMagicHello[] = {
|
||||
0x50, 0x52, 0x49, 0x20, 0x2a, 0x20, 0x48, 0x54,
|
||||
0x54, 0x50, 0x2f, 0x32, 0x2e, 0x30, 0x0d, 0x0a,
|
||||
0x0d, 0x0a, 0x53, 0x4d, 0x0d, 0x0a, 0x0d, 0x0a
|
||||
};
|
||||
|
||||
#define MAGIC_FRAME_LENGTH 24
|
||||
|
||||
|
||||
#if 1
|
||||
void UT_Parse_ReqHeaders(nghttp2_session *as_server)
|
||||
{
|
||||
int stream_id = 1;
|
||||
|
||||
struct h2_stream_data_t *h2_stream = (struct h2_stream_data_t *)nghttp2_session_get_stream_user_data(as_server, stream_id);
|
||||
ASSERT_TRUE(h2_stream != NULL);
|
||||
|
||||
struct http2_half_private *half_private_req = h2_stream->req;
|
||||
struct tfe_http_half *tfe_half = &half_private_req->half_public;
|
||||
struct tfe_http_req_spec *req_spec = &tfe_half->req_spec;
|
||||
|
||||
/* PUBLIC FIELD */
|
||||
EXPECT_EQ(req_spec->method, NGHTTP2_METHOD_GET);
|
||||
EXPECT_STREQ(req_spec->uri, "/");
|
||||
EXPECT_STREQ(req_spec->url, "www.jd.com/");
|
||||
EXPECT_STREQ(req_spec->host, "www.jd.com");
|
||||
|
||||
/* Header Field */
|
||||
struct http_field_name field_name;
|
||||
void * __iterator = NULL;
|
||||
const char * hdr_value = NULL;
|
||||
|
||||
/*read User-Agent*/
|
||||
field_name.field_id = TFE_HTTP_USER_AGENT;
|
||||
hdr_value = tfe_http_field_read((const struct tfe_http_half*)tfe_half,
|
||||
&field_name);
|
||||
EXPECT_STREQ(hdr_value,
|
||||
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36");
|
||||
|
||||
/* method */
|
||||
hdr_value = tfe_http_field_iterate((const struct tfe_http_half*)tfe_half, &__iterator, &field_name);
|
||||
EXPECT_EQ(field_name.field_id, TFE_HTTP_UNKNOWN_FIELD);
|
||||
EXPECT_STREQ(hdr_value, "GET");
|
||||
|
||||
/* Host */
|
||||
hdr_value = tfe_http_field_iterate((const struct tfe_http_half*)tfe_half, &__iterator, &field_name);
|
||||
EXPECT_EQ(field_name.field_id, TFE_HTTP_HOST);
|
||||
EXPECT_STREQ(hdr_value, "www.jd.com");
|
||||
|
||||
/* scheme */
|
||||
hdr_value = tfe_http_field_iterate((const struct tfe_http_half*)tfe_half, &__iterator, &field_name);
|
||||
EXPECT_EQ(field_name.field_id, TFE_HTTP_UNKNOWN_FIELD);
|
||||
EXPECT_STREQ(hdr_value, "https");
|
||||
|
||||
/*write **/
|
||||
field_name.field_id = TFE_HTTP_DATE;
|
||||
field_name.field_name = "date";
|
||||
int xret = tfe_http_field_write(tfe_half, &field_name, "20181018");
|
||||
EXPECT_EQ(xret, 0);
|
||||
|
||||
/*read TFE_HTTP_DATE **/
|
||||
field_name.field_id = TFE_HTTP_HOST;
|
||||
hdr_value = tfe_http_field_read((const struct tfe_http_half*)tfe_half, &field_name);
|
||||
EXPECT_STREQ(hdr_value, "www.jd.com");
|
||||
|
||||
/*rewrite date **/
|
||||
field_name.field_id = TFE_HTTP_DATE;
|
||||
field_name.field_name = "date";
|
||||
xret = tfe_http_field_write(tfe_half, &field_name, "201x101x");
|
||||
EXPECT_EQ(xret, 0);
|
||||
field_name.field_id = TFE_HTTP_DATE;
|
||||
hdr_value = tfe_http_field_read((const struct tfe_http_half*)tfe_half, &field_name);
|
||||
EXPECT_STREQ(hdr_value, "201x101x");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void UT_Parse_RespHeaders(nghttp2_session *as_client)
|
||||
{
|
||||
int stream_id = 1;
|
||||
|
||||
struct h2_stream_data_t *h2_stream = (struct h2_stream_data_t *)nghttp2_session_get_stream_user_data(as_client, stream_id);
|
||||
ASSERT_TRUE(h2_stream != NULL);
|
||||
|
||||
struct http2_half_private *half_private_req = h2_stream->resp;
|
||||
struct tfe_http_half *tfe_half = &half_private_req->half_public;
|
||||
struct tfe_http_resp_spec *resp_spec = &tfe_half->resp_spec;
|
||||
|
||||
/* PUBLIC FIELD */
|
||||
EXPECT_EQ(resp_spec->resp_code, 200);
|
||||
EXPECT_STREQ(resp_spec->content_type, "text/html; charset=utf-8");
|
||||
EXPECT_STREQ(resp_spec->content_encoding, "gzip");
|
||||
|
||||
/* Header Field */
|
||||
struct http_field_name field_name;
|
||||
void * __iterator = NULL;
|
||||
const char * hdr_value = NULL;
|
||||
|
||||
/* resp code */
|
||||
hdr_value = tfe_http_field_iterate((const struct tfe_http_half*)tfe_half, &__iterator, &field_name);
|
||||
EXPECT_EQ(field_name.field_id, TFE_HTTP_UNKNOWN_FIELD);
|
||||
EXPECT_STREQ(hdr_value, "200");
|
||||
|
||||
/*server*/
|
||||
hdr_value = tfe_http_field_iterate((const struct tfe_http_half*)tfe_half, &__iterator, &field_name);
|
||||
EXPECT_EQ(field_name.field_id, TFE_HTTP_SERVER);
|
||||
EXPECT_STREQ(hdr_value, "JDWS/2.0");
|
||||
|
||||
/*Date*/
|
||||
hdr_value = tfe_http_field_iterate((const struct tfe_http_half*)tfe_half, &__iterator, &field_name);
|
||||
EXPECT_EQ(field_name.field_id, TFE_HTTP_DATE);
|
||||
EXPECT_STREQ(hdr_value, "Mon, 24 Sep 2018 13:16:55 GMT");
|
||||
|
||||
field_name.field_id = TFE_HTTP_CONT_TYPE;
|
||||
hdr_value = tfe_http_field_read((const struct tfe_http_half*)tfe_half, &field_name);
|
||||
EXPECT_STREQ(hdr_value, "text/html; charset=utf-8");
|
||||
|
||||
field_name.field_id = TFE_HTTP_CONT_ENCODING;
|
||||
hdr_value = tfe_http_field_read((const struct tfe_http_half*)tfe_half, &field_name);
|
||||
EXPECT_STREQ(hdr_value, "gzip");
|
||||
|
||||
field_name.field_id = TFE_HTTP_DATE;
|
||||
hdr_value = tfe_http_field_read((const struct tfe_http_half*)tfe_half, &field_name);
|
||||
EXPECT_STREQ(hdr_value, "Mon, 24 Sep 2018 13:16:55 GMT");
|
||||
|
||||
field_name.field_id = TFE_HTTP_EXPIRES;
|
||||
hdr_value = tfe_http_field_read((const struct tfe_http_half*)tfe_half, &field_name);
|
||||
EXPECT_STREQ(hdr_value, "Mon, 24 Sep 2018 13:17:22 GMT");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
TEST(Http2StreamParser, GetFrameWithMagic)
|
||||
{
|
||||
int readlen = 0;
|
||||
struct stream_tap_info_t *tapinfo = ALLOC(struct stream_tap_info_t, 1);
|
||||
assert(tapinfo);
|
||||
|
||||
tapinfo->session_info = tfe_session_info_init();
|
||||
ASSERT_FALSE(tapinfo->session_info == NULL);
|
||||
|
||||
struct tfe_session_info_t *session_info = tapinfo->session_info;
|
||||
|
||||
/*Http2 protocol**/
|
||||
EXPECT_EQ(memcmp(magic_headers, kMagicHello, MAGIC_FRAME_LENGTH), 0);
|
||||
|
||||
/*Recv data magic**/
|
||||
readlen = nghttp2_session_mem_recv(session_info->as_server, magic_headers, sizeof(magic_headers));
|
||||
EXPECT_GT(readlen, 0);
|
||||
}
|
||||
|
||||
TEST(Http2StreamParser, GetFrameWithHeader_01)
|
||||
{
|
||||
int readlen = 0;
|
||||
struct stream_tap_info_t *tapinfo = ALLOC(struct stream_tap_info_t, 1);
|
||||
assert(tapinfo);
|
||||
|
||||
tapinfo->session_info = tfe_session_info_init();
|
||||
ASSERT_FALSE(tapinfo->session_info == NULL);
|
||||
|
||||
struct tfe_session_info_t *session_info = tapinfo->session_info;
|
||||
|
||||
/*Recv data magic**/
|
||||
readlen = nghttp2_session_mem_recv(session_info->as_server, magic_headers, sizeof(magic_headers));
|
||||
EXPECT_GT(readlen, 0);
|
||||
|
||||
/*Recv request Headers**/
|
||||
readlen = nghttp2_session_mem_recv(session_info->as_server, request_get_headers, sizeof(request_get_headers));
|
||||
EXPECT_GT(readlen, 0);
|
||||
|
||||
UT_Parse_ReqHeaders(session_info->as_server);
|
||||
}
|
||||
|
||||
TEST(Http2StreamParser, GetFrameWithHeader_02)
|
||||
{
|
||||
int readlen = 0;
|
||||
struct stream_tap_info_t *tapinfo = ALLOC(struct stream_tap_info_t, 1);
|
||||
assert(tapinfo);
|
||||
|
||||
tapinfo->session_info = tfe_session_info_init();
|
||||
ASSERT_FALSE(tapinfo->session_info == NULL);
|
||||
|
||||
struct tfe_session_info_t *session_info = tapinfo->session_info;
|
||||
|
||||
/*Recv data magic**/
|
||||
readlen = nghttp2_session_mem_recv(session_info->as_server, magic_headers, sizeof(magic_headers));
|
||||
EXPECT_GT(readlen, 0);
|
||||
|
||||
/*Recv request Headers**/
|
||||
readlen = nghttp2_session_mem_recv(session_info->as_server, request_get_headers, sizeof(request_get_headers));
|
||||
EXPECT_GT(readlen, 0);
|
||||
|
||||
/*Send data message**/
|
||||
enum tfe_stream_action stream_action = ACTION_FORWARD_DATA;
|
||||
stream_action = nghttp2_client_mem_send(session_info);
|
||||
EXPECT_EQ(stream_action, ACTION_DROP_DATA);
|
||||
}
|
||||
|
||||
TEST(Http2StreamParser, RespFrameWithHead_01)
|
||||
{
|
||||
int readlen = 0;
|
||||
struct stream_tap_info_t *tapinfo = ALLOC(struct stream_tap_info_t, 1);
|
||||
assert(tapinfo);
|
||||
|
||||
tapinfo->session_info = tfe_session_info_init();
|
||||
ASSERT_FALSE(tapinfo->session_info == NULL);
|
||||
|
||||
struct tfe_session_info_t *session_info = tapinfo->session_info;
|
||||
|
||||
/*Recv data magic**/
|
||||
readlen = nghttp2_session_mem_recv(session_info->as_server, magic_headers, sizeof(magic_headers));
|
||||
EXPECT_GT(readlen, 0);
|
||||
|
||||
/*Recv request Headers**/
|
||||
readlen = nghttp2_session_mem_recv(session_info->as_server, request_get_headers, sizeof(request_get_headers));
|
||||
EXPECT_GT(readlen, 0);
|
||||
|
||||
/*Send data head message**/
|
||||
enum tfe_stream_action stream_action = ACTION_FORWARD_DATA;
|
||||
stream_action = nghttp2_client_mem_send(session_info);
|
||||
EXPECT_EQ(stream_action, ACTION_DROP_DATA);
|
||||
|
||||
/*Recv response settings*/
|
||||
readlen = nghttp2_session_mem_recv(session_info->as_client, response_settings, sizeof(response_settings));
|
||||
EXPECT_GT(readlen, 0);
|
||||
|
||||
/*Recv response Header*/
|
||||
readlen = nghttp2_session_mem_recv(session_info->as_client, response_header2, sizeof(response_header2));
|
||||
EXPECT_GT(readlen, 0);
|
||||
UT_Parse_RespHeaders(session_info->as_client);
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(Http2StreamParser, FrameWithJdData)
|
||||
{
|
||||
int len = 0;
|
||||
const uint8_t *data[] = {jd_data_00, jd_data_01, jd_data_02, jd_data_03,
|
||||
jd_data_04, jd_data_05, jd_data_06, jd_data_07};
|
||||
|
||||
size_t datalen[] = {sizeof(jd_data_00), sizeof(jd_data_01), sizeof(jd_data_02),
|
||||
sizeof(jd_data_03), sizeof(jd_data_04), sizeof(jd_data_05),
|
||||
sizeof(jd_data_06), sizeof(jd_data_07)};
|
||||
|
||||
enum tfe_stream_action __attribute__((__unused__))action;
|
||||
|
||||
struct stream_tap_info_t *tapinfo = ALLOC(struct stream_tap_info_t, 1);
|
||||
assert(tapinfo);
|
||||
|
||||
tapinfo->session_info = tfe_session_info_init();
|
||||
ASSERT_FALSE(tapinfo->session_info == NULL);
|
||||
|
||||
struct tfe_session_info_t *session_info = tapinfo->session_info;
|
||||
|
||||
for (len = 0; len <= 7; len++){
|
||||
if (len > 0 && len < 4){
|
||||
printf("Proc down stream(%d)\n", len);
|
||||
action = detect_down_stream_protocol(session_info, NULL, 0, data[len], datalen[len]);
|
||||
}else{
|
||||
printf("Proc up stream(%d)\n", len);
|
||||
action = detect_up_stream_protocol(session_info, NULL, 0, data[len], datalen[len]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(UI_TEST_INFLATE_GZIP, inflate_01)
|
||||
{
|
||||
char *uncompr = NULL;
|
||||
struct data_t body;
|
||||
int ret = 0, uncompr_len = 0;
|
||||
|
||||
memset(&body, 0, sizeof(struct data_t));
|
||||
|
||||
ret = inflate_read(ut_gip_01, sizeof(ut_gip_01), &uncompr, &uncompr_len, &(body.inflater), 2);
|
||||
|
||||
EXPECT_EQ(ret, Z_STREAM_END);
|
||||
EXPECT_EQ(uncompr_len, sizeof(ut_ungip_01));
|
||||
EXPECT_EQ(memcmp(uncompr, ut_ungip_01, sizeof(ut_ungip_01)), 0);
|
||||
|
||||
free(uncompr);
|
||||
uncompr = NULL;
|
||||
}
|
||||
|
||||
TEST(UI_TEST_INFLATE_GZIP, inflate_02)
|
||||
{
|
||||
struct data_t body;
|
||||
int ret = 0, half = 0;
|
||||
int size = sizeof(ut_gip_01);
|
||||
half = size / 2;
|
||||
|
||||
body.inflater = NULL;
|
||||
|
||||
char *uncompr1 = NULL; int uncompr_len1 = 0;
|
||||
ret = inflate_read(ut_gip_01, half, &uncompr1, &uncompr_len1, &(body.inflater), 2);
|
||||
EXPECT_EQ(ret, Z_OK);
|
||||
|
||||
char *uncompr2 = NULL; int uncompr_len2 = 0;
|
||||
ret = inflate_read(ut_gip_01 + half, size - half, &uncompr2, &uncompr_len2, &(body.inflater), 2);
|
||||
EXPECT_EQ(ret, Z_STREAM_END);
|
||||
|
||||
char uncompr[1024] = {0};
|
||||
snprintf(uncompr, 1024 -1, "%s%s", uncompr1, uncompr2);
|
||||
EXPECT_EQ(uncompr_len1 + uncompr_len2, sizeof(ut_ungip_01));
|
||||
EXPECT_EQ(memcmp(uncompr, ut_ungip_01, sizeof(ut_ungip_01)), 0);
|
||||
|
||||
free(uncompr1);
|
||||
uncompr1 = NULL;
|
||||
free(uncompr2);
|
||||
uncompr2 = NULL;
|
||||
}
|
||||
|
||||
TEST(UI_TEST_DEFLATE_GZIP, deflate_01)
|
||||
{
|
||||
unsigned char *dest = NULL;
|
||||
struct data_t body;
|
||||
int ret = 0, dlen = 0;
|
||||
struct evbuffer * buf = evbuffer_new();
|
||||
int size = sizeof(ut_ungip_01);
|
||||
|
||||
memset(&body, 0, sizeof(struct data_t));
|
||||
|
||||
ret = deflate_write(&(body.deflate), ut_ungip_01, size, buf, 2, 1);
|
||||
EXPECT_EQ(ret, Z_OK);
|
||||
|
||||
dest = evbuffer_pullup(buf, -1);
|
||||
dlen = evbuffer_get_length(buf);
|
||||
|
||||
char *uncompr = NULL;
|
||||
int uncompr_len = 0;
|
||||
ret = inflate_read(dest, dlen, &uncompr, &uncompr_len, &(body.inflater), 2);
|
||||
EXPECT_EQ(ret, Z_STREAM_END);
|
||||
EXPECT_EQ(uncompr_len, sizeof(ut_ungip_01));
|
||||
EXPECT_EQ(memcmp(uncompr, ut_ungip_01, sizeof(ut_ungip_01)), 0);
|
||||
|
||||
free(uncompr);
|
||||
uncompr = NULL;
|
||||
evbuffer_free(buf);
|
||||
}
|
||||
|
||||
TEST(UI_TEST_DEFLATE_GZIP, deflate_02)
|
||||
{
|
||||
struct data_t body;
|
||||
unsigned char *dest = NULL;
|
||||
int ret = 0, half = 0, dlen = 0;
|
||||
|
||||
int size = sizeof(ut_ungip_01);
|
||||
half = size / 2;
|
||||
|
||||
struct evbuffer * buf = evbuffer_new();
|
||||
|
||||
memset(&body, 0, sizeof(struct data_t));
|
||||
|
||||
/* First frag */
|
||||
ret = deflate_write(&(body.deflate), ut_ungip_01, half, buf, 2, 0);
|
||||
EXPECT_EQ(ret, Z_OK);
|
||||
|
||||
/* Last frag */
|
||||
ret = deflate_write(&(body.deflate), ut_ungip_01 + half, size - half, buf, 2, 0);
|
||||
EXPECT_EQ(ret, Z_OK);
|
||||
|
||||
/* End frag */
|
||||
ret = deflate_write(&(body.deflate), NULL, 0, buf, 2, 1);
|
||||
EXPECT_EQ(ret, Z_OK);
|
||||
|
||||
dest = evbuffer_pullup(buf, -1);
|
||||
dlen = evbuffer_get_length(buf);
|
||||
|
||||
char *uncompr = NULL;
|
||||
int uncompr_len = 0;
|
||||
ret = inflate_read(dest, dlen, &uncompr, &uncompr_len, &(body.inflater), 2);
|
||||
EXPECT_EQ(ret, Z_STREAM_END);
|
||||
EXPECT_EQ(uncompr_len, sizeof(ut_ungip_01));
|
||||
EXPECT_EQ(memcmp(uncompr, ut_ungip_01, sizeof(ut_ungip_01)), 0);
|
||||
|
||||
free(uncompr);
|
||||
uncompr = NULL;
|
||||
evbuffer_free(buf);
|
||||
}
|
||||
|
||||
TEST(UI_TEST_DEFLATE_BR, deflate_01)
|
||||
{
|
||||
unsigned char *dest = NULL;
|
||||
struct data_t body;
|
||||
int ret = 0, dlen = 0;
|
||||
struct evbuffer * buf = evbuffer_new();
|
||||
int size = sizeof(ut_ungip_01);
|
||||
|
||||
memset(&body, 0, sizeof(struct data_t));
|
||||
|
||||
ret = deflate_write(&(body.deflate), ut_ungip_01, size, buf, HTTP2_CONTENT_ENCODING_BR, 1);
|
||||
EXPECT_EQ(ret, Z_OK);
|
||||
|
||||
dest = evbuffer_pullup(buf, -1);
|
||||
dlen = evbuffer_get_length(buf);
|
||||
|
||||
char *uncompr = NULL;
|
||||
int uncompr_len = 0;
|
||||
ret = inflate_read(dest, dlen, &uncompr, &uncompr_len, &(body.inflater), HTTP2_CONTENT_ENCODING_BR);
|
||||
EXPECT_EQ(ret, Z_STREAM_END);
|
||||
EXPECT_EQ(uncompr_len, sizeof(ut_ungip_01));
|
||||
EXPECT_EQ(memcmp(uncompr, ut_ungip_01, sizeof(ut_ungip_01)), 0);
|
||||
|
||||
free(uncompr);
|
||||
uncompr = NULL;
|
||||
evbuffer_free(buf);
|
||||
}
|
||||
|
||||
TEST(UI_TEST_DEFLATE_BR, deflate_02)
|
||||
{
|
||||
struct data_t body;
|
||||
unsigned char *dest = NULL;
|
||||
int ret = 0, half = 0, dlen = 0;
|
||||
|
||||
int size = sizeof(ut_ungip_01);
|
||||
half = size / 2;
|
||||
|
||||
struct evbuffer * buf = evbuffer_new();
|
||||
|
||||
memset(&body, 0, sizeof(struct data_t));
|
||||
|
||||
/* First frag */
|
||||
ret = deflate_write(&(body.deflate), ut_ungip_01, half, buf, HTTP2_CONTENT_ENCODING_BR, 0);
|
||||
EXPECT_EQ(ret, Z_OK);
|
||||
|
||||
/* Last frag */
|
||||
ret = deflate_write(&(body.deflate), ut_ungip_01 + half, size - half, buf, HTTP2_CONTENT_ENCODING_BR, 0);
|
||||
EXPECT_EQ(ret, Z_OK);
|
||||
|
||||
/* End frag */
|
||||
ret = deflate_write(&(body.deflate), NULL, 0, buf, HTTP2_CONTENT_ENCODING_BR, 1);
|
||||
EXPECT_EQ(ret, Z_OK);
|
||||
|
||||
dest = evbuffer_pullup(buf, -1);
|
||||
dlen = evbuffer_get_length(buf);
|
||||
|
||||
char *uncompr = NULL;
|
||||
int uncompr_len = 0;
|
||||
ret = inflate_read(dest, dlen, &uncompr, &uncompr_len, &(body.inflater), HTTP2_CONTENT_ENCODING_BR);
|
||||
EXPECT_EQ(ret, Z_STREAM_END);
|
||||
EXPECT_EQ(uncompr_len, sizeof(ut_ungip_01));
|
||||
EXPECT_EQ(memcmp(uncompr, ut_ungip_01, sizeof(ut_ungip_01)), 0);
|
||||
|
||||
free(uncompr);
|
||||
uncompr = NULL;
|
||||
evbuffer_free(buf);
|
||||
}
|
||||
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
2284
plugin/protocol/http2/test/test_http2_stream.h
Normal file
2284
plugin/protocol/http2/test/test_http2_stream.h
Normal file
File diff suppressed because it is too large
Load Diff
6
vendor/CMakeLists.txt
vendored
6
vendor/CMakeLists.txt
vendored
@@ -80,8 +80,8 @@ set_property(TARGET http-parser-static PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${
|
||||
### nghttp2
|
||||
ExternalProject_Add(nghttp2
|
||||
PREFIX nghttp2
|
||||
URL ${CMAKE_CURRENT_SOURCE_DIR}/nghttp2-1.32.0.tar.gz
|
||||
URL_MD5 35944dff48a2d823774c9ed15344d25b
|
||||
URL ${CMAKE_CURRENT_SOURCE_DIR}/nghttp2-1.24.0.tar.gz
|
||||
URL_MD5 d3bf46ac99772d39fa60fa8fd2ab91e5
|
||||
CONFIGURE_COMMAND ./configure --prefix=<INSTALL_DIR> --disable-shared
|
||||
BUILD_IN_SOURCE 1)
|
||||
|
||||
@@ -91,7 +91,7 @@ file(MAKE_DIRECTORY ${INSTALL_DIR}/include)
|
||||
add_library(nghttp2-static STATIC IMPORTED GLOBAL)
|
||||
add_dependencies(nghttp2-static nghttp2)
|
||||
set_property(TARGET nghttp2-static PROPERTY IMPORTED_LOCATION ${INSTALL_DIR}/lib/libnghttp2.a)
|
||||
set_property(TARGET nghttp2-static PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${INSTALL_DIR}/include)
|
||||
set_property(TARGET nghttp2-static PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${INSTALL_DIR}/include ${INSTALL_DIR}/src/nghttp2/lib)
|
||||
|
||||
#### GoogleTest
|
||||
ExternalProject_Add(googletest PREFIX googletest
|
||||
|
||||
BIN
vendor/nghttp2-1.24.0.tar.gz
vendored
Normal file
BIN
vendor/nghttp2-1.24.0.tar.gz
vendored
Normal file
Binary file not shown.
BIN
vendor/nghttp2-1.32.0.tar.gz
vendored
BIN
vendor/nghttp2-1.32.0.tar.gz
vendored
Binary file not shown.
Reference in New Issue
Block a user