*由于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:
fengweihao
2019-02-22 15:42:20 +08:00
committed by zhengchao
parent fcb1581a1c
commit 10c0ef7b76
14 changed files with 5690 additions and 3 deletions

View 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");
}

View 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)

File diff suppressed because it is too large Load Diff