feature: http decoder
* support parser uncompress request/response
* define public API interface
This commit is contained in:
@@ -84,7 +84,7 @@ int main(int argc, char ** argv)
|
||||
struct plugin_manager *plug_mgr = plugin_manager_create();
|
||||
|
||||
// register build-in plugin
|
||||
plugin_manager_register(plug_mgr, "HTTP", SESSION_EVENT_ALL, http_decoder);
|
||||
plugin_manager_register(plug_mgr, "HTTP", SESSION_EVENT_ALL, http_entry);
|
||||
|
||||
// load external plugins
|
||||
char file_path[] = "./plugs/plugins.inf";
|
||||
|
||||
@@ -396,14 +396,14 @@ int plugin_manager_register(struct plugin_manager *plug_mgr, const char *session
|
||||
|
||||
void plugin_manager_dispatch(struct plugin_manager *plug_mgr, struct stellar_event *event)
|
||||
{
|
||||
const struct stellar_session *seesion = stellar_event_get_session(event);
|
||||
const struct stellar_session *session = stellar_event_get_session(event);
|
||||
struct session_plugin_ctx *plug_ctx = stellar_event_get_plugin_ctx(event);
|
||||
enum session_event_type event_type = stellar_event_get_type(event);
|
||||
const char *session_name = stellar_event_get_session_name(event);
|
||||
uint16_t payload_len = stellar_event_get_payload_length(event);
|
||||
const char *payload = stellar_event_get_payload(event);
|
||||
|
||||
assert(seesion);
|
||||
assert(session);
|
||||
assert(session_name);
|
||||
|
||||
char event_str_buffer[1024] = {0};
|
||||
@@ -441,7 +441,7 @@ void plugin_manager_dispatch(struct plugin_manager *plug_mgr, struct stellar_eve
|
||||
{
|
||||
plug_ctx->callback_index = i;
|
||||
plugin_manager_log(DEBUG, "dispatch, run event_cb: %p, plugin status: 'taken over', session: %s, event: (%d, %s)", runtime->event_cb, session_name, event_type, event_str_buffer);
|
||||
runtime->event_cb(seesion, SESSION_EVENT_CLOSING, payload, payload_len, &runtime->cb_args);
|
||||
runtime->event_cb(session, SESSION_EVENT_CLOSING, payload, payload_len, &runtime->cb_args);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
@@ -455,7 +455,7 @@ void plugin_manager_dispatch(struct plugin_manager *plug_mgr, struct stellar_eve
|
||||
{
|
||||
plug_ctx->callback_index = i;
|
||||
plugin_manager_log(DEBUG, "dispatch, run event_cb: %p, plugin status: 'normal', session: %s, event: (%d, %s)", runtime->event_cb, session_name, event_type, event_str_buffer);
|
||||
runtime->event_cb(seesion, event_type, payload, payload_len, &runtime->cb_args);
|
||||
runtime->event_cb(session, event_type, payload, payload_len, &runtime->cb_args);
|
||||
runtime->is_be_called = 1;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -1,6 +1,15 @@
|
||||
|
||||
|
||||
add_library(http
|
||||
http.cpp
|
||||
http_decoder_util.cpp
|
||||
http_decoder_rstring.cpp
|
||||
http_decoder_table.cpp
|
||||
http_decoder.cpp
|
||||
)
|
||||
target_include_directories(http PUBLIC ${CMAKE_SOURCE_DIR})
|
||||
|
||||
target_link_libraries(http
|
||||
llhttp-static
|
||||
)
|
||||
|
||||
target_include_directories(http PUBLIC ${CMAKE_SOURCE_DIR})
|
||||
|
||||
add_subdirectory(test)
|
||||
@@ -1,12 +1,31 @@
|
||||
#include <stddef.h>
|
||||
|
||||
#include "sdk/include/session.h"
|
||||
#include "sdk/include/http.h"
|
||||
|
||||
void http_decoder(const struct stellar_session *session, enum session_event_type event, const char *payload, size_t len, void **ctx)
|
||||
void http_entry(const struct stellar_session *session, enum session_event_type event, const char *payload, size_t len, void **ctx)
|
||||
{
|
||||
struct stellar_session_event_extras *info = NULL;
|
||||
struct stellar_session *new_session = session_manager_session_derive(session, "HTTP");
|
||||
|
||||
session_manager_trigger_event(new_session, SESSION_EVENT_OPENING, info);
|
||||
session_manager_trigger_event(new_session, SESSION_EVENT_META, info);
|
||||
}
|
||||
|
||||
struct http_decoder *http_session_get_decoder(const struct stellar_session *http_session)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
enum http_event http_decoder_get_event(struct http_decoder *decoder)
|
||||
{
|
||||
return HTTP_EVENT_NONE;
|
||||
}
|
||||
|
||||
void http_decoder_fetch_request_line(struct http_decoder *decoder, struct http_request_line *request_line)
|
||||
{
|
||||
}
|
||||
|
||||
void http_decoder_fetch_status_line(struct http_decoder *decoder, struct http_status_line *status_line)
|
||||
{
|
||||
}
|
||||
506
src/protocol_decoder/http/http_decoder.cpp
Normal file
506
src/protocol_decoder/http/http_decoder.cpp
Normal file
@@ -0,0 +1,506 @@
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "llhttp.h"
|
||||
#include "http_decoder_util.h"
|
||||
#include "http_decoder_table.h"
|
||||
#include "http_decoder.h"
|
||||
|
||||
struct http_decoder
|
||||
{
|
||||
llhttp_t parser;
|
||||
llhttp_settings_t settings;
|
||||
enum http_decoder_status status;
|
||||
struct http_decoder_table *table;
|
||||
int commit_count;
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
* Private API
|
||||
******************************************************************************/
|
||||
|
||||
static void printf_debug_info(const char *desc, const char *at, size_t length)
|
||||
{
|
||||
if (at)
|
||||
{
|
||||
char *temp = http_decoder_safe_dup(at, length);
|
||||
printf("%s: %s\n", desc, temp);
|
||||
http_decoder_safe_free(temp);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("%s\n", desc);
|
||||
}
|
||||
}
|
||||
|
||||
/* Possible return values 0, -1, `HPE_PAUSED` */
|
||||
static int on_message_begin(llhttp_t *http)
|
||||
{
|
||||
printf_debug_info("on_message_begin", NULL, 0);
|
||||
|
||||
struct http_decoder *decoder = container_of(http, struct http_decoder, parser);
|
||||
if (decoder->table == NULL)
|
||||
{
|
||||
decoder->table = http_decoder_table_create();
|
||||
}
|
||||
else
|
||||
{
|
||||
http_decoder_table_reset(decoder->table);
|
||||
}
|
||||
decoder->commit_count = 0;
|
||||
decoder->status = ON_MESSAGE_BEGIN;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Possible return values 0, -1, `HPE_PAUSED` */
|
||||
static int on_message_complete(llhttp_t *http)
|
||||
{
|
||||
printf_debug_info("on_message_complete", NULL, 0);
|
||||
|
||||
struct http_decoder *decoder = container_of(http, struct http_decoder, parser);
|
||||
enum rstring_status status = http_decoder_table_status(decoder->table, HTTP_ITERM_BODY);
|
||||
if (status == RSTRING_STATUS_REFER || status == RSTRING_STATUS_CACHE)
|
||||
{
|
||||
http_decoder_table_commit(decoder->table, HTTP_ITERM_BODY);
|
||||
decoder->commit_count++;
|
||||
}
|
||||
decoder->status = ON_MESSAGE_COMPLETE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Possible return values 0, -1, HPE_USER */
|
||||
static int on_uri(llhttp_t *http, const char *at, size_t length)
|
||||
{
|
||||
printf_debug_info("on_uri", at, length);
|
||||
|
||||
struct http_decoder *decoder = container_of(http, struct http_decoder, parser);
|
||||
http_decoder_table_add(decoder->table, HTTP_ITERM_URI, at, length);
|
||||
decoder->status = ON_URI;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Information-only callbacks, return value is ignored */
|
||||
static int on_uri_complete(llhttp_t *http)
|
||||
{
|
||||
printf_debug_info("on_uri_complete", NULL, 0);
|
||||
|
||||
struct http_decoder *decoder = container_of(http, struct http_decoder, parser);
|
||||
http_decoder_table_commit(decoder->table, HTTP_ITERM_URI);
|
||||
decoder->commit_count++;
|
||||
decoder->status = ON_URI_COMPLETE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Possible return values 0, -1, HPE_USER */
|
||||
static int on_status(llhttp_t *http, const char *at, size_t length)
|
||||
{
|
||||
printf_debug_info("on_status", at, length);
|
||||
|
||||
struct http_decoder *decoder = container_of(http, struct http_decoder, parser);
|
||||
http_decoder_table_add(decoder->table, HTTP_ITERM_STATUS, at, length);
|
||||
decoder->status = ON_STATUS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Information-only callbacks, return value is ignored */
|
||||
static int on_status_complete(llhttp_t *http)
|
||||
{
|
||||
printf_debug_info("on_status_complete", NULL, 0);
|
||||
|
||||
struct http_decoder *decoder = container_of(http, struct http_decoder, parser);
|
||||
http_decoder_table_commit(decoder->table, HTTP_ITERM_STATUS);
|
||||
decoder->commit_count++;
|
||||
decoder->status = ON_STATUS_COMPLETE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Possible return values 0, -1, HPE_USER */
|
||||
static int on_header_field(llhttp_t *http, const char *at, size_t length)
|
||||
{
|
||||
printf_debug_info("on_header_field", at, length);
|
||||
|
||||
struct http_decoder *decoder = container_of(http, struct http_decoder, parser);
|
||||
http_decoder_table_add(decoder->table, HTTP_ITERM_HEADER_FILED, at, length);
|
||||
decoder->status = ON_HEADER_FIELD;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Information-only callbacks, return value is ignored */
|
||||
static int on_header_field_complete(llhttp_t *http)
|
||||
{
|
||||
printf_debug_info("on_header_field_complete", NULL, 0);
|
||||
|
||||
struct http_decoder *decoder = container_of(http, struct http_decoder, parser);
|
||||
http_decoder_table_commit(decoder->table, HTTP_ITERM_HEADER_FILED);
|
||||
decoder->commit_count++;
|
||||
decoder->status = ON_HEADER_FIELD_COMPLETE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Possible return values 0, -1, HPE_USER */
|
||||
static int on_header_value(llhttp_t *http, const char *at, size_t length)
|
||||
{
|
||||
printf_debug_info("on_header_value", at, length);
|
||||
|
||||
struct http_decoder *decoder = container_of(http, struct http_decoder, parser);
|
||||
http_decoder_table_add(decoder->table, HTTP_ITERM_HEADER_VALUE, at, length);
|
||||
decoder->status = ON_HEADER_VALUE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Information-only callbacks, return value is ignored */
|
||||
static int on_header_value_complete(llhttp_t *http)
|
||||
{
|
||||
printf_debug_info("on_header_value_complete", NULL, 0);
|
||||
|
||||
struct http_decoder *decoder = container_of(http, struct http_decoder, parser);
|
||||
http_decoder_table_commit(decoder->table, HTTP_ITERM_HEADER_VALUE);
|
||||
decoder->commit_count++;
|
||||
decoder->status = ON_HEADER_VALUE_COMPLETE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* When on_chunk_header is called, the current chunk length is stored
|
||||
* in parser->content_length.
|
||||
* Possible return values 0, -1, `HPE_PAUSED`
|
||||
*/
|
||||
static int on_chunk_header(llhttp_t *http)
|
||||
{
|
||||
printf_debug_info("on_chunk_header", NULL, 0);
|
||||
|
||||
struct http_decoder *decoder = container_of(http, struct http_decoder, parser);
|
||||
decoder->status = ON_CHUNK_HEADER;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* When on_chunk_header is called, the current chunk length is stored
|
||||
* in parser->content_length.
|
||||
* Possible return values 0, -1, `HPE_PAUSED`
|
||||
*/
|
||||
static int on_chunk_header_complete(llhttp_t *http)
|
||||
{
|
||||
printf_debug_info("on_chunk_header_complete", NULL, 0);
|
||||
|
||||
struct http_decoder *decoder = container_of(http, struct http_decoder, parser);
|
||||
decoder->status = ON_CHUNK_HEADER_COMPLETE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Possible return values:
|
||||
* 0 - Proceed normally
|
||||
* 1 - Assume that request/response has no body, and proceed to parsing the next message
|
||||
* 2 - Assume absence of body (as above) and make `llhttp_execute()` return `HPE_PAUSED_UPGRADE`
|
||||
* -1 - Error `HPE_PAUSED`
|
||||
*/
|
||||
static int on_headers_complete(llhttp_t *http)
|
||||
{
|
||||
printf_debug_info("on_headers_complete", NULL, 0);
|
||||
|
||||
struct http_decoder *decoder = container_of(http, struct http_decoder, parser);
|
||||
decoder->status = ON_HEADERS_COMPLETE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Possible return values 0, -1, HPE_USER */
|
||||
static int on_body(llhttp_t *http, const char *at, size_t length)
|
||||
{
|
||||
printf_debug_info("on_body", at, length);
|
||||
|
||||
struct http_decoder *decoder = container_of(http, struct http_decoder, parser);
|
||||
http_decoder_table_add(decoder->table, HTTP_ITERM_BODY, at, length);
|
||||
decoder->status = ON_BODY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Manipulate http decoder
|
||||
******************************************************************************/
|
||||
|
||||
struct http_decoder *http_decoder_create()
|
||||
{
|
||||
struct http_decoder *decoder = http_decoder_safe_alloc(struct http_decoder, 1);
|
||||
|
||||
return decoder;
|
||||
}
|
||||
|
||||
void http_decoder_destory(struct http_decoder *decoder)
|
||||
{
|
||||
if (decoder)
|
||||
{
|
||||
http_decoder_table_destory(decoder->table);
|
||||
http_decoder_safe_free(decoder);
|
||||
}
|
||||
}
|
||||
|
||||
void http_decoder_init(struct http_decoder *decoder)
|
||||
{
|
||||
assert(decoder);
|
||||
|
||||
enum llhttp_type type = HTTP_BOTH; // HTTP_BOTH | HTTP_REQUEST | HTTP_RESPONSE
|
||||
|
||||
llhttp_settings_init(&decoder->settings);
|
||||
llhttp_init(&decoder->parser, type, &decoder->settings);
|
||||
|
||||
decoder->settings.on_message_begin = on_message_begin;
|
||||
decoder->settings.on_message_complete = on_message_complete;
|
||||
|
||||
decoder->settings.on_url = on_uri;
|
||||
decoder->settings.on_url_complete = on_uri_complete;
|
||||
|
||||
decoder->settings.on_status = on_status;
|
||||
decoder->settings.on_status_complete = on_status_complete;
|
||||
|
||||
decoder->settings.on_header_field = on_header_field;
|
||||
decoder->settings.on_header_field_complete = on_header_field_complete;
|
||||
|
||||
decoder->settings.on_header_value = on_header_value;
|
||||
decoder->settings.on_header_value_complete = on_header_value_complete;
|
||||
|
||||
decoder->settings.on_chunk_header = on_chunk_header;
|
||||
decoder->settings.on_chunk_complete = on_chunk_header_complete;
|
||||
|
||||
decoder->settings.on_headers_complete = on_headers_complete;
|
||||
|
||||
decoder->settings.on_body = on_body;
|
||||
|
||||
decoder->status = ON_INIT;
|
||||
}
|
||||
|
||||
void http_decoder_reset(struct http_decoder *decoder)
|
||||
{
|
||||
if (decoder)
|
||||
{
|
||||
http_decoder_init(decoder);
|
||||
http_decoder_table_reset(decoder->table);
|
||||
decoder->commit_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* return 0 : new data that needs to be consumed by upper layers has been parsed
|
||||
* return -1 : no new data
|
||||
* return -2 : error or not http protocol
|
||||
*/
|
||||
int http_decoder_dispatch(struct http_decoder *decoder, const char *data, size_t len)
|
||||
{
|
||||
assert(decoder);
|
||||
|
||||
enum llhttp_errno err = llhttp_execute(&decoder->parser, data, len);
|
||||
if (err != HPE_OK)
|
||||
{
|
||||
fprintf(stderr, "llhttp_execute parse error: %s %s\n", llhttp_errno_name(err), decoder->parser.reason);
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (decoder->table == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (http_decoder_table_status(decoder->table, HTTP_ITERM_URI) == RSTRING_STATUS_REFER)
|
||||
{
|
||||
http_decoder_table_cache(decoder->table, HTTP_ITERM_URI);
|
||||
}
|
||||
|
||||
if (http_decoder_table_status(decoder->table, HTTP_ITERM_STATUS) == RSTRING_STATUS_REFER)
|
||||
{
|
||||
http_decoder_table_cache(decoder->table, HTTP_ITERM_STATUS);
|
||||
}
|
||||
|
||||
if (http_decoder_table_status(decoder->table, HTTP_ITERM_HEADER_FILED) == RSTRING_STATUS_REFER)
|
||||
{
|
||||
http_decoder_table_cache(decoder->table, HTTP_ITERM_HEADER_FILED);
|
||||
}
|
||||
|
||||
if (http_decoder_table_status(decoder->table, HTTP_ITERM_HEADER_VALUE) == RSTRING_STATUS_REFER)
|
||||
{
|
||||
http_decoder_table_cache(decoder->table, HTTP_ITERM_HEADER_VALUE);
|
||||
}
|
||||
|
||||
// do not cache incomplete http body, submit immediately every time
|
||||
if (http_decoder_table_status(decoder->table, HTTP_ITERM_BODY) == RSTRING_STATUS_REFER ||
|
||||
http_decoder_table_status(decoder->table, HTTP_ITERM_BODY) == RSTRING_STATUS_CACHE)
|
||||
|
||||
{
|
||||
http_decoder_table_commit(decoder->table, HTTP_ITERM_BODY);
|
||||
}
|
||||
|
||||
if (decoder->commit_count)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// remove the data that has been consumed by the upper layer
|
||||
void http_decoder_remove(struct http_decoder *decoder)
|
||||
{
|
||||
assert(decoder);
|
||||
|
||||
if (decoder->table)
|
||||
{
|
||||
http_decoder_table_remove(decoder->table);
|
||||
}
|
||||
decoder->commit_count = 0;
|
||||
}
|
||||
|
||||
// for debug
|
||||
void http_decoder_dump(struct http_decoder *decoder)
|
||||
{
|
||||
uint64_t content_length = decoder->parser.content_length;
|
||||
uint8_t type = decoder->parser.type;
|
||||
uint8_t method = decoder->parser.method;
|
||||
uint8_t http_major = decoder->parser.http_major;
|
||||
uint8_t http_minor = decoder->parser.http_minor;
|
||||
uint8_t header_state = decoder->parser.header_state;
|
||||
uint8_t lenient_flags = decoder->parser.lenient_flags;
|
||||
uint8_t upgrade = decoder->parser.upgrade;
|
||||
uint8_t finish = decoder->parser.finish;
|
||||
uint16_t flags = decoder->parser.flags;
|
||||
uint16_t status_code = decoder->parser.status_code;
|
||||
|
||||
char *method_str = (char *)llhttp_method_name((llhttp_method_t)method);
|
||||
|
||||
printf("\n=====================================================\n");
|
||||
printf("content_length: %lu, type: %d, header_state: %d, lenient_flags: %d, upgrade: %d, finish: %d, flags: %d\n",
|
||||
content_length, type, header_state, lenient_flags, upgrade, finish, flags);
|
||||
printf("method: %d %s, http_major: %d, http_minor: %d, status_code: %d\n",
|
||||
method, method_str, http_major, http_minor, status_code);
|
||||
|
||||
if (decoder->table)
|
||||
{
|
||||
http_decoder_table_dump(decoder->table);
|
||||
}
|
||||
printf("=====================================================\n");
|
||||
}
|
||||
|
||||
// for gtest
|
||||
enum http_decoder_status http_decoder_status(struct http_decoder *decoder)
|
||||
{
|
||||
return decoder->status;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Consume decoded table
|
||||
******************************************************************************/
|
||||
|
||||
// HTTP_DIR_UNKNOWN: Not Find
|
||||
enum http_dir http_decoder_fetch_dir(struct http_decoder *decoder)
|
||||
{
|
||||
if (decoder->status >= ON_URI)
|
||||
{
|
||||
switch (decoder->parser.type)
|
||||
{
|
||||
case 1:
|
||||
return HTTP_DIR_REQUEST;
|
||||
break;
|
||||
case 2:
|
||||
return HTTP_DIR_RESPONSE;
|
||||
default:
|
||||
return HTTP_DIR_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return HTTP_DIR_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
// -1 : Not Find
|
||||
int http_decoder_fetch_status_code(struct http_decoder *decoder)
|
||||
{
|
||||
if (decoder->status >= ON_STATUS_COMPLETE && http_decoder_fetch_dir(decoder) == HTTP_DIR_RESPONSE)
|
||||
{
|
||||
return decoder->parser.status_code;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// -1 : Not Find
|
||||
int http_decoder_fetch_major_version(struct http_decoder *decoder)
|
||||
{
|
||||
if (decoder->status >= ON_HEADER_FIELD)
|
||||
{
|
||||
return decoder->parser.http_major;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// -1 : Not Find
|
||||
int http_decoder_fetch_minor_version(struct http_decoder *decoder)
|
||||
{
|
||||
if (decoder->status >= ON_HEADER_FIELD)
|
||||
{
|
||||
return decoder->parser.http_minor;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// ptr == NULL : Not Find
|
||||
void http_decoder_fetch_method(struct http_decoder *decoder, char **ptr, size_t *len)
|
||||
{
|
||||
if (decoder->status >= ON_URI && http_decoder_fetch_dir(decoder) == HTTP_DIR_REQUEST)
|
||||
{
|
||||
const char *method_str = llhttp_method_name((llhttp_method_t)decoder->parser.method);
|
||||
*ptr = (char *)method_str;
|
||||
*len = strlen(method_str);
|
||||
}
|
||||
else
|
||||
{
|
||||
*ptr = NULL;
|
||||
*len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// ptr == NULL : Not Find
|
||||
void http_decoder_fetch_uri(struct http_decoder *decoder, char **ptr, size_t *len)
|
||||
{
|
||||
http_decoder_table_get_uri(decoder->table, ptr, len);
|
||||
}
|
||||
|
||||
// ptr == NULL : Not Find
|
||||
void http_decoder_fetch_status(struct http_decoder *decoder, char **ptr, size_t *len)
|
||||
{
|
||||
http_decoder_table_get_status(decoder->table, ptr, len);
|
||||
}
|
||||
|
||||
// ptr == NULL : Not Find
|
||||
void http_decoder_fetch_body(struct http_decoder *decoder, char **ptr, size_t *len)
|
||||
{
|
||||
http_decoder_table_get_body(decoder->table, ptr, len);
|
||||
}
|
||||
|
||||
// filed_ptr == NULL : Not Find
|
||||
void http_decoder_fetch_next_header(struct http_decoder *decoder, int *iter_index,
|
||||
char **filed_ptr, size_t *filed_len, char **value_ptr, size_t *value_len)
|
||||
{
|
||||
http_decoder_table_next_header(decoder->table, iter_index, filed_ptr, filed_len, value_ptr, value_len);
|
||||
}
|
||||
81
src/protocol_decoder/http/http_decoder.h
Normal file
81
src/protocol_decoder/http/http_decoder.h
Normal file
@@ -0,0 +1,81 @@
|
||||
#ifndef _HTTP_DECODER_H
|
||||
#define _HTTP_DECODER_H
|
||||
|
||||
#ifdef __cpluscplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/******************************************************************************
|
||||
* Manipulate http decoder(Per HTTP Session)
|
||||
******************************************************************************/
|
||||
|
||||
enum http_decoder_status
|
||||
{
|
||||
ON_INIT = 0x1,
|
||||
ON_MESSAGE_BEGIN = 0x2,
|
||||
ON_URI = 0x3,
|
||||
ON_URI_COMPLETE = 0x4,
|
||||
ON_STATUS = 0x5,
|
||||
ON_STATUS_COMPLETE = 0x6,
|
||||
ON_HEADER_FIELD = 0x7,
|
||||
ON_HEADER_FIELD_COMPLETE = 0x8,
|
||||
ON_HEADER_VALUE = 0x9,
|
||||
ON_HEADER_VALUE_COMPLETE = 0xa,
|
||||
ON_CHUNK_HEADER = 0xb,
|
||||
ON_CHUNK_HEADER_COMPLETE = 0xc,
|
||||
ON_HEADERS_COMPLETE = 0xd,
|
||||
ON_BODY = 0xe,
|
||||
ON_MESSAGE_COMPLETE = 0xf,
|
||||
};
|
||||
|
||||
struct http_decoder;
|
||||
|
||||
struct http_decoder *http_decoder_create();
|
||||
void http_decoder_destory(struct http_decoder *decoder);
|
||||
|
||||
void http_decoder_init(struct http_decoder *decoder);
|
||||
void http_decoder_reset(struct http_decoder *decoder);
|
||||
|
||||
/*
|
||||
* return 0 : new data that needs to be consumed by upper layers has been parsed
|
||||
* return -1 : no new data
|
||||
* return -2 : error or not http protocol
|
||||
*/
|
||||
int http_decoder_dispatch(struct http_decoder *decoder, const char *data, size_t len);
|
||||
// remove the data that has been consumed by the upper layer
|
||||
void http_decoder_remove(struct http_decoder *decoder);
|
||||
|
||||
void http_decoder_dump(struct http_decoder *decoder); // for debug
|
||||
enum http_decoder_status http_decoder_status(struct http_decoder *decoder); // for gtest
|
||||
|
||||
/******************************************************************************
|
||||
* Consume decoded data
|
||||
******************************************************************************/
|
||||
|
||||
enum http_dir
|
||||
{
|
||||
HTTP_DIR_UNKNOWN = 0x0,
|
||||
HTTP_DIR_REQUEST = 0x1,
|
||||
HTTP_DIR_RESPONSE = 0x2,
|
||||
};
|
||||
|
||||
enum http_dir http_decoder_fetch_dir(struct http_decoder *decoder); // HTTP_DIR_UNKNOWN: Not Find
|
||||
int http_decoder_fetch_status_code(struct http_decoder *decoder); // -1 : Not Find
|
||||
int http_decoder_fetch_major_version(struct http_decoder *decoder); // -1 : Not Find
|
||||
int http_decoder_fetch_minor_version(struct http_decoder *decoder); // -1 : Not Find
|
||||
|
||||
void http_decoder_fetch_method(struct http_decoder *decoder, char **ptr, size_t *len); // ptr == NULL : Not Find
|
||||
void http_decoder_fetch_uri(struct http_decoder *decoder, char **ptr, size_t *len); // ptr == NULL : Not Find
|
||||
void http_decoder_fetch_status(struct http_decoder *decoder, char **ptr, size_t *len); // ptr == NULL : Not Find
|
||||
void http_decoder_fetch_body(struct http_decoder *decoder, char **ptr, size_t *len); // ptr == NULL : Not Find
|
||||
void http_decoder_fetch_next_header(struct http_decoder *decoder, int *iter_index,
|
||||
char **filed_ptr, size_t *filed_len, char **value_ptr, size_t *value_len); // filed_ptr == NULL : Not Find
|
||||
|
||||
#ifdef __cpluscplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
179
src/protocol_decoder/http/http_decoder_rstring.cpp
Normal file
179
src/protocol_decoder/http/http_decoder_rstring.cpp
Normal file
@@ -0,0 +1,179 @@
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "http_decoder_util.h"
|
||||
#include "http_decoder_rstring.h"
|
||||
|
||||
static const char *rstring_status_to_desc(enum rstring_status status)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case RSTRING_STATUS_INIT:
|
||||
return "INIT";
|
||||
break;
|
||||
case RSTRING_STATUS_REFER:
|
||||
return "REFER";
|
||||
break;
|
||||
case RSTRING_STATUS_CACHE:
|
||||
return "CACHE";
|
||||
break;
|
||||
case RSTRING_STATUS_COMMIT:
|
||||
return "COMMIT";
|
||||
break;
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// RSTRING_STATUS_INIT -> RSTRING_STATUS_REFER
|
||||
// RSTRING_STATUS_CACHE -> RSTRING_STATUS_REFER
|
||||
void http_decoder_rstring_refer(struct http_decoder_rstring *rstr, const char *at, size_t length)
|
||||
{
|
||||
assert(rstr);
|
||||
|
||||
switch (rstr->status)
|
||||
{
|
||||
case RSTRING_STATUS_INIT:
|
||||
case RSTRING_STATUS_CACHE:
|
||||
rstr->refer.str = (char *)at;
|
||||
rstr->refer.len = length;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
|
||||
rstr->status = RSTRING_STATUS_REFER;
|
||||
}
|
||||
|
||||
// RSTRING_STATUS_REFER -> RSTRING_STATUS_CACHE
|
||||
void http_decoder_rstring_cache(struct http_decoder_rstring *rstr)
|
||||
{
|
||||
assert(rstr);
|
||||
|
||||
switch (rstr->status)
|
||||
{
|
||||
case RSTRING_STATUS_REFER:
|
||||
if (rstr->refer.len > 0)
|
||||
{
|
||||
rstr->cache.str = http_decoder_safe_realloc(char, rstr->cache.str, rstr->cache.len + rstr->refer.len);
|
||||
memcpy(rstr->cache.str + rstr->cache.len, rstr->refer.str, rstr->refer.len);
|
||||
rstr->cache.len += rstr->refer.len;
|
||||
|
||||
rstr->refer.str = NULL;
|
||||
rstr->refer.len = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
|
||||
rstr->status = RSTRING_STATUS_CACHE;
|
||||
}
|
||||
|
||||
// RSTRING_STATUS_REFER -> RSTRING_STATUS_COMMIT
|
||||
// RSTRING_STATUS_CACHE -> RSTRING_STATUS_COMMIT
|
||||
void http_decoder_rstring_commit(struct http_decoder_rstring *rstr)
|
||||
{
|
||||
assert(rstr);
|
||||
|
||||
switch (rstr->status)
|
||||
{
|
||||
case RSTRING_STATUS_REFER:
|
||||
if (rstr->cache.len)
|
||||
{
|
||||
http_decoder_rstring_cache(rstr);
|
||||
|
||||
rstr->commit.str = rstr->cache.str;
|
||||
rstr->commit.len = rstr->cache.len;
|
||||
// not overwrite rstr->cache.str
|
||||
}
|
||||
else
|
||||
{
|
||||
rstr->commit.str = rstr->refer.str;
|
||||
rstr->commit.len = rstr->refer.len;
|
||||
|
||||
rstr->refer.str = NULL;
|
||||
rstr->refer.len = 0;
|
||||
}
|
||||
break;
|
||||
case RSTRING_STATUS_CACHE:
|
||||
rstr->commit.str = rstr->cache.str;
|
||||
rstr->commit.len = rstr->cache.len;
|
||||
// not overwrite rstr->cache.str
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
|
||||
rstr->status = RSTRING_STATUS_COMMIT;
|
||||
}
|
||||
|
||||
// RSTRING_STATUS_INIT -> RSTRING_STATUS_INIT
|
||||
// RSTRING_STATUS_REFER -> RSTRING_STATUS_INIT
|
||||
// RSTRING_STATUS_CACHE -> RSTRING_STATUS_INIT
|
||||
// RSTRING_STATUS_COMMIT -> RSTRING_STATUS_INIT
|
||||
void http_decoder_rstring_reset(struct http_decoder_rstring *rstr)
|
||||
{
|
||||
assert(rstr);
|
||||
|
||||
switch (rstr->status)
|
||||
{
|
||||
case RSTRING_STATUS_INIT:
|
||||
case RSTRING_STATUS_REFER:
|
||||
case RSTRING_STATUS_CACHE:
|
||||
case RSTRING_STATUS_COMMIT:
|
||||
http_decoder_safe_free(rstr->cache.str);
|
||||
memset(rstr, 0, sizeof(struct http_decoder_rstring));
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
|
||||
rstr->status = RSTRING_STATUS_INIT;
|
||||
}
|
||||
|
||||
enum rstring_status http_decoder_rstring_status(struct http_decoder_rstring *rstr)
|
||||
{
|
||||
return rstr->status;
|
||||
}
|
||||
|
||||
void http_decoder_rstring_read(struct http_decoder_rstring *rstr, char **ptr, size_t *len)
|
||||
{
|
||||
assert(rstr);
|
||||
|
||||
if (http_decoder_rstring_status(rstr) == RSTRING_STATUS_COMMIT)
|
||||
{
|
||||
*ptr = rstr->commit.str;
|
||||
*len = rstr->commit.len;
|
||||
}
|
||||
else
|
||||
{
|
||||
*ptr = NULL;
|
||||
*len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void http_decoder_rstring_dump(struct http_decoder_rstring *rstr, const char *desc)
|
||||
{
|
||||
assert(rstr);
|
||||
|
||||
char *refer_str = http_decoder_safe_dup(rstr->refer.str, rstr->refer.len);
|
||||
char *cache_str = http_decoder_safe_dup(rstr->cache.str, rstr->cache.len);
|
||||
char *commit_str = http_decoder_safe_dup(rstr->commit.str, rstr->commit.len);
|
||||
|
||||
printf("%s: status: %s, refer: {len: %02zu, str: %s}, cache: {len: %02zu, str: %s}, commit: {len: %02zu, str: %s}\n",
|
||||
desc, rstring_status_to_desc(rstr->status),
|
||||
rstr->refer.len, refer_str,
|
||||
rstr->cache.len, cache_str,
|
||||
rstr->commit.len, commit_str);
|
||||
|
||||
http_decoder_safe_free(refer_str);
|
||||
http_decoder_safe_free(cache_str);
|
||||
http_decoder_safe_free(commit_str);
|
||||
}
|
||||
90
src/protocol_decoder/http/http_decoder_rstring.h
Normal file
90
src/protocol_decoder/http/http_decoder_rstring.h
Normal file
@@ -0,0 +1,90 @@
|
||||
#ifndef _HTTP_DECODER_RSTRING_H
|
||||
#define _HTTP_DECODER_RSTRING_H
|
||||
|
||||
#ifdef __cpluscplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
enum rstring_status
|
||||
{
|
||||
RSTRING_STATUS_INIT,
|
||||
RSTRING_STATUS_REFER,
|
||||
RSTRING_STATUS_CACHE,
|
||||
RSTRING_STATUS_COMMIT,
|
||||
};
|
||||
|
||||
struct rstring
|
||||
{
|
||||
char *str;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
struct http_decoder_rstring
|
||||
{
|
||||
struct rstring refer; // shallow copy
|
||||
struct rstring cache; // deep copy
|
||||
struct rstring commit;
|
||||
|
||||
enum rstring_status status;
|
||||
};
|
||||
|
||||
/* state transition diagram
|
||||
* +----------+
|
||||
* | |
|
||||
* \|/ |
|
||||
* +------+ |
|
||||
* | init | |
|
||||
* +------+ |
|
||||
* | |
|
||||
* +---->| |
|
||||
* | \|/ |
|
||||
* | +-------+ |
|
||||
* | | refer |--+ |
|
||||
* | +-------+ | |
|
||||
* | | | |
|
||||
* | \|/ | |
|
||||
* | +-------+ | |
|
||||
* +--| cache | | |
|
||||
* +-------+ | |
|
||||
* | | |
|
||||
* |<------+ |
|
||||
* \|/ |
|
||||
* +--------+ |
|
||||
* | commit | |
|
||||
* +--------+ |
|
||||
* | |
|
||||
* \|/ |
|
||||
* +--------+ |
|
||||
* | reset |----+
|
||||
* +--------+
|
||||
*/
|
||||
|
||||
// RSTRING_STATUS_INIT -> RSTRING_STATUS_REFER
|
||||
// RSTRING_STATUS_CACHE -> RSTRING_STATUS_REFER
|
||||
void http_decoder_rstring_refer(struct http_decoder_rstring *rstr, const char *at, size_t length);
|
||||
|
||||
// RSTRING_STATUS_REFER -> RSTRING_STATUS_CACHE
|
||||
void http_decoder_rstring_cache(struct http_decoder_rstring *rstr);
|
||||
|
||||
// RSTRING_STATUS_REFER -> RSTRING_STATUS_COMMIT
|
||||
// RSTRING_STATUS_CACHE -> RSTRING_STATUS_COMMIT
|
||||
void http_decoder_rstring_commit(struct http_decoder_rstring *rstr);
|
||||
|
||||
// RSTRING_STATUS_INIT -> RSTRING_STATUS_INIT
|
||||
// RSTRING_STATUS_REFER -> RSTRING_STATUS_INIT
|
||||
// RSTRING_STATUS_CACHE -> RSTRING_STATUS_INIT
|
||||
// RSTRING_STATUS_COMMIT -> RSTRING_STATUS_INIT
|
||||
void http_decoder_rstring_reset(struct http_decoder_rstring *rstr);
|
||||
|
||||
enum rstring_status http_decoder_rstring_status(struct http_decoder_rstring *rstr);
|
||||
void http_decoder_rstring_read(struct http_decoder_rstring *rstr, char **ptr, size_t *len);
|
||||
void http_decoder_rstring_dump(struct http_decoder_rstring *rstr, const char *desc);
|
||||
|
||||
#ifdef __cpluscplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
344
src/protocol_decoder/http/http_decoder_table.cpp
Normal file
344
src/protocol_decoder/http/http_decoder_table.cpp
Normal file
@@ -0,0 +1,344 @@
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "http_decoder_util.h"
|
||||
#include "http_decoder_rstring.h"
|
||||
#include "http_decoder_table.h"
|
||||
|
||||
struct http_decoder_header
|
||||
{
|
||||
struct http_decoder_rstring filed;
|
||||
struct http_decoder_rstring value;
|
||||
};
|
||||
|
||||
struct http_decoder_table
|
||||
{
|
||||
struct http_decoder_rstring uri;
|
||||
struct http_decoder_rstring status;
|
||||
struct http_decoder_rstring body;
|
||||
|
||||
int header_size;
|
||||
int header_index;
|
||||
struct http_decoder_header *headers;
|
||||
};
|
||||
|
||||
struct http_decoder_table *http_decoder_table_create()
|
||||
{
|
||||
struct http_decoder_table *table = http_decoder_safe_alloc(struct http_decoder_table, 1);
|
||||
assert(table);
|
||||
|
||||
table->header_size = 16;
|
||||
table->headers = http_decoder_safe_alloc(struct http_decoder_header, table->header_size);
|
||||
assert(table->headers);
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
void http_decoder_table_destory(struct http_decoder_table *table)
|
||||
{
|
||||
if (table)
|
||||
{
|
||||
http_decoder_table_reset(table);
|
||||
http_decoder_safe_free(table->headers);
|
||||
http_decoder_safe_free(table);
|
||||
}
|
||||
}
|
||||
|
||||
void http_decoder_table_reset(struct http_decoder_table *table)
|
||||
{
|
||||
assert(table);
|
||||
|
||||
http_decoder_rstring_reset(&table->uri);
|
||||
http_decoder_rstring_reset(&table->status);
|
||||
http_decoder_rstring_reset(&table->body);
|
||||
|
||||
for (int i = 0; i < table->header_size; i++)
|
||||
{
|
||||
struct http_decoder_header *header = &table->headers[i];
|
||||
http_decoder_rstring_reset(&header->filed);
|
||||
http_decoder_rstring_reset(&header->value);
|
||||
}
|
||||
|
||||
int header_size = table->header_size;
|
||||
struct http_decoder_header *headers = table->headers;
|
||||
|
||||
memset(table->headers, 0, sizeof(struct http_decoder_header) * table->header_size);
|
||||
memset(table, 0, sizeof(struct http_decoder_table));
|
||||
|
||||
table->header_size = header_size;
|
||||
table->headers = headers;
|
||||
}
|
||||
|
||||
void http_decoder_table_add(struct http_decoder_table *table, enum http_iterm type, const char *str, size_t len)
|
||||
{
|
||||
struct http_decoder_header *header = NULL;
|
||||
assert(table);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case HTTP_ITERM_URI:
|
||||
http_decoder_rstring_refer(&table->uri, str, len);
|
||||
break;
|
||||
case HTTP_ITERM_STATUS:
|
||||
http_decoder_rstring_refer(&table->status, str, len);
|
||||
break;
|
||||
case HTTP_ITERM_HEADER_FILED:
|
||||
if (table->header_index >= table->header_size)
|
||||
{
|
||||
table->headers = http_decoder_safe_realloc(struct http_decoder_header, table->headers, table->header_size * 2 * sizeof(struct http_decoder_header));
|
||||
assert(table->headers);
|
||||
table->header_size *= 2;
|
||||
for (int i = table->header_index; i < table->header_size; i++)
|
||||
{
|
||||
header = &table->headers[i];
|
||||
memset(header, 0, sizeof(struct http_decoder_header));
|
||||
}
|
||||
}
|
||||
header = &table->headers[table->header_index];
|
||||
http_decoder_rstring_refer(&header->filed, str, len);
|
||||
break;
|
||||
case HTTP_ITERM_HEADER_VALUE:
|
||||
header = &table->headers[table->header_index];
|
||||
http_decoder_rstring_refer(&header->value, str, len);
|
||||
break;
|
||||
case HTTP_ITERM_BODY:
|
||||
http_decoder_rstring_refer(&table->body, str, len);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void http_decoder_table_cache(struct http_decoder_table *table, enum http_iterm type)
|
||||
{
|
||||
struct http_decoder_header *header = NULL;
|
||||
assert(table);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case HTTP_ITERM_URI:
|
||||
http_decoder_rstring_cache(&table->uri);
|
||||
break;
|
||||
case HTTP_ITERM_STATUS:
|
||||
http_decoder_rstring_cache(&table->status);
|
||||
break;
|
||||
case HTTP_ITERM_HEADER_FILED:
|
||||
header = &table->headers[table->header_index];
|
||||
http_decoder_rstring_cache(&header->filed);
|
||||
break;
|
||||
case HTTP_ITERM_HEADER_VALUE:
|
||||
header = &table->headers[table->header_index];
|
||||
http_decoder_rstring_cache(&header->value);
|
||||
break;
|
||||
case HTTP_ITERM_BODY:
|
||||
http_decoder_rstring_cache(&table->body);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void http_decoder_table_commit(struct http_decoder_table *table, enum http_iterm type)
|
||||
{
|
||||
struct http_decoder_header *header = NULL;
|
||||
assert(table);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case HTTP_ITERM_URI:
|
||||
http_decoder_rstring_commit(&table->uri);
|
||||
break;
|
||||
case HTTP_ITERM_STATUS:
|
||||
http_decoder_rstring_commit(&table->status);
|
||||
break;
|
||||
case HTTP_ITERM_HEADER_FILED:
|
||||
header = &table->headers[table->header_index];
|
||||
http_decoder_rstring_commit(&header->filed);
|
||||
break;
|
||||
case HTTP_ITERM_HEADER_VALUE:
|
||||
header = &table->headers[table->header_index];
|
||||
http_decoder_rstring_commit(&header->value);
|
||||
|
||||
// inc index
|
||||
table->header_index++;
|
||||
break;
|
||||
case HTTP_ITERM_BODY:
|
||||
http_decoder_rstring_commit(&table->body);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void http_decoder_table_remove(struct http_decoder_table *table)
|
||||
{
|
||||
assert(table);
|
||||
|
||||
if (http_decoder_rstring_status(&table->uri) == RSTRING_STATUS_COMMIT)
|
||||
{
|
||||
http_decoder_rstring_reset(&table->uri);
|
||||
}
|
||||
|
||||
if (http_decoder_rstring_status(&table->status) == RSTRING_STATUS_COMMIT)
|
||||
{
|
||||
http_decoder_rstring_reset(&table->status);
|
||||
}
|
||||
|
||||
if (http_decoder_rstring_status(&table->body) == RSTRING_STATUS_COMMIT)
|
||||
{
|
||||
http_decoder_rstring_reset(&table->body);
|
||||
}
|
||||
|
||||
for (int i = 0; i <= table->header_index; i++)
|
||||
{
|
||||
struct http_decoder_header *header = &table->headers[i];
|
||||
if (http_decoder_rstring_status(&header->filed) == RSTRING_STATUS_COMMIT && http_decoder_rstring_status(&header->value) == RSTRING_STATUS_COMMIT)
|
||||
{
|
||||
http_decoder_rstring_reset(&header->filed);
|
||||
http_decoder_rstring_reset(&header->value);
|
||||
}
|
||||
}
|
||||
|
||||
if (table->header_index != 0)
|
||||
{
|
||||
struct http_decoder_header *last_header = &table->headers[table->header_index];
|
||||
if (http_decoder_rstring_status(&last_header->filed) == RSTRING_STATUS_CACHE || http_decoder_rstring_status(&last_header->value) == RSTRING_STATUS_CACHE)
|
||||
{
|
||||
memmove(&table->headers[0], last_header, sizeof(struct http_decoder_header));
|
||||
memset(last_header, 0, sizeof(struct http_decoder_header));
|
||||
}
|
||||
|
||||
table->header_index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void http_decoder_table_dump(struct http_decoder_table *table)
|
||||
{
|
||||
assert(table);
|
||||
|
||||
http_decoder_rstring_dump(&table->uri, "uri");
|
||||
http_decoder_rstring_dump(&table->status, "status");
|
||||
http_decoder_rstring_dump(&table->body, "body");
|
||||
|
||||
for (int i = 0; i <= table->header_index; i++)
|
||||
{
|
||||
struct http_decoder_header *header = &table->headers[i];
|
||||
http_decoder_rstring_dump(&header->filed, "filed");
|
||||
http_decoder_rstring_dump(&header->value, "value");
|
||||
}
|
||||
}
|
||||
|
||||
enum rstring_status http_decoder_table_status(struct http_decoder_table *table, enum http_iterm type)
|
||||
{
|
||||
struct http_decoder_header *header = NULL;
|
||||
enum rstring_status status = RSTRING_STATUS_INIT;
|
||||
assert(table);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case HTTP_ITERM_URI:
|
||||
status = http_decoder_rstring_status(&table->uri);
|
||||
break;
|
||||
case HTTP_ITERM_STATUS:
|
||||
status = http_decoder_rstring_status(&table->status);
|
||||
break;
|
||||
case HTTP_ITERM_HEADER_FILED:
|
||||
header = &table->headers[table->header_index];
|
||||
status = http_decoder_rstring_status(&header->filed);
|
||||
break;
|
||||
case HTTP_ITERM_HEADER_VALUE:
|
||||
header = &table->headers[table->header_index];
|
||||
status = http_decoder_rstring_status(&header->value);
|
||||
break;
|
||||
case HTTP_ITERM_BODY:
|
||||
status = http_decoder_rstring_status(&table->body);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void http_decoder_table_get_uri(struct http_decoder_table *table, char **ptr, size_t *len)
|
||||
{
|
||||
assert(table);
|
||||
|
||||
if (http_decoder_rstring_status(&table->uri) == RSTRING_STATUS_COMMIT)
|
||||
{
|
||||
http_decoder_rstring_read(&table->uri, ptr, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
*ptr = NULL;
|
||||
*len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void http_decoder_table_get_status(struct http_decoder_table *table, char **ptr, size_t *len)
|
||||
{
|
||||
assert(table);
|
||||
|
||||
if (http_decoder_rstring_status(&table->status) == RSTRING_STATUS_COMMIT)
|
||||
{
|
||||
http_decoder_rstring_read(&table->status, ptr, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
*ptr = NULL;
|
||||
*len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void http_decoder_table_get_body(struct http_decoder_table *table, char **ptr, size_t *len)
|
||||
{
|
||||
assert(table);
|
||||
|
||||
if (http_decoder_rstring_status(&table->body) == RSTRING_STATUS_COMMIT)
|
||||
{
|
||||
http_decoder_rstring_read(&table->body, ptr, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
*ptr = NULL;
|
||||
*len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void http_decoder_table_next_header(struct http_decoder_table *table, int *iter_index, char **filed_ptr, size_t *filed_len, char **value_ptr, size_t *value_len)
|
||||
{
|
||||
assert(table);
|
||||
|
||||
if (*iter_index <= table->header_index)
|
||||
{
|
||||
struct http_decoder_header *header = &table->headers[*iter_index];
|
||||
if (http_decoder_rstring_status(&header->filed) == RSTRING_STATUS_COMMIT && http_decoder_rstring_status(&header->value) == RSTRING_STATUS_COMMIT)
|
||||
{
|
||||
http_decoder_rstring_read(&header->filed, filed_ptr, filed_len);
|
||||
http_decoder_rstring_read(&header->value, value_ptr, value_len);
|
||||
}
|
||||
else
|
||||
{
|
||||
*filed_ptr = NULL;
|
||||
*filed_len = 0;
|
||||
|
||||
*value_ptr = NULL;
|
||||
*value_len = 0;
|
||||
}
|
||||
*iter_index = *iter_index + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
*filed_ptr = NULL;
|
||||
*filed_len = 0;
|
||||
|
||||
*value_ptr = NULL;
|
||||
*value_len = 0;
|
||||
}
|
||||
}
|
||||
45
src/protocol_decoder/http/http_decoder_table.h
Normal file
45
src/protocol_decoder/http/http_decoder_table.h
Normal file
@@ -0,0 +1,45 @@
|
||||
#ifndef _HTTP_DECODER_TABLE_H
|
||||
#define _HTTP_DECODER_TABLE_H
|
||||
|
||||
#ifdef __cpluscplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "http_decoder_rstring.h"
|
||||
|
||||
enum http_iterm
|
||||
{
|
||||
HTTP_ITERM_URI = 0x01,
|
||||
HTTP_ITERM_STATUS = 0x02,
|
||||
HTTP_ITERM_HEADER_FILED = 0x03,
|
||||
HTTP_ITERM_HEADER_VALUE = 0x04,
|
||||
HTTP_ITERM_BODY = 0x05,
|
||||
};
|
||||
|
||||
struct http_decoder_table;
|
||||
|
||||
struct http_decoder_table *http_decoder_table_create();
|
||||
void http_decoder_table_destory(struct http_decoder_table *table);
|
||||
void http_decoder_table_reset(struct http_decoder_table *table);
|
||||
|
||||
void http_decoder_table_add(struct http_decoder_table *table, enum http_iterm type, const char *str, size_t len);
|
||||
void http_decoder_table_cache(struct http_decoder_table *table, enum http_iterm type);
|
||||
void http_decoder_table_commit(struct http_decoder_table *table, enum http_iterm type);
|
||||
void http_decoder_table_remove(struct http_decoder_table *table);
|
||||
void http_decoder_table_dump(struct http_decoder_table *table);
|
||||
enum rstring_status http_decoder_table_status(struct http_decoder_table *table, enum http_iterm type);
|
||||
|
||||
void http_decoder_table_get_uri(struct http_decoder_table *table, char **ptr, size_t *len);
|
||||
void http_decoder_table_get_status(struct http_decoder_table *table, char **ptr, size_t *len);
|
||||
void http_decoder_table_get_body(struct http_decoder_table *table, char **ptr, size_t *len);
|
||||
|
||||
void http_decoder_table_next_header(struct http_decoder_table *table, int *iter_index, char **filed_ptr, size_t *filed_len, char **value_ptr, size_t *value_len);
|
||||
|
||||
#ifdef __cpluscplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
16
src/protocol_decoder/http/http_decoder_util.cpp
Normal file
16
src/protocol_decoder/http/http_decoder_util.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "http_decoder_util.h"
|
||||
|
||||
char *http_decoder_safe_dup(const char *str, size_t len)
|
||||
{
|
||||
if (str == NULL || len == 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *dup = http_decoder_safe_alloc(char, len + 1);
|
||||
memcpy(dup, str, len);
|
||||
|
||||
return dup;
|
||||
}
|
||||
61
src/protocol_decoder/http/http_decoder_util.h
Normal file
61
src/protocol_decoder/http/http_decoder_util.h
Normal file
@@ -0,0 +1,61 @@
|
||||
#ifndef _HTTP_DECODER_UTIL_H
|
||||
#define _HTTP_DECODER_UTIL_H
|
||||
|
||||
#ifdef __cpluscplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/******************************************************************************
|
||||
* Malloc
|
||||
******************************************************************************/
|
||||
|
||||
#define http_decoder_safe_realloc(type, ptr, number) ((type *)realloc(ptr, number))
|
||||
#define http_decoder_safe_alloc(type, number) ((type *)calloc(number, sizeof(type)))
|
||||
#define http_decoder_safe_free(ptr) \
|
||||
{ \
|
||||
if (ptr) \
|
||||
{ \
|
||||
free(ptr); \
|
||||
ptr = NULL; \
|
||||
} \
|
||||
}
|
||||
char *http_decoder_safe_dup(const char *str, size_t len);
|
||||
|
||||
/******************************************************************************
|
||||
* Offset
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef offsetof
|
||||
#define offsetof(TYPE, MEMBER) __builtin_offsetof(TYPE, MEMBER)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Return pointer to the wrapping struct instance.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* struct wrapper {
|
||||
* ...
|
||||
* struct child c;
|
||||
* ...
|
||||
* };
|
||||
*
|
||||
* struct child *x = obtain(...);
|
||||
* struct wrapper *w = container_of(x, struct wrapper, c);
|
||||
*/
|
||||
#ifndef container_of
|
||||
#define container_of(ptr, type, member) __extension__({ \
|
||||
const typeof(((type *)0)->member) *_ptr = (ptr); \
|
||||
__attribute__((unused)) type *_target_ptr = (type *)(ptr); \
|
||||
(type *)(((uintptr_t)_ptr) - offsetof(type, member)); \
|
||||
})
|
||||
#endif
|
||||
|
||||
#ifdef __cpluscplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
38
src/protocol_decoder/http/test/CMakeLists.txt
Normal file
38
src/protocol_decoder/http/test/CMakeLists.txt
Normal file
@@ -0,0 +1,38 @@
|
||||
add_executable(http_decoder_rstring_test
|
||||
http_decoder_rstring_test.cpp
|
||||
)
|
||||
|
||||
add_executable(http_decoder_table_test
|
||||
http_decoder_table_test.cpp
|
||||
)
|
||||
|
||||
add_executable(http_decoder_test
|
||||
http_decoder_test.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
http_decoder_rstring_test
|
||||
gtest
|
||||
http
|
||||
llhttp-static
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
http_decoder_table_test
|
||||
gtest
|
||||
http
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
http_decoder_test
|
||||
gtest
|
||||
http
|
||||
)
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wl,--export-dynamic")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,--export-dynamic")
|
||||
|
||||
include(GoogleTest)
|
||||
gtest_discover_tests(http_decoder_rstring_test)
|
||||
gtest_discover_tests(http_decoder_table_test)
|
||||
gtest_discover_tests(http_decoder_test)
|
||||
328
src/protocol_decoder/http/test/http_decoder_rstring_test.cpp
Normal file
328
src/protocol_decoder/http/test/http_decoder_rstring_test.cpp
Normal file
@@ -0,0 +1,328 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "../http_decoder_util.h"
|
||||
#include "../http_decoder_rstring.h"
|
||||
|
||||
TEST(HTTP_DECODER_RSTRING_TEST, refer_commit_reset)
|
||||
{
|
||||
char *ptr = NULL;
|
||||
size_t len = 0;
|
||||
struct http_decoder_rstring rstr = {0};
|
||||
char *hello_str = http_decoder_safe_dup("Hello111", 8);
|
||||
|
||||
// refer
|
||||
http_decoder_rstring_refer(&rstr, hello_str, 5);
|
||||
http_decoder_rstring_dump(&rstr, "After refer");
|
||||
|
||||
EXPECT_TRUE(http_decoder_rstring_status(&rstr) == RSTRING_STATUS_REFER);
|
||||
EXPECT_TRUE(rstr.refer.len == 5);
|
||||
EXPECT_TRUE(strncmp(rstr.refer.str, "Hello", 5) == 0);
|
||||
EXPECT_TRUE(rstr.cache.len == 0);
|
||||
EXPECT_TRUE(rstr.cache.str == NULL);
|
||||
EXPECT_TRUE(rstr.commit.len == 0);
|
||||
EXPECT_TRUE(rstr.commit.str == NULL);
|
||||
|
||||
http_decoder_rstring_read(&rstr, &ptr, &len);
|
||||
EXPECT_TRUE(NULL == ptr && len == 0);
|
||||
|
||||
// commit
|
||||
http_decoder_rstring_commit(&rstr);
|
||||
http_decoder_rstring_dump(&rstr, "After commit");
|
||||
|
||||
EXPECT_TRUE(http_decoder_rstring_status(&rstr) == RSTRING_STATUS_COMMIT);
|
||||
EXPECT_TRUE(rstr.refer.len == 0);
|
||||
EXPECT_TRUE(rstr.refer.str == NULL);
|
||||
EXPECT_TRUE(rstr.cache.len == 0);
|
||||
EXPECT_TRUE(rstr.cache.str == NULL);
|
||||
EXPECT_TRUE(rstr.commit.len == 5);
|
||||
EXPECT_TRUE(strncmp(rstr.commit.str, "Hello", 5) == 0);
|
||||
|
||||
http_decoder_rstring_read(&rstr, &ptr, &len);
|
||||
EXPECT_TRUE(strncmp("Hello", ptr, len) == 0);
|
||||
|
||||
// reset
|
||||
http_decoder_rstring_reset(&rstr);
|
||||
http_decoder_rstring_dump(&rstr, "After reset");
|
||||
|
||||
EXPECT_TRUE(http_decoder_rstring_status(&rstr) == RSTRING_STATUS_INIT);
|
||||
EXPECT_TRUE(rstr.refer.len == 0);
|
||||
EXPECT_TRUE(rstr.refer.str == NULL);
|
||||
EXPECT_TRUE(rstr.cache.len == 0);
|
||||
EXPECT_TRUE(rstr.cache.str == NULL);
|
||||
EXPECT_TRUE(rstr.commit.len == 0);
|
||||
EXPECT_TRUE(rstr.commit.str == NULL);
|
||||
|
||||
http_decoder_rstring_read(&rstr, &ptr, &len);
|
||||
EXPECT_TRUE(NULL == ptr && len == 0);
|
||||
|
||||
http_decoder_safe_free(hello_str);
|
||||
}
|
||||
|
||||
TEST(HTTP_DECODER_RSTRING_TEST, refer_cache_commit_reset)
|
||||
{
|
||||
char *ptr = NULL;
|
||||
size_t len = 0;
|
||||
struct http_decoder_rstring rstr = {0};
|
||||
char *hello_str = http_decoder_safe_dup("Hello111", 8);
|
||||
|
||||
// refer
|
||||
http_decoder_rstring_refer(&rstr, hello_str, 5);
|
||||
http_decoder_rstring_dump(&rstr, "After refer");
|
||||
|
||||
EXPECT_TRUE(http_decoder_rstring_status(&rstr) == RSTRING_STATUS_REFER);
|
||||
EXPECT_TRUE(rstr.refer.len == 5);
|
||||
EXPECT_TRUE(strncmp(rstr.refer.str, "Hello", 5) == 0);
|
||||
EXPECT_TRUE(rstr.cache.len == 0);
|
||||
EXPECT_TRUE(rstr.cache.str == NULL);
|
||||
EXPECT_TRUE(rstr.commit.len == 0);
|
||||
EXPECT_TRUE(rstr.commit.str == NULL);
|
||||
|
||||
http_decoder_rstring_read(&rstr, &ptr, &len);
|
||||
EXPECT_TRUE(NULL == ptr && len == 0);
|
||||
|
||||
// cache
|
||||
http_decoder_rstring_cache(&rstr);
|
||||
http_decoder_rstring_dump(&rstr, "After cache");
|
||||
|
||||
EXPECT_TRUE(http_decoder_rstring_status(&rstr) == RSTRING_STATUS_CACHE);
|
||||
EXPECT_TRUE(rstr.refer.len == 0);
|
||||
EXPECT_TRUE(rstr.refer.str == NULL);
|
||||
EXPECT_TRUE(rstr.cache.len == 5);
|
||||
EXPECT_TRUE(strncmp(rstr.cache.str, "Hello", 5) == 0);
|
||||
EXPECT_TRUE(rstr.commit.len == 0);
|
||||
EXPECT_TRUE(rstr.commit.str == NULL);
|
||||
|
||||
http_decoder_rstring_read(&rstr, &ptr, &len);
|
||||
EXPECT_TRUE(NULL == ptr && len == 0);
|
||||
|
||||
http_decoder_safe_free(hello_str);
|
||||
|
||||
// commit
|
||||
http_decoder_rstring_commit(&rstr);
|
||||
http_decoder_rstring_dump(&rstr, "After commit");
|
||||
|
||||
EXPECT_TRUE(http_decoder_rstring_status(&rstr) == RSTRING_STATUS_COMMIT);
|
||||
EXPECT_TRUE(rstr.refer.len == 0);
|
||||
EXPECT_TRUE(rstr.refer.str == NULL);
|
||||
EXPECT_TRUE(rstr.cache.len == 5);
|
||||
EXPECT_TRUE(strncmp(rstr.cache.str, "Hello", 5) == 0);
|
||||
EXPECT_TRUE(rstr.commit.len == 5);
|
||||
EXPECT_TRUE(strncmp(rstr.commit.str, "Hello", 5) == 0);
|
||||
|
||||
http_decoder_rstring_read(&rstr, &ptr, &len);
|
||||
EXPECT_TRUE(strncmp("Hello", ptr, len) == 0);
|
||||
|
||||
// reset
|
||||
http_decoder_rstring_reset(&rstr);
|
||||
http_decoder_rstring_dump(&rstr, "After reset");
|
||||
|
||||
EXPECT_TRUE(http_decoder_rstring_status(&rstr) == RSTRING_STATUS_INIT);
|
||||
EXPECT_TRUE(rstr.refer.len == 0);
|
||||
EXPECT_TRUE(rstr.refer.str == NULL);
|
||||
EXPECT_TRUE(rstr.cache.len == 0);
|
||||
EXPECT_TRUE(rstr.cache.str == NULL);
|
||||
EXPECT_TRUE(rstr.commit.len == 0);
|
||||
EXPECT_TRUE(rstr.commit.str == NULL);
|
||||
|
||||
http_decoder_rstring_read(&rstr, &ptr, &len);
|
||||
EXPECT_TRUE(NULL == ptr && len == 0);
|
||||
}
|
||||
|
||||
TEST(HTTP_DECODER_RSTRING_TEST, refer_cache_refer_commit_reset)
|
||||
{
|
||||
char *ptr = NULL;
|
||||
size_t len = 0;
|
||||
struct http_decoder_rstring rstr = {0};
|
||||
char *hello_str = http_decoder_safe_dup("Hello111", 8);
|
||||
char *world_str = http_decoder_safe_dup("World222", 8);
|
||||
|
||||
// refer
|
||||
http_decoder_rstring_refer(&rstr, hello_str, 5);
|
||||
http_decoder_rstring_dump(&rstr, "After refer");
|
||||
|
||||
EXPECT_TRUE(http_decoder_rstring_status(&rstr) == RSTRING_STATUS_REFER);
|
||||
EXPECT_TRUE(rstr.refer.len == 5);
|
||||
EXPECT_TRUE(strncmp(rstr.refer.str, "Hello", 5) == 0);
|
||||
EXPECT_TRUE(rstr.cache.len == 0);
|
||||
EXPECT_TRUE(rstr.cache.str == NULL);
|
||||
EXPECT_TRUE(rstr.commit.len == 0);
|
||||
EXPECT_TRUE(rstr.commit.str == NULL);
|
||||
|
||||
http_decoder_rstring_read(&rstr, &ptr, &len);
|
||||
EXPECT_TRUE(NULL == ptr && len == 0);
|
||||
|
||||
// cache
|
||||
http_decoder_rstring_cache(&rstr);
|
||||
http_decoder_rstring_dump(&rstr, "After cache");
|
||||
|
||||
EXPECT_TRUE(http_decoder_rstring_status(&rstr) == RSTRING_STATUS_CACHE);
|
||||
EXPECT_TRUE(rstr.refer.len == 0);
|
||||
EXPECT_TRUE(rstr.refer.str == NULL);
|
||||
EXPECT_TRUE(rstr.cache.len == 5);
|
||||
EXPECT_TRUE(strncmp(rstr.cache.str, "Hello", 5) == 0);
|
||||
EXPECT_TRUE(rstr.commit.len == 0);
|
||||
EXPECT_TRUE(rstr.commit.str == NULL);
|
||||
|
||||
http_decoder_rstring_read(&rstr, &ptr, &len);
|
||||
EXPECT_TRUE(NULL == ptr && len == 0);
|
||||
|
||||
http_decoder_safe_free(hello_str);
|
||||
|
||||
// refer
|
||||
http_decoder_rstring_refer(&rstr, world_str, 5);
|
||||
http_decoder_rstring_dump(&rstr, "After refer");
|
||||
|
||||
EXPECT_TRUE(http_decoder_rstring_status(&rstr) == RSTRING_STATUS_REFER);
|
||||
EXPECT_TRUE(rstr.refer.len == 5);
|
||||
EXPECT_TRUE(strncmp(rstr.refer.str, "World", 5) == 0);
|
||||
EXPECT_TRUE(rstr.cache.len == 5);
|
||||
EXPECT_TRUE(strncmp(rstr.cache.str, "Hello", 5) == 0);
|
||||
EXPECT_TRUE(rstr.commit.len == 0);
|
||||
EXPECT_TRUE(rstr.commit.str == NULL);
|
||||
|
||||
http_decoder_rstring_read(&rstr, &ptr, &len);
|
||||
EXPECT_TRUE(NULL == ptr && len == 0);
|
||||
|
||||
// commit
|
||||
http_decoder_rstring_commit(&rstr);
|
||||
http_decoder_rstring_dump(&rstr, "After commit");
|
||||
|
||||
EXPECT_TRUE(http_decoder_rstring_status(&rstr) == RSTRING_STATUS_COMMIT);
|
||||
EXPECT_TRUE(rstr.refer.len == 0);
|
||||
EXPECT_TRUE(rstr.refer.str == NULL);
|
||||
EXPECT_TRUE(rstr.cache.len == 10);
|
||||
EXPECT_TRUE(strncmp(rstr.cache.str, "HelloWorld", 10) == 0);
|
||||
EXPECT_TRUE(rstr.commit.len == 10);
|
||||
EXPECT_TRUE(strncmp(rstr.commit.str, "HelloWorld", 10) == 0);
|
||||
|
||||
http_decoder_rstring_read(&rstr, &ptr, &len);
|
||||
EXPECT_TRUE(strncmp("HelloWorld", ptr, len) == 0);
|
||||
|
||||
http_decoder_safe_free(world_str);
|
||||
|
||||
// reset
|
||||
http_decoder_rstring_reset(&rstr);
|
||||
http_decoder_rstring_dump(&rstr, "After reset");
|
||||
|
||||
EXPECT_TRUE(http_decoder_rstring_status(&rstr) == RSTRING_STATUS_INIT);
|
||||
EXPECT_TRUE(rstr.refer.len == 0);
|
||||
EXPECT_TRUE(rstr.refer.str == NULL);
|
||||
EXPECT_TRUE(rstr.cache.len == 0);
|
||||
EXPECT_TRUE(rstr.cache.str == NULL);
|
||||
EXPECT_TRUE(rstr.commit.len == 0);
|
||||
EXPECT_TRUE(rstr.commit.str == NULL);
|
||||
|
||||
http_decoder_rstring_read(&rstr, &ptr, &len);
|
||||
EXPECT_TRUE(NULL == ptr && len == 0);
|
||||
}
|
||||
|
||||
TEST(HTTP_DECODER_RSTRING_TEST, refer_cache_refer_cache_commit_reset)
|
||||
{
|
||||
char *ptr = NULL;
|
||||
size_t len = 0;
|
||||
struct http_decoder_rstring rstr = {0};
|
||||
char *hello_str = http_decoder_safe_dup("Hello111", 8);
|
||||
char *world_str = http_decoder_safe_dup("World222", 8);
|
||||
|
||||
// refer
|
||||
http_decoder_rstring_refer(&rstr, hello_str, 5);
|
||||
http_decoder_rstring_dump(&rstr, "After refer");
|
||||
|
||||
EXPECT_TRUE(http_decoder_rstring_status(&rstr) == RSTRING_STATUS_REFER);
|
||||
EXPECT_TRUE(rstr.refer.len == 5);
|
||||
EXPECT_TRUE(strncmp(rstr.refer.str, "Hello", 5) == 0);
|
||||
EXPECT_TRUE(rstr.cache.len == 0);
|
||||
EXPECT_TRUE(rstr.cache.str == NULL);
|
||||
EXPECT_TRUE(rstr.commit.len == 0);
|
||||
EXPECT_TRUE(rstr.commit.str == NULL);
|
||||
|
||||
http_decoder_rstring_read(&rstr, &ptr, &len);
|
||||
EXPECT_TRUE(NULL == ptr && len == 0);
|
||||
|
||||
// cache
|
||||
http_decoder_rstring_cache(&rstr);
|
||||
http_decoder_rstring_dump(&rstr, "After cache");
|
||||
|
||||
EXPECT_TRUE(http_decoder_rstring_status(&rstr) == RSTRING_STATUS_CACHE);
|
||||
EXPECT_TRUE(rstr.refer.len == 0);
|
||||
EXPECT_TRUE(rstr.refer.str == NULL);
|
||||
EXPECT_TRUE(rstr.cache.len == 5);
|
||||
EXPECT_TRUE(strncmp(rstr.cache.str, "Hello", 5) == 0);
|
||||
EXPECT_TRUE(rstr.commit.len == 0);
|
||||
EXPECT_TRUE(rstr.commit.str == NULL);
|
||||
|
||||
http_decoder_rstring_read(&rstr, &ptr, &len);
|
||||
EXPECT_TRUE(NULL == ptr && len == 0);
|
||||
|
||||
http_decoder_safe_free(hello_str);
|
||||
|
||||
// refer
|
||||
http_decoder_rstring_refer(&rstr, world_str, 5);
|
||||
http_decoder_rstring_dump(&rstr, "After refer");
|
||||
|
||||
EXPECT_TRUE(http_decoder_rstring_status(&rstr) == RSTRING_STATUS_REFER);
|
||||
EXPECT_TRUE(rstr.refer.len == 5);
|
||||
EXPECT_TRUE(strncmp(rstr.refer.str, "World", 5) == 0);
|
||||
EXPECT_TRUE(rstr.cache.len == 5);
|
||||
EXPECT_TRUE(strncmp(rstr.cache.str, "Hello", 5) == 0);
|
||||
EXPECT_TRUE(rstr.commit.len == 0);
|
||||
EXPECT_TRUE(rstr.commit.str == NULL);
|
||||
|
||||
http_decoder_rstring_read(&rstr, &ptr, &len);
|
||||
EXPECT_TRUE(NULL == ptr && len == 0);
|
||||
|
||||
// cache
|
||||
http_decoder_rstring_cache(&rstr);
|
||||
http_decoder_rstring_dump(&rstr, "After cache");
|
||||
|
||||
EXPECT_TRUE(http_decoder_rstring_status(&rstr) == RSTRING_STATUS_CACHE);
|
||||
EXPECT_TRUE(rstr.refer.len == 0);
|
||||
EXPECT_TRUE(rstr.refer.str == NULL);
|
||||
EXPECT_TRUE(rstr.cache.len == 10);
|
||||
EXPECT_TRUE(strncmp(rstr.cache.str, "HelloWorld", 10) == 0);
|
||||
EXPECT_TRUE(rstr.commit.len == 0);
|
||||
EXPECT_TRUE(rstr.commit.str == NULL);
|
||||
|
||||
http_decoder_rstring_read(&rstr, &ptr, &len);
|
||||
EXPECT_TRUE(NULL == ptr && len == 0);
|
||||
|
||||
http_decoder_safe_free(world_str);
|
||||
|
||||
// commit
|
||||
http_decoder_rstring_commit(&rstr);
|
||||
http_decoder_rstring_dump(&rstr, "After commit");
|
||||
|
||||
EXPECT_TRUE(http_decoder_rstring_status(&rstr) == RSTRING_STATUS_COMMIT);
|
||||
EXPECT_TRUE(rstr.refer.len == 0);
|
||||
EXPECT_TRUE(rstr.refer.str == NULL);
|
||||
EXPECT_TRUE(rstr.cache.len == 10);
|
||||
EXPECT_TRUE(strncmp(rstr.cache.str, "HelloWorld", 10) == 0);
|
||||
EXPECT_TRUE(rstr.commit.len == 10);
|
||||
EXPECT_TRUE(strncmp(rstr.commit.str, "HelloWorld", 10) == 0);
|
||||
|
||||
http_decoder_rstring_read(&rstr, &ptr, &len);
|
||||
EXPECT_TRUE(strncmp("HelloWorld", ptr, len) == 0);
|
||||
|
||||
// reset
|
||||
http_decoder_rstring_reset(&rstr);
|
||||
http_decoder_rstring_dump(&rstr, "After reset");
|
||||
|
||||
EXPECT_TRUE(http_decoder_rstring_status(&rstr) == RSTRING_STATUS_INIT);
|
||||
EXPECT_TRUE(rstr.refer.len == 0);
|
||||
EXPECT_TRUE(rstr.refer.str == NULL);
|
||||
EXPECT_TRUE(rstr.cache.len == 0);
|
||||
EXPECT_TRUE(rstr.cache.str == NULL);
|
||||
EXPECT_TRUE(rstr.commit.len == 0);
|
||||
EXPECT_TRUE(rstr.commit.str == NULL);
|
||||
|
||||
http_decoder_rstring_read(&rstr, &ptr, &len);
|
||||
EXPECT_TRUE(NULL == ptr && len == 0);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int ret = 0;
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
ret = RUN_ALL_TESTS();
|
||||
return ret;
|
||||
}
|
||||
431
src/protocol_decoder/http/test/http_decoder_table_test.cpp
Normal file
431
src/protocol_decoder/http/test/http_decoder_table_test.cpp
Normal file
@@ -0,0 +1,431 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "../http_decoder_table.h"
|
||||
|
||||
struct key_val
|
||||
{
|
||||
const char *key;
|
||||
const char *val;
|
||||
};
|
||||
|
||||
struct key_val simple_headers[] = {
|
||||
{"Host", "www.baidu.com"},
|
||||
{"User-Agent", "curl/7.64.1"},
|
||||
{"connection", "close"},
|
||||
{"Accept", "*/*"},
|
||||
};
|
||||
|
||||
// At least 17 headers to trigger realloc
|
||||
struct key_val mutil_headers[] = {
|
||||
{"Server", "nginx"},
|
||||
{"content-length", "11"},
|
||||
{"Date", "Mon, 15 Aug 2022 07:40:35 GMT"},
|
||||
{"Content-Type", "text/html;charset=utf-8"},
|
||||
{"Expires", "Mon, 15 Aug 2022 07:50:34 GMT"},
|
||||
{"X-Cache-Lookup", "Hit From Disktank3"},
|
||||
{"ETag", "346f24f3000e27ce6f3d3b61f2c6a83b"},
|
||||
{"X-XSS-Protection", "0"},
|
||||
{"X-Daa-Tunnel", "hop_count=1"},
|
||||
{"X-Cache-Lookup", "Hit From Inner Cluster"},
|
||||
{"X-Cache-Lookup", "Cache Miss"},
|
||||
{"Last-Modified", "Mon, 15 Aug 2022 07:30:00 GMT"},
|
||||
{"Cache-Control", "private, max-age=600"},
|
||||
{"Content-Length", "51792"},
|
||||
{"X-NWS-LOG-UUID", "13366651529734458115"},
|
||||
{"Connection", "keep-alive"},
|
||||
{"X-Cache-Lookup", "Cache Miss"},
|
||||
{"Set-cookie", "aaa"},
|
||||
{"Set-cookie", "bbb"},
|
||||
};
|
||||
|
||||
const char *append = "000";
|
||||
const char *status = "OK";
|
||||
const char *uri = "index.html";
|
||||
const char *body = "hello world";
|
||||
|
||||
TEST(HTTP_DECODER_TABLE_TEST, add_commit)
|
||||
{
|
||||
char *key_str = NULL;
|
||||
char *val_str = NULL;
|
||||
size_t key_len = 0;
|
||||
size_t val_len = 0;
|
||||
int iter_index = 0;
|
||||
|
||||
// create
|
||||
struct http_decoder_table *data = http_decoder_table_create();
|
||||
EXPECT_TRUE(data != NULL);
|
||||
|
||||
// add/get uri
|
||||
http_decoder_table_add(data, HTTP_ITERM_URI, uri, strlen(uri));
|
||||
http_decoder_table_commit(data, HTTP_ITERM_URI);
|
||||
|
||||
http_decoder_table_get_uri(data, &key_str, &key_len);
|
||||
EXPECT_TRUE(strncmp(uri, key_str, key_len) == 0);
|
||||
|
||||
// add/get status
|
||||
http_decoder_table_add(data, HTTP_ITERM_STATUS, status, strlen(status));
|
||||
http_decoder_table_commit(data, HTTP_ITERM_STATUS);
|
||||
|
||||
http_decoder_table_get_status(data, &key_str, &key_len);
|
||||
EXPECT_TRUE(strncmp(status, key_str, key_len) == 0);
|
||||
|
||||
// add/get body
|
||||
http_decoder_table_add(data, HTTP_ITERM_BODY, body, strlen(body));
|
||||
http_decoder_table_commit(data, HTTP_ITERM_BODY);
|
||||
|
||||
http_decoder_table_get_body(data, &key_str, &key_len);
|
||||
EXPECT_TRUE(strncmp(body, key_str, key_len) == 0);
|
||||
|
||||
// add/get header
|
||||
for (size_t i = 0; i < sizeof(simple_headers) / sizeof(simple_headers[0]); i++)
|
||||
{
|
||||
http_decoder_table_add(data, HTTP_ITERM_HEADER_FILED, simple_headers[i].key, strlen(simple_headers[i].key));
|
||||
http_decoder_table_commit(data, HTTP_ITERM_HEADER_FILED);
|
||||
|
||||
http_decoder_table_add(data, HTTP_ITERM_HEADER_VALUE, simple_headers[i].val, strlen(simple_headers[i].val));
|
||||
http_decoder_table_commit(data, HTTP_ITERM_HEADER_VALUE);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < sizeof(simple_headers) / sizeof(simple_headers[0]); i++)
|
||||
{
|
||||
http_decoder_table_next_header(data, &iter_index, &key_str, &key_len, &val_str, &val_len);
|
||||
EXPECT_TRUE(strncmp(simple_headers[i].key, key_str, key_len) == 0);
|
||||
EXPECT_TRUE(strncmp(simple_headers[i].val, val_str, val_len) == 0);
|
||||
}
|
||||
|
||||
// dump
|
||||
printf("After commit:\n");
|
||||
http_decoder_table_dump(data);
|
||||
|
||||
// destory
|
||||
http_decoder_table_destory(data);
|
||||
}
|
||||
|
||||
TEST(HTTP_DECODER_TABLE_TEST, add_cache_commit)
|
||||
{
|
||||
char *key_str = NULL;
|
||||
char *val_str = NULL;
|
||||
size_t key_len = 0;
|
||||
size_t val_len = 0;
|
||||
int iter_index = 0;
|
||||
|
||||
// create
|
||||
struct http_decoder_table *data = http_decoder_table_create();
|
||||
EXPECT_TRUE(data != NULL);
|
||||
|
||||
// add/get uri
|
||||
http_decoder_table_add(data, HTTP_ITERM_URI, uri, strlen(uri));
|
||||
http_decoder_table_cache(data, HTTP_ITERM_URI);
|
||||
http_decoder_table_commit(data, HTTP_ITERM_URI);
|
||||
|
||||
http_decoder_table_get_uri(data, &key_str, &key_len);
|
||||
EXPECT_TRUE(strncmp(uri, key_str, key_len) == 0);
|
||||
|
||||
// add/get status
|
||||
http_decoder_table_add(data, HTTP_ITERM_STATUS, status, strlen(status));
|
||||
http_decoder_table_cache(data, HTTP_ITERM_STATUS);
|
||||
http_decoder_table_commit(data, HTTP_ITERM_STATUS);
|
||||
|
||||
http_decoder_table_get_status(data, &key_str, &key_len);
|
||||
EXPECT_TRUE(strncmp(status, key_str, key_len) == 0);
|
||||
|
||||
// add/get body
|
||||
http_decoder_table_add(data, HTTP_ITERM_BODY, body, strlen(body));
|
||||
http_decoder_table_cache(data, HTTP_ITERM_BODY);
|
||||
http_decoder_table_commit(data, HTTP_ITERM_BODY);
|
||||
|
||||
http_decoder_table_get_body(data, &key_str, &key_len);
|
||||
EXPECT_TRUE(strncmp(body, key_str, key_len) == 0);
|
||||
|
||||
// add/get header
|
||||
for (size_t i = 0; i < sizeof(simple_headers) / sizeof(simple_headers[0]); i++)
|
||||
{
|
||||
http_decoder_table_add(data, HTTP_ITERM_HEADER_FILED, simple_headers[i].key, strlen(simple_headers[i].key));
|
||||
http_decoder_table_cache(data, HTTP_ITERM_HEADER_FILED);
|
||||
http_decoder_table_commit(data, HTTP_ITERM_HEADER_FILED);
|
||||
|
||||
http_decoder_table_add(data, HTTP_ITERM_HEADER_VALUE, simple_headers[i].val, strlen(simple_headers[i].val));
|
||||
http_decoder_table_cache(data, HTTP_ITERM_HEADER_VALUE);
|
||||
http_decoder_table_commit(data, HTTP_ITERM_HEADER_VALUE);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < sizeof(simple_headers) / sizeof(simple_headers[0]); i++)
|
||||
{
|
||||
http_decoder_table_next_header(data, &iter_index, &key_str, &key_len, &val_str, &val_len);
|
||||
EXPECT_TRUE(strncmp(simple_headers[i].key, key_str, key_len) == 0);
|
||||
EXPECT_TRUE(strncmp(simple_headers[i].val, val_str, val_len) == 0);
|
||||
}
|
||||
|
||||
// dump
|
||||
printf("After commit:\n");
|
||||
http_decoder_table_dump(data);
|
||||
|
||||
// destory
|
||||
http_decoder_table_destory(data);
|
||||
}
|
||||
|
||||
TEST(HTTP_DECODER_TABLE_TEST, add_cache_add_commit)
|
||||
{
|
||||
char *key_str = NULL;
|
||||
char *val_str = NULL;
|
||||
size_t key_len = 0;
|
||||
size_t val_len = 0;
|
||||
int iter_index = 0;
|
||||
|
||||
// create
|
||||
struct http_decoder_table *data = http_decoder_table_create();
|
||||
EXPECT_TRUE(data != NULL);
|
||||
|
||||
// add/get uri
|
||||
http_decoder_table_add(data, HTTP_ITERM_URI, uri, strlen(uri));
|
||||
http_decoder_table_cache(data, HTTP_ITERM_URI);
|
||||
http_decoder_table_add(data, HTTP_ITERM_URI, append, strlen(append));
|
||||
http_decoder_table_commit(data, HTTP_ITERM_URI);
|
||||
|
||||
http_decoder_table_get_uri(data, &key_str, &key_len);
|
||||
EXPECT_TRUE(strncmp(key_str, uri, strlen(uri)) == 0);
|
||||
EXPECT_TRUE(strncmp(key_str + strlen(uri), append, strlen(append)) == 0);
|
||||
|
||||
// add/get status
|
||||
http_decoder_table_add(data, HTTP_ITERM_STATUS, status, strlen(status));
|
||||
http_decoder_table_cache(data, HTTP_ITERM_STATUS);
|
||||
http_decoder_table_add(data, HTTP_ITERM_STATUS, append, strlen(append));
|
||||
http_decoder_table_commit(data, HTTP_ITERM_STATUS);
|
||||
|
||||
http_decoder_table_get_status(data, &key_str, &key_len);
|
||||
EXPECT_TRUE(strncmp(key_str, status, strlen(status)) == 0);
|
||||
EXPECT_TRUE(strncmp(key_str + strlen(status), append, strlen(append)) == 0);
|
||||
|
||||
// add/get body
|
||||
http_decoder_table_add(data, HTTP_ITERM_BODY, body, strlen(body));
|
||||
http_decoder_table_cache(data, HTTP_ITERM_BODY);
|
||||
http_decoder_table_add(data, HTTP_ITERM_BODY, append, strlen(append));
|
||||
http_decoder_table_commit(data, HTTP_ITERM_BODY);
|
||||
|
||||
http_decoder_table_get_body(data, &key_str, &key_len);
|
||||
EXPECT_TRUE(strncmp(key_str, body, strlen(body)) == 0);
|
||||
EXPECT_TRUE(strncmp(key_str + strlen(body), append, strlen(append)) == 0);
|
||||
|
||||
// add/get header
|
||||
for (size_t i = 0; i < sizeof(simple_headers) / sizeof(simple_headers[0]); i++)
|
||||
{
|
||||
http_decoder_table_add(data, HTTP_ITERM_HEADER_FILED, simple_headers[i].key, strlen(simple_headers[i].key));
|
||||
http_decoder_table_cache(data, HTTP_ITERM_HEADER_FILED);
|
||||
http_decoder_table_add(data, HTTP_ITERM_HEADER_FILED, append, strlen(append));
|
||||
http_decoder_table_commit(data, HTTP_ITERM_HEADER_FILED);
|
||||
|
||||
http_decoder_table_add(data, HTTP_ITERM_HEADER_VALUE, simple_headers[i].val, strlen(simple_headers[i].val));
|
||||
http_decoder_table_cache(data, HTTP_ITERM_HEADER_VALUE);
|
||||
http_decoder_table_add(data, HTTP_ITERM_HEADER_VALUE, append, strlen(append));
|
||||
http_decoder_table_commit(data, HTTP_ITERM_HEADER_VALUE);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < sizeof(simple_headers) / sizeof(simple_headers[0]); i++)
|
||||
{
|
||||
http_decoder_table_next_header(data, &iter_index, &key_str, &key_len, &val_str, &val_len);
|
||||
|
||||
EXPECT_TRUE(strncmp(key_str, simple_headers[i].key, strlen(simple_headers[i].key)) == 0);
|
||||
EXPECT_TRUE(strncmp(key_str + strlen(simple_headers[i].key), append, strlen(append)) == 0);
|
||||
|
||||
EXPECT_TRUE(strncmp(val_str, simple_headers[i].val, strlen(simple_headers[i].val)) == 0);
|
||||
EXPECT_TRUE(strncmp(val_str + strlen(simple_headers[i].val), append, strlen(append)) == 0);
|
||||
}
|
||||
|
||||
// dump
|
||||
printf("After commit:\n");
|
||||
http_decoder_table_dump(data);
|
||||
|
||||
// destory
|
||||
http_decoder_table_destory(data);
|
||||
}
|
||||
|
||||
TEST(HTTP_DECODER_TABLE_TEST, realloc_header)
|
||||
{
|
||||
char *key_str = NULL;
|
||||
char *val_str = NULL;
|
||||
size_t key_len = 0;
|
||||
size_t val_len = 0;
|
||||
int iter_index = 0;
|
||||
|
||||
// create
|
||||
struct http_decoder_table *data = http_decoder_table_create();
|
||||
EXPECT_TRUE(data != NULL);
|
||||
|
||||
// add/get header
|
||||
for (size_t i = 0; i < sizeof(mutil_headers) / sizeof(mutil_headers[0]); i++)
|
||||
{
|
||||
http_decoder_table_add(data, HTTP_ITERM_HEADER_FILED, mutil_headers[i].key, strlen(mutil_headers[i].key));
|
||||
http_decoder_table_cache(data, HTTP_ITERM_HEADER_FILED);
|
||||
http_decoder_table_add(data, HTTP_ITERM_HEADER_FILED, append, strlen(append));
|
||||
http_decoder_table_commit(data, HTTP_ITERM_HEADER_FILED);
|
||||
|
||||
http_decoder_table_add(data, HTTP_ITERM_HEADER_VALUE, mutil_headers[i].val, strlen(mutil_headers[i].val));
|
||||
http_decoder_table_cache(data, HTTP_ITERM_HEADER_VALUE);
|
||||
http_decoder_table_add(data, HTTP_ITERM_HEADER_VALUE, append, strlen(append));
|
||||
http_decoder_table_commit(data, HTTP_ITERM_HEADER_VALUE);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < sizeof(mutil_headers) / sizeof(mutil_headers[0]); i++)
|
||||
{
|
||||
http_decoder_table_next_header(data, &iter_index, &key_str, &key_len, &val_str, &val_len);
|
||||
|
||||
EXPECT_TRUE(strncmp(key_str, mutil_headers[i].key, strlen(mutil_headers[i].key)) == 0);
|
||||
EXPECT_TRUE(strncmp(key_str + strlen(mutil_headers[i].key), append, strlen(append)) == 0);
|
||||
|
||||
EXPECT_TRUE(strncmp(val_str, mutil_headers[i].val, strlen(mutil_headers[i].val)) == 0);
|
||||
EXPECT_TRUE(strncmp(val_str + strlen(mutil_headers[i].val), append, strlen(append)) == 0);
|
||||
}
|
||||
|
||||
// dump
|
||||
printf("After commit:\n");
|
||||
http_decoder_table_dump(data);
|
||||
|
||||
// destory
|
||||
http_decoder_table_destory(data);
|
||||
}
|
||||
|
||||
TEST(HTTP_DECODER_TABLE_TEST, remove)
|
||||
{
|
||||
char *key_str = NULL;
|
||||
char *val_str = NULL;
|
||||
size_t key_len = 0;
|
||||
size_t val_len = 0;
|
||||
int iter_index = 0;
|
||||
|
||||
// create
|
||||
struct http_decoder_table *data = http_decoder_table_create();
|
||||
EXPECT_TRUE(data != NULL);
|
||||
|
||||
// add/get uri
|
||||
http_decoder_table_add(data, HTTP_ITERM_URI, uri, strlen(uri));
|
||||
http_decoder_table_cache(data, HTTP_ITERM_URI);
|
||||
|
||||
http_decoder_table_get_uri(data, &key_str, &key_len);
|
||||
EXPECT_TRUE(key_str == NULL && key_len == 0);
|
||||
|
||||
// add/get status
|
||||
http_decoder_table_add(data, HTTP_ITERM_STATUS, status, strlen(status));
|
||||
http_decoder_table_cache(data, HTTP_ITERM_STATUS);
|
||||
|
||||
http_decoder_table_get_status(data, &key_str, &key_len);
|
||||
EXPECT_TRUE(key_str == NULL && key_len == 0);
|
||||
|
||||
// add/get body
|
||||
http_decoder_table_add(data, HTTP_ITERM_BODY, body, strlen(body));
|
||||
http_decoder_table_cache(data, HTTP_ITERM_BODY);
|
||||
|
||||
http_decoder_table_get_body(data, &key_str, &key_len);
|
||||
EXPECT_TRUE(key_str == NULL && key_len == 0);
|
||||
|
||||
// add/get header
|
||||
http_decoder_table_add(data, HTTP_ITERM_HEADER_FILED, simple_headers[0].key, strlen(simple_headers[0].key));
|
||||
http_decoder_table_cache(data, HTTP_ITERM_HEADER_FILED);
|
||||
|
||||
http_decoder_table_add(data, HTTP_ITERM_HEADER_VALUE, simple_headers[0].val, strlen(simple_headers[0].val));
|
||||
http_decoder_table_cache(data, HTTP_ITERM_HEADER_VALUE);
|
||||
|
||||
http_decoder_table_next_header(data, &iter_index, &key_str, &key_len, &val_str, &val_len);
|
||||
EXPECT_TRUE(key_str == NULL && key_len == 0);
|
||||
EXPECT_TRUE(val_str == NULL && val_len == 0);
|
||||
|
||||
// dump
|
||||
printf("After cache:\n");
|
||||
http_decoder_table_dump(data);
|
||||
|
||||
http_decoder_table_remove(data);
|
||||
|
||||
printf("After remove:\n");
|
||||
http_decoder_table_dump(data);
|
||||
|
||||
http_decoder_table_commit(data, HTTP_ITERM_URI);
|
||||
http_decoder_table_commit(data, HTTP_ITERM_STATUS);
|
||||
http_decoder_table_commit(data, HTTP_ITERM_BODY);
|
||||
http_decoder_table_commit(data, HTTP_ITERM_HEADER_FILED);
|
||||
http_decoder_table_commit(data, HTTP_ITERM_HEADER_VALUE);
|
||||
|
||||
printf("After commit:\n");
|
||||
http_decoder_table_dump(data);
|
||||
|
||||
http_decoder_table_get_uri(data, &key_str, &key_len);
|
||||
EXPECT_TRUE(strncmp(uri, key_str, key_len) == 0);
|
||||
|
||||
http_decoder_table_get_status(data, &key_str, &key_len);
|
||||
EXPECT_TRUE(strncmp(status, key_str, key_len) == 0);
|
||||
|
||||
http_decoder_table_get_body(data, &key_str, &key_len);
|
||||
EXPECT_TRUE(strncmp(body, key_str, key_len) == 0);
|
||||
|
||||
iter_index = 0;
|
||||
http_decoder_table_next_header(data, &iter_index, &key_str, &key_len, &val_str, &val_len);
|
||||
|
||||
EXPECT_TRUE(strncmp(simple_headers[0].key, key_str, key_len) == 0);
|
||||
EXPECT_TRUE(strncmp(simple_headers[0].val, val_str, val_len) == 0);
|
||||
|
||||
// destory
|
||||
http_decoder_table_destory(data);
|
||||
}
|
||||
|
||||
TEST(HTTP_DECODER_TABLE_TEST, reset)
|
||||
{
|
||||
char *key_str = NULL;
|
||||
char *val_str = NULL;
|
||||
size_t key_len = 0;
|
||||
size_t val_len = 0;
|
||||
int iter_index = 0;
|
||||
|
||||
// create
|
||||
struct http_decoder_table *data = http_decoder_table_create();
|
||||
EXPECT_TRUE(data != NULL);
|
||||
|
||||
// add/get uri
|
||||
http_decoder_table_add(data, HTTP_ITERM_URI, uri, strlen(uri));
|
||||
http_decoder_table_cache(data, HTTP_ITERM_URI);
|
||||
|
||||
http_decoder_table_get_uri(data, &key_str, &key_len);
|
||||
EXPECT_TRUE(key_str == NULL && key_len == 0);
|
||||
|
||||
// add/get status
|
||||
http_decoder_table_add(data, HTTP_ITERM_STATUS, status, strlen(status));
|
||||
http_decoder_table_cache(data, HTTP_ITERM_STATUS);
|
||||
|
||||
http_decoder_table_get_status(data, &key_str, &key_len);
|
||||
EXPECT_TRUE(key_str == NULL && key_len == 0);
|
||||
|
||||
// add/get body
|
||||
http_decoder_table_add(data, HTTP_ITERM_BODY, body, strlen(body));
|
||||
http_decoder_table_cache(data, HTTP_ITERM_BODY);
|
||||
|
||||
http_decoder_table_get_body(data, &key_str, &key_len);
|
||||
EXPECT_TRUE(key_str == NULL && key_len == 0);
|
||||
|
||||
// add/get header
|
||||
http_decoder_table_add(data, HTTP_ITERM_HEADER_FILED, simple_headers[0].key, strlen(simple_headers[0].key));
|
||||
http_decoder_table_cache(data, HTTP_ITERM_HEADER_FILED);
|
||||
|
||||
http_decoder_table_add(data, HTTP_ITERM_HEADER_VALUE, simple_headers[0].val, strlen(simple_headers[0].val));
|
||||
http_decoder_table_cache(data, HTTP_ITERM_HEADER_VALUE);
|
||||
|
||||
http_decoder_table_next_header(data, &iter_index, &key_str, &key_len, &val_str, &val_len);
|
||||
EXPECT_TRUE(key_str == NULL && key_len == 0);
|
||||
EXPECT_TRUE(val_str == NULL && val_len == 0);
|
||||
|
||||
// dump
|
||||
printf("After cache:\n");
|
||||
http_decoder_table_dump(data);
|
||||
|
||||
http_decoder_table_reset(data);
|
||||
|
||||
printf("After reset:\n");
|
||||
http_decoder_table_dump(data);
|
||||
|
||||
// destory
|
||||
http_decoder_table_destory(data);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int ret = 0;
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
ret = RUN_ALL_TESTS();
|
||||
return ret;
|
||||
}
|
||||
614
src/protocol_decoder/http/test/http_decoder_test.cpp
Normal file
614
src/protocol_decoder/http/test/http_decoder_test.cpp
Normal file
@@ -0,0 +1,614 @@
|
||||
#include "../http_decoder.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
const char *request_post = "POST /index.html HTTP/1.1\r\nconnection:close\r\ncontent-length: 1\r\n\r\n1\r\n\r\n";
|
||||
const char *request_get = "GET /index.html HTTP/1.1\r\nHost: www.baidu.com\r\nUser-Agent: curl/7.64.1\r\nAccept: */*\r\n\r\n";
|
||||
const char *response_200 = "HTTP/1.1 200 OK\r\nServer: nginx\r\ncontent-length: 11\r\n\r\nhello:world\r\n\r\n";
|
||||
|
||||
/******************************************************************************
|
||||
* complete http request/response
|
||||
******************************************************************************/
|
||||
|
||||
#if 1
|
||||
TEST(HTTP_DECODER_TEST, complete_post_request)
|
||||
{
|
||||
char *key_str = NULL;
|
||||
char *val_str = NULL;
|
||||
size_t key_len = 0;
|
||||
size_t val_len = 0;
|
||||
int iter_index = 0;
|
||||
|
||||
struct http_decoder *decoder = http_decoder_create();
|
||||
http_decoder_init(decoder);
|
||||
EXPECT_TRUE(http_decoder_dispatch(decoder, request_post, strlen(request_post)) == 0);
|
||||
http_decoder_dump(decoder);
|
||||
|
||||
// check data
|
||||
EXPECT_TRUE(http_decoder_fetch_dir(decoder) == HTTP_DIR_REQUEST);
|
||||
EXPECT_TRUE(http_decoder_fetch_status_code(decoder) == -1); // unused
|
||||
EXPECT_TRUE(http_decoder_fetch_major_version(decoder) == 1);
|
||||
EXPECT_TRUE(http_decoder_fetch_minor_version(decoder) == 1);
|
||||
|
||||
http_decoder_fetch_method(decoder, &key_str, &key_len);
|
||||
EXPECT_TRUE(strncmp("POST", key_str, key_len) == 0);
|
||||
|
||||
http_decoder_fetch_uri(decoder, &key_str, &key_len);
|
||||
EXPECT_TRUE(strncmp("/index.html", key_str, key_len) == 0);
|
||||
|
||||
http_decoder_fetch_status(decoder, &key_str, &key_len);
|
||||
EXPECT_TRUE(NULL == key_str && key_len == 0);
|
||||
|
||||
http_decoder_fetch_body(decoder, &key_str, &key_len);
|
||||
EXPECT_TRUE(strncmp("1", key_str, key_len) == 0);
|
||||
|
||||
http_decoder_fetch_next_header(decoder, &iter_index, &key_str, &key_len, &val_str, &val_len);
|
||||
EXPECT_TRUE(strncmp("connection", key_str, key_len) == 0);
|
||||
EXPECT_TRUE(strncmp("close", val_str, val_len) == 0);
|
||||
|
||||
http_decoder_fetch_next_header(decoder, &iter_index, &key_str, &key_len, &val_str, &val_len);
|
||||
EXPECT_TRUE(strncmp("content-length", key_str, key_len) == 0);
|
||||
EXPECT_TRUE(strncmp("1", val_str, val_len) == 0);
|
||||
|
||||
http_decoder_destory(decoder);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
TEST(HTTP_DECODER_TEST, complete_get_request)
|
||||
{
|
||||
char *key_str = NULL;
|
||||
char *val_str = NULL;
|
||||
size_t key_len = 0;
|
||||
size_t val_len = 0;
|
||||
int iter_index = 0;
|
||||
|
||||
struct http_decoder *decoder = http_decoder_create();
|
||||
http_decoder_init(decoder);
|
||||
EXPECT_TRUE(http_decoder_dispatch(decoder, request_get, strlen(request_get)) == 0);
|
||||
http_decoder_dump(decoder);
|
||||
|
||||
// check data
|
||||
EXPECT_TRUE(http_decoder_fetch_dir(decoder) == HTTP_DIR_REQUEST);
|
||||
EXPECT_TRUE(http_decoder_fetch_status_code(decoder) == -1); // unused
|
||||
EXPECT_TRUE(http_decoder_fetch_major_version(decoder) == 1);
|
||||
EXPECT_TRUE(http_decoder_fetch_minor_version(decoder) == 1);
|
||||
|
||||
http_decoder_fetch_method(decoder, &key_str, &key_len);
|
||||
EXPECT_TRUE(strncmp("GET", key_str, key_len) == 0);
|
||||
|
||||
http_decoder_fetch_uri(decoder, &key_str, &key_len);
|
||||
EXPECT_TRUE(strncmp("/index.html", key_str, key_len) == 0);
|
||||
|
||||
http_decoder_fetch_status(decoder, &key_str, &key_len);
|
||||
EXPECT_TRUE(NULL == key_str && key_len == 0);
|
||||
|
||||
http_decoder_fetch_body(decoder, &key_str, &key_len);
|
||||
EXPECT_TRUE(key_str == NULL && key_len == 0);
|
||||
|
||||
http_decoder_fetch_next_header(decoder, &iter_index, &key_str, &key_len, &val_str, &val_len);
|
||||
EXPECT_TRUE(strncmp("Host", key_str, key_len) == 0);
|
||||
EXPECT_TRUE(strncmp("www.baidu.com", val_str, val_len) == 0);
|
||||
|
||||
http_decoder_fetch_next_header(decoder, &iter_index, &key_str, &key_len, &val_str, &val_len);
|
||||
EXPECT_TRUE(strncmp("User-Agent", key_str, key_len) == 0);
|
||||
EXPECT_TRUE(strncmp("curl/7.64.1", val_str, val_len) == 0);
|
||||
|
||||
http_decoder_fetch_next_header(decoder, &iter_index, &key_str, &key_len, &val_str, &val_len);
|
||||
EXPECT_TRUE(strncmp("Accept", key_str, key_len) == 0);
|
||||
EXPECT_TRUE(strncmp("*/*", val_str, val_len) == 0);
|
||||
|
||||
http_decoder_destory(decoder);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
TEST(HTTP_DECODER_TEST, complete_response)
|
||||
{
|
||||
char *key_str = NULL;
|
||||
char *val_str = NULL;
|
||||
size_t key_len = 0;
|
||||
size_t val_len = 0;
|
||||
int iter_index = 0;
|
||||
|
||||
struct http_decoder *decoder = http_decoder_create();
|
||||
http_decoder_init(decoder);
|
||||
EXPECT_TRUE(http_decoder_dispatch(decoder, response_200, strlen(response_200)) == 0);
|
||||
http_decoder_dump(decoder);
|
||||
|
||||
// check data
|
||||
EXPECT_TRUE(http_decoder_fetch_dir(decoder) == HTTP_DIR_RESPONSE);
|
||||
EXPECT_TRUE(http_decoder_fetch_status_code(decoder) == 200);
|
||||
EXPECT_TRUE(http_decoder_fetch_major_version(decoder) == 1);
|
||||
EXPECT_TRUE(http_decoder_fetch_minor_version(decoder) == 1);
|
||||
|
||||
http_decoder_fetch_method(decoder, &key_str, &key_len);
|
||||
EXPECT_TRUE(NULL == key_str && key_len == 0);
|
||||
|
||||
http_decoder_fetch_uri(decoder, &key_str, &key_len);
|
||||
EXPECT_TRUE(NULL == key_str && key_len == 0);
|
||||
|
||||
http_decoder_fetch_status(decoder, &key_str, &key_len);
|
||||
EXPECT_TRUE(strncmp("OK", key_str, key_len) == 0);
|
||||
|
||||
http_decoder_fetch_body(decoder, &key_str, &key_len);
|
||||
EXPECT_TRUE(strncmp("hello:world", key_str, key_len) == 0);
|
||||
|
||||
http_decoder_fetch_next_header(decoder, &iter_index, &key_str, &key_len, &val_str, &val_len);
|
||||
EXPECT_TRUE(strncmp("Server", key_str, key_len) == 0);
|
||||
EXPECT_TRUE(strncmp("nginx", val_str, val_len) == 0);
|
||||
|
||||
http_decoder_fetch_next_header(decoder, &iter_index, &key_str, &key_len, &val_str, &val_len);
|
||||
EXPECT_TRUE(strncmp("content-length", key_str, key_len) == 0);
|
||||
EXPECT_TRUE(strncmp("11", val_str, val_len) == 0);
|
||||
|
||||
http_decoder_destory(decoder);
|
||||
}
|
||||
#endif
|
||||
|
||||
/******************************************************************************
|
||||
* uncomplete http request
|
||||
******************************************************************************/
|
||||
|
||||
#if 1
|
||||
TEST(HTTP_DECODER_TEST, uncomplete_post_request)
|
||||
{
|
||||
char *key_str = NULL;
|
||||
char *val_str = NULL;
|
||||
size_t key_len = 0;
|
||||
size_t val_len = 0;
|
||||
int iter_index = 0;
|
||||
|
||||
struct http_decoder *decoder = http_decoder_create();
|
||||
http_decoder_init(decoder);
|
||||
|
||||
for (size_t i = 0; i < strlen(request_post); i++)
|
||||
{
|
||||
EXPECT_TRUE(http_decoder_dispatch(decoder, request_post + i, 1) != -2);
|
||||
}
|
||||
http_decoder_dump(decoder);
|
||||
|
||||
// check data
|
||||
EXPECT_TRUE(http_decoder_fetch_dir(decoder) == HTTP_DIR_REQUEST);
|
||||
EXPECT_TRUE(http_decoder_fetch_status_code(decoder) == -1); // unused
|
||||
EXPECT_TRUE(http_decoder_fetch_major_version(decoder) == 1);
|
||||
EXPECT_TRUE(http_decoder_fetch_minor_version(decoder) == 1);
|
||||
|
||||
http_decoder_fetch_method(decoder, &key_str, &key_len);
|
||||
EXPECT_TRUE(strncmp("POST", key_str, key_len) == 0);
|
||||
|
||||
http_decoder_fetch_uri(decoder, &key_str, &key_len);
|
||||
EXPECT_TRUE(strncmp("/index.html", key_str, key_len) == 0);
|
||||
|
||||
http_decoder_fetch_status(decoder, &key_str, &key_len);
|
||||
EXPECT_TRUE(NULL == key_str && key_len == 0);
|
||||
|
||||
http_decoder_fetch_body(decoder, &key_str, &key_len);
|
||||
EXPECT_TRUE(strncmp("1", key_str, key_len) == 0);
|
||||
|
||||
http_decoder_fetch_next_header(decoder, &iter_index, &key_str, &key_len, &val_str, &val_len);
|
||||
EXPECT_TRUE(strncmp("connection", key_str, key_len) == 0);
|
||||
EXPECT_TRUE(strncmp("close", val_str, val_len) == 0);
|
||||
|
||||
http_decoder_fetch_next_header(decoder, &iter_index, &key_str, &key_len, &val_str, &val_len);
|
||||
EXPECT_TRUE(strncmp("content-length", key_str, key_len) == 0);
|
||||
EXPECT_TRUE(strncmp("1", val_str, val_len) == 0);
|
||||
|
||||
http_decoder_destory(decoder);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
TEST(HTTP_DECODER_TEST, uncomplete_get_request)
|
||||
{
|
||||
char *key_str = NULL;
|
||||
char *val_str = NULL;
|
||||
size_t key_len = 0;
|
||||
size_t val_len = 0;
|
||||
int iter_index = 0;
|
||||
|
||||
struct http_decoder *decoder = http_decoder_create();
|
||||
http_decoder_init(decoder);
|
||||
|
||||
for (size_t i = 0; i < strlen(request_get); i++)
|
||||
{
|
||||
EXPECT_TRUE(http_decoder_dispatch(decoder, request_get + i, 1) != -2);
|
||||
}
|
||||
http_decoder_dump(decoder);
|
||||
|
||||
// check data
|
||||
EXPECT_TRUE(http_decoder_fetch_dir(decoder) == HTTP_DIR_REQUEST);
|
||||
EXPECT_TRUE(http_decoder_fetch_status_code(decoder) == -1); // unused
|
||||
EXPECT_TRUE(http_decoder_fetch_major_version(decoder) == 1);
|
||||
EXPECT_TRUE(http_decoder_fetch_minor_version(decoder) == 1);
|
||||
|
||||
http_decoder_fetch_method(decoder, &key_str, &key_len);
|
||||
EXPECT_TRUE(strncmp("GET", key_str, key_len) == 0);
|
||||
|
||||
http_decoder_fetch_uri(decoder, &key_str, &key_len);
|
||||
EXPECT_TRUE(strncmp("/index.html", key_str, key_len) == 0);
|
||||
|
||||
http_decoder_fetch_status(decoder, &key_str, &key_len);
|
||||
EXPECT_TRUE(NULL == key_str && key_len == 0);
|
||||
|
||||
http_decoder_fetch_body(decoder, &key_str, &key_len);
|
||||
EXPECT_TRUE(key_str == NULL && key_len == 0);
|
||||
|
||||
http_decoder_fetch_next_header(decoder, &iter_index, &key_str, &key_len, &val_str, &val_len);
|
||||
EXPECT_TRUE(strncmp("Host", key_str, key_len) == 0);
|
||||
EXPECT_TRUE(strncmp("www.baidu.com", val_str, val_len) == 0);
|
||||
|
||||
http_decoder_fetch_next_header(decoder, &iter_index, &key_str, &key_len, &val_str, &val_len);
|
||||
EXPECT_TRUE(strncmp("User-Agent", key_str, key_len) == 0);
|
||||
EXPECT_TRUE(strncmp("curl/7.64.1", val_str, val_len) == 0);
|
||||
|
||||
http_decoder_fetch_next_header(decoder, &iter_index, &key_str, &key_len, &val_str, &val_len);
|
||||
EXPECT_TRUE(strncmp("Accept", key_str, key_len) == 0);
|
||||
EXPECT_TRUE(strncmp("*/*", val_str, val_len) == 0);
|
||||
|
||||
http_decoder_destory(decoder);
|
||||
}
|
||||
#endif
|
||||
|
||||
/******************************************************************************
|
||||
* uncomplete http request/response and consume meta
|
||||
******************************************************************************/
|
||||
|
||||
#if 1
|
||||
TEST(HTTP_DECODER_TEST, uncomplete_post_request_and_consume_meta)
|
||||
{
|
||||
char *key_str = NULL;
|
||||
char *val_str = NULL;
|
||||
size_t key_len = 0;
|
||||
size_t val_len = 0;
|
||||
int iter_index = 0;
|
||||
int next_header = 0;
|
||||
|
||||
struct http_decoder *decoder = http_decoder_create();
|
||||
http_decoder_init(decoder);
|
||||
|
||||
for (size_t i = 0; i < strlen(request_post); i++)
|
||||
{
|
||||
EXPECT_TRUE(http_decoder_dispatch(decoder, request_post + i, 1) != -2);
|
||||
|
||||
if (http_decoder_status(decoder) >= ON_URI)
|
||||
{
|
||||
EXPECT_TRUE(http_decoder_fetch_dir(decoder) == HTTP_DIR_REQUEST);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(http_decoder_fetch_status_code(decoder) == -1); // unused
|
||||
|
||||
if (http_decoder_status(decoder) >= ON_HEADER_FIELD)
|
||||
{
|
||||
EXPECT_TRUE(http_decoder_fetch_major_version(decoder) == 1);
|
||||
}
|
||||
|
||||
if (http_decoder_status(decoder) >= ON_HEADER_FIELD)
|
||||
{
|
||||
EXPECT_TRUE(http_decoder_fetch_minor_version(decoder) == 1);
|
||||
}
|
||||
|
||||
if (http_decoder_status(decoder) >= ON_URI)
|
||||
{
|
||||
http_decoder_fetch_method(decoder, &key_str, &key_len);
|
||||
EXPECT_TRUE(strncmp("POST", key_str, key_len) == 0);
|
||||
}
|
||||
|
||||
if (http_decoder_status(decoder) >= ON_URI_COMPLETE)
|
||||
{
|
||||
http_decoder_fetch_uri(decoder, &key_str, &key_len);
|
||||
EXPECT_TRUE(strncmp("/index.html", key_str, key_len) == 0);
|
||||
}
|
||||
|
||||
http_decoder_fetch_status(decoder, &key_str, &key_len);
|
||||
EXPECT_TRUE(NULL == key_str && key_len == 0);
|
||||
|
||||
if (http_decoder_status(decoder) >= ON_BODY)
|
||||
{
|
||||
http_decoder_fetch_body(decoder, &key_str, &key_len);
|
||||
EXPECT_TRUE(strncmp("1", key_str, key_len) == 0);
|
||||
}
|
||||
|
||||
if (http_decoder_status(decoder) >= ON_HEADER_FIELD)
|
||||
{
|
||||
http_decoder_fetch_next_header(decoder, &iter_index, &key_str, &key_len, &val_str, &val_len);
|
||||
if (next_header == 0)
|
||||
{
|
||||
EXPECT_TRUE(strncmp("connection", key_str, key_len) == 0);
|
||||
EXPECT_TRUE(strncmp("close", val_str, val_len) == 0);
|
||||
|
||||
next_header++;
|
||||
}
|
||||
else if (next_header == 1)
|
||||
{
|
||||
EXPECT_TRUE(strncmp("content-length", key_str, key_len) == 0);
|
||||
EXPECT_TRUE(strncmp("1", val_str, val_len) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
http_decoder_dump(decoder);
|
||||
http_decoder_remove(decoder);
|
||||
}
|
||||
http_decoder_dump(decoder);
|
||||
|
||||
http_decoder_destory(decoder);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
TEST(HTTP_DECODER_TEST, uncomplete_get_request_and_consume_meta)
|
||||
{
|
||||
char *key_str = NULL;
|
||||
char *val_str = NULL;
|
||||
size_t key_len = 0;
|
||||
size_t val_len = 0;
|
||||
int iter_index = 0;
|
||||
int next_header = 0;
|
||||
|
||||
struct http_decoder *decoder = http_decoder_create();
|
||||
http_decoder_init(decoder);
|
||||
|
||||
for (size_t i = 0; i < strlen(request_get); i++)
|
||||
{
|
||||
EXPECT_TRUE(http_decoder_dispatch(decoder, request_get + i, 1) != -2);
|
||||
|
||||
if (http_decoder_status(decoder) >= ON_URI)
|
||||
{
|
||||
EXPECT_TRUE(http_decoder_fetch_dir(decoder) == HTTP_DIR_REQUEST);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(http_decoder_fetch_status_code(decoder) == -1); // unused
|
||||
|
||||
if (http_decoder_status(decoder) >= ON_HEADER_FIELD)
|
||||
{
|
||||
EXPECT_TRUE(http_decoder_fetch_major_version(decoder) == 1);
|
||||
}
|
||||
|
||||
if (http_decoder_status(decoder) >= ON_HEADER_FIELD)
|
||||
{
|
||||
EXPECT_TRUE(http_decoder_fetch_minor_version(decoder) == 1);
|
||||
}
|
||||
|
||||
if (http_decoder_status(decoder) >= ON_URI)
|
||||
{
|
||||
http_decoder_fetch_method(decoder, &key_str, &key_len);
|
||||
EXPECT_TRUE(strncmp("GET", key_str, key_len) == 0);
|
||||
}
|
||||
|
||||
if (http_decoder_status(decoder) >= ON_URI_COMPLETE)
|
||||
{
|
||||
http_decoder_fetch_uri(decoder, &key_str, &key_len);
|
||||
EXPECT_TRUE(strncmp("/index.html", key_str, key_len) == 0);
|
||||
}
|
||||
|
||||
http_decoder_fetch_status(decoder, &key_str, &key_len);
|
||||
EXPECT_TRUE(NULL == key_str && key_len == 0);
|
||||
|
||||
http_decoder_fetch_body(decoder, &key_str, &key_len);
|
||||
EXPECT_TRUE(key_str == NULL && key_len == 0);
|
||||
|
||||
if (http_decoder_status(decoder) >= ON_HEADER_FIELD)
|
||||
{
|
||||
http_decoder_fetch_next_header(decoder, &iter_index, &key_str, &key_len, &val_str, &val_len);
|
||||
if (next_header == 0)
|
||||
{
|
||||
EXPECT_TRUE(strncmp("Host", key_str, key_len) == 0);
|
||||
EXPECT_TRUE(strncmp("www.baidu.com", val_str, val_len) == 0);
|
||||
|
||||
next_header++;
|
||||
}
|
||||
else if (next_header == 1)
|
||||
{
|
||||
EXPECT_TRUE(strncmp("User-Agent", key_str, key_len) == 0);
|
||||
EXPECT_TRUE(strncmp("curl/7.64.1", val_str, val_len) == 0);
|
||||
|
||||
next_header++;
|
||||
}
|
||||
else if (next_header == 2)
|
||||
{
|
||||
EXPECT_TRUE(strncmp("Accept", key_str, key_len) == 0);
|
||||
EXPECT_TRUE(strncmp("*/*", val_str, val_len) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
http_decoder_dump(decoder);
|
||||
http_decoder_remove(decoder);
|
||||
}
|
||||
http_decoder_dump(decoder);
|
||||
|
||||
http_decoder_destory(decoder);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
TEST(HTTP_DECODER_TEST, uncomplete_response_and_consume_meta)
|
||||
{
|
||||
char *key_str = NULL;
|
||||
char *val_str = NULL;
|
||||
size_t key_len = 0;
|
||||
size_t val_len = 0;
|
||||
int iter_index = 0;
|
||||
int next_header = 0;
|
||||
|
||||
char body_data[] = "hello:world";
|
||||
int body_offset = 0;
|
||||
|
||||
struct http_decoder *decoder = http_decoder_create();
|
||||
http_decoder_init(decoder);
|
||||
|
||||
for (size_t i = 0; i < strlen(response_200); i++)
|
||||
{
|
||||
EXPECT_TRUE(http_decoder_dispatch(decoder, response_200 + i, 1) != -2);
|
||||
|
||||
if (http_decoder_status(decoder) >= ON_URI)
|
||||
{
|
||||
EXPECT_TRUE(http_decoder_fetch_dir(decoder) == HTTP_DIR_RESPONSE);
|
||||
}
|
||||
|
||||
if (http_decoder_status(decoder) >= ON_STATUS_COMPLETE)
|
||||
{
|
||||
EXPECT_TRUE(http_decoder_fetch_status_code(decoder) == 200);
|
||||
http_decoder_fetch_status(decoder, &key_str, &key_len);
|
||||
EXPECT_TRUE(strncmp("OK", key_str, key_len) == 0);
|
||||
}
|
||||
|
||||
if (http_decoder_status(decoder) >= ON_HEADER_FIELD)
|
||||
{
|
||||
EXPECT_TRUE(http_decoder_fetch_major_version(decoder) == 1);
|
||||
}
|
||||
|
||||
if (http_decoder_status(decoder) >= ON_HEADER_FIELD)
|
||||
{
|
||||
EXPECT_TRUE(http_decoder_fetch_minor_version(decoder) == 1);
|
||||
}
|
||||
|
||||
http_decoder_fetch_method(decoder, &key_str, &key_len);
|
||||
EXPECT_TRUE(key_str == NULL && key_len == 0);
|
||||
|
||||
http_decoder_fetch_uri(decoder, &key_str, &key_len);
|
||||
EXPECT_TRUE(key_str == NULL && key_len == 0);
|
||||
|
||||
if (http_decoder_status(decoder) >= ON_BODY)
|
||||
{
|
||||
http_decoder_fetch_body(decoder, &key_str, &key_len);
|
||||
if (key_str)
|
||||
{
|
||||
EXPECT_TRUE(strncmp(body_data + body_offset, key_str, key_len) == 0);
|
||||
body_offset += key_len;
|
||||
}
|
||||
}
|
||||
|
||||
if (http_decoder_status(decoder) >= ON_HEADER_FIELD)
|
||||
{
|
||||
http_decoder_fetch_next_header(decoder, &iter_index, &key_str, &key_len, &val_str, &val_len);
|
||||
if (next_header == 0)
|
||||
{
|
||||
EXPECT_TRUE(strncmp("Server", key_str, key_len) == 0);
|
||||
EXPECT_TRUE(strncmp("nginx", val_str, val_len) == 0);
|
||||
|
||||
next_header++;
|
||||
}
|
||||
else if (next_header == 1)
|
||||
{
|
||||
EXPECT_TRUE(strncmp("content-length", key_str, key_len) == 0);
|
||||
EXPECT_TRUE(strncmp("11", val_str, val_len) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
http_decoder_dump(decoder);
|
||||
http_decoder_remove(decoder);
|
||||
}
|
||||
http_decoder_dump(decoder);
|
||||
|
||||
http_decoder_destory(decoder);
|
||||
}
|
||||
#endif
|
||||
|
||||
/******************************************************************************
|
||||
* error test
|
||||
******************************************************************************/
|
||||
|
||||
#if 1
|
||||
TEST(HTTP_DECODER_TEST, error_test_without_http_version)
|
||||
{
|
||||
const char *request_part_1 = "POST /index.html ";
|
||||
const char *request_part_2 = "\r\nconnection:close\r\ncontent-length: 1\r\n\r\n1\r\n\r\n";
|
||||
|
||||
struct http_decoder *decoder = http_decoder_create();
|
||||
http_decoder_init(decoder);
|
||||
|
||||
EXPECT_TRUE(http_decoder_dispatch(decoder, request_part_1, strlen(request_part_1)) != -2);
|
||||
http_decoder_dump(decoder);
|
||||
|
||||
// error occur
|
||||
EXPECT_TRUE(http_decoder_dispatch(decoder, request_part_2, strlen(request_part_2)) == -2);
|
||||
http_decoder_reset(decoder);
|
||||
|
||||
http_decoder_destory(decoder);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
TEST(HTTP_DECODER_TEST, error_test_without_content_length)
|
||||
{
|
||||
char *key_str = NULL;
|
||||
size_t key_len = 0;
|
||||
const char *without_content_length = "POST /index.html HTTP/1.1\r\nconnection:close\r\n\r\n12345\r\n\r\n";
|
||||
|
||||
struct http_decoder *decoder = http_decoder_create();
|
||||
http_decoder_init(decoder);
|
||||
|
||||
EXPECT_TRUE(http_decoder_dispatch(decoder, without_content_length, strlen(without_content_length)) != -2);
|
||||
http_decoder_dump(decoder);
|
||||
|
||||
// no content-length, so skip parsing the request body
|
||||
EXPECT_TRUE(http_decoder_status(decoder) == ON_MESSAGE_COMPLETE);
|
||||
http_decoder_fetch_body(decoder, &key_str, &key_len);
|
||||
EXPECT_TRUE(NULL == key_str && key_len == 0);
|
||||
|
||||
http_decoder_destory(decoder);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
// escape vulnerability
|
||||
TEST(HTTP_DECODER_TEST, error_test_content_length_too_small)
|
||||
{
|
||||
char *key_str = NULL;
|
||||
size_t key_len = 0;
|
||||
const char *content_length_too_small = "POST /index.html HTTP/1.1\r\nconnection:close\r\ncontent-length: 2\r\n\r\n12345\r\n\r\n";
|
||||
|
||||
struct http_decoder *decoder = http_decoder_create();
|
||||
http_decoder_init(decoder);
|
||||
|
||||
EXPECT_TRUE(http_decoder_dispatch(decoder, content_length_too_small, strlen(content_length_too_small)) != -2);
|
||||
http_decoder_dump(decoder);
|
||||
|
||||
// only parse data of the length specified by content-length
|
||||
EXPECT_TRUE(http_decoder_status(decoder) == ON_MESSAGE_COMPLETE);
|
||||
http_decoder_fetch_body(decoder, &key_str, &key_len);
|
||||
EXPECT_TRUE(strncmp("12", key_str, key_len) == 0);
|
||||
|
||||
http_decoder_destory(decoder);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
TEST(HTTP_DECODER_TEST, error_test_content_length_too_big)
|
||||
{
|
||||
char *key_str = NULL;
|
||||
size_t key_len = 0;
|
||||
const char *content_length_too_big = "POST /index.html HTTP/1.1\r\nconnection:close\r\ncontent-length: 20\r\n\r\n12345\r\n\r\n";
|
||||
const char *last_body = "12345678901";
|
||||
|
||||
struct http_decoder *decoder = http_decoder_create();
|
||||
http_decoder_init(decoder);
|
||||
|
||||
// parser content_length_too_big
|
||||
EXPECT_TRUE(http_decoder_dispatch(decoder, content_length_too_big, strlen(content_length_too_big)) != -2);
|
||||
http_decoder_dump(decoder);
|
||||
|
||||
EXPECT_TRUE(http_decoder_status(decoder) == ON_BODY);
|
||||
http_decoder_fetch_body(decoder, &key_str, &key_len);
|
||||
EXPECT_TRUE(strncmp("12345\r\n\r\n", key_str, key_len) == 0);
|
||||
|
||||
// parser last_body
|
||||
http_decoder_remove(decoder);
|
||||
EXPECT_TRUE(http_decoder_dispatch(decoder, last_body, strlen(last_body)) != -2);
|
||||
http_decoder_dump(decoder);
|
||||
|
||||
EXPECT_TRUE(http_decoder_status(decoder) == ON_MESSAGE_COMPLETE);
|
||||
http_decoder_fetch_body(decoder, &key_str, &key_len);
|
||||
EXPECT_TRUE(strncmp(last_body, key_str, key_len) == 0);
|
||||
|
||||
http_decoder_destory(decoder);
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int ret = 0;
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
ret = RUN_ALL_TESTS();
|
||||
return ret;
|
||||
}
|
||||
Reference in New Issue
Block a user