使用pcre2替代glib从中的regex进行替换。
This commit is contained in:
@@ -7,7 +7,7 @@ target_link_libraries(tfe common)
|
|||||||
target_link_libraries(tfe pthread dl
|
target_link_libraries(tfe pthread dl
|
||||||
openssl-ssl-static
|
openssl-ssl-static
|
||||||
openssl-crypto-static
|
openssl-crypto-static
|
||||||
pthread libevent-static
|
libevent-static
|
||||||
libevent-static-openssl
|
libevent-static-openssl
|
||||||
libevent-static-pthreads
|
libevent-static-pthreads
|
||||||
MESA_handle_logger
|
MESA_handle_logger
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
add_library(pangu-http pangu_logger.cpp pangu_http.cpp)
|
add_library(pangu-http pangu_logger.cpp pangu_http.cpp pattern_replace.cpp)
|
||||||
target_link_libraries(pangu-http common http)
|
target_link_libraries(pangu-http common http)
|
||||||
target_link_libraries(pangu-http librdkafka-static ctemplate-static cjson)
|
target_link_libraries(pangu-http librdkafka-static ctemplate-static cjson pcre2-static)
|
||||||
target_link_libraries(pangu-http maatframe)
|
target_link_libraries(pangu-http maatframe)
|
||||||
|
|
||||||
|
add_executable(test_pattern_replace test_pattern_replace.cpp pattern_replace.cpp)
|
||||||
|
target_link_libraries(test_pattern_replace common libevent-static gtest pcre2-static)
|
||||||
|
file(COPY test_data DESTINATION ./)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "pangu_logger.h"
|
#include "pangu_logger.h"
|
||||||
|
#include "pattern_replace.h"
|
||||||
|
|
||||||
#include <tfe_stream.h>
|
#include <tfe_stream.h>
|
||||||
#include <tfe_utils.h>
|
#include <tfe_utils.h>
|
||||||
@@ -19,11 +20,10 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <regex.h>
|
|
||||||
|
|
||||||
#define MAX_SCAN_RESULT 16
|
#define MAX_SCAN_RESULT 16
|
||||||
#define MAX_EDIT_ZONE_NUM 64
|
#define MAX_EDIT_ZONE_NUM 64
|
||||||
#define MAX_EDIT_MATCHES 16
|
|
||||||
|
|
||||||
enum pangu_action//Bigger action number is prior.
|
enum pangu_action//Bigger action number is prior.
|
||||||
{
|
{
|
||||||
@@ -221,21 +221,7 @@ static void _wrap_non_std_field_write(struct tfe_http_half * half, const char* f
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
enum replace_zone
|
|
||||||
{
|
|
||||||
kZoneRequestUri = 0,
|
|
||||||
kZoneRequestHeaders,
|
|
||||||
kZoneRequestBody,
|
|
||||||
kZoneResponseHeader,
|
|
||||||
kZoneResponseBody,
|
|
||||||
kZoneMax
|
|
||||||
};
|
|
||||||
struct replace_rule
|
|
||||||
{
|
|
||||||
enum replace_zone zone;
|
|
||||||
char * find;
|
|
||||||
char * replace_with;
|
|
||||||
};
|
|
||||||
struct replace_ctx
|
struct replace_ctx
|
||||||
{
|
{
|
||||||
struct replace_rule * rule;
|
struct replace_rule * rule;
|
||||||
@@ -365,10 +351,10 @@ static enum pangu_action decide_ctrl_action(const struct Maat_rule_t * hit_rules
|
|||||||
|
|
||||||
return prior_action;
|
return prior_action;
|
||||||
}
|
}
|
||||||
//https://github.com/AndiDittrich/HttpErrorPages
|
//HTML template is downloaded from https://github.com/AndiDittrich/HttpErrorPages
|
||||||
static void html_generate(int cfg_id, int status_code, char ** page_buff, size_t * page_size)
|
static void html_generate(int cfg_id, int status_code, char ** page_buff, size_t * page_size)
|
||||||
{
|
{
|
||||||
ctemplate::TemplateDictionary dict("pg_page_dict");
|
ctemplate::TemplateDictionary dict("pg_page_dict"); //dict is automatically finalized after function returned.
|
||||||
dict.SetIntValue("cfg_id", cfg_id);
|
dict.SetIntValue("cfg_id", cfg_id);
|
||||||
std::string output;
|
std::string output;
|
||||||
ctemplate::Template * tpl = NULL;
|
ctemplate::Template * tpl = NULL;
|
||||||
@@ -385,7 +371,6 @@ static void html_generate(int cfg_id, int status_code, char ** page_buff, size_t
|
|||||||
}
|
}
|
||||||
|
|
||||||
tpl->Expand(&output, &dict);
|
tpl->Expand(&output, &dict);
|
||||||
//todo: do I need to delete dict?
|
|
||||||
*page_size = output.length();
|
*page_size = output.length();
|
||||||
*page_buff = ALLOC(char, *page_size);
|
*page_buff = ALLOC(char, *page_size);
|
||||||
memcpy(*page_buff, output.c_str(), *page_size);
|
memcpy(*page_buff, output.c_str(), *page_size);
|
||||||
@@ -409,244 +394,6 @@ static int is_http_request(enum tfe_http_event events)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum replace_zone zone_name_to_id(const char * name)
|
|
||||||
{
|
|
||||||
const char * std_name[] = {"http_req_uri",
|
|
||||||
"http_req_header",
|
|
||||||
"http_req_body",
|
|
||||||
"http_resp_header",
|
|
||||||
"http_resp_body",
|
|
||||||
"http_resp_body"};
|
|
||||||
size_t i = 0;
|
|
||||||
for (i = 0; i < sizeof(std_name) / sizeof(const char *); i++)
|
|
||||||
{
|
|
||||||
if (0 == strcasecmp(name, std_name[i]))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (enum replace_zone) i;
|
|
||||||
}
|
|
||||||
static char * strchr_esc(char * s, const char delim)
|
|
||||||
{
|
|
||||||
char * token;
|
|
||||||
if (s == NULL)
|
|
||||||
return NULL;
|
|
||||||
for (token = s; *token != '\0'; token++)
|
|
||||||
{
|
|
||||||
if (*token == '\\')
|
|
||||||
{
|
|
||||||
token++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (*token == delim)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (*token == '\0')
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return token;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
static char * strtok_r_esc(char * s, const char delim, char ** save_ptr)
|
|
||||||
{
|
|
||||||
char * token;
|
|
||||||
|
|
||||||
if (s == NULL) s = *save_ptr;
|
|
||||||
|
|
||||||
/* Scan leading delimiters. */
|
|
||||||
token = strchr_esc(s, delim);
|
|
||||||
if (token == NULL)
|
|
||||||
{
|
|
||||||
*save_ptr = token;
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
/* Find the end of the token. */
|
|
||||||
*token = '\0';
|
|
||||||
token++;
|
|
||||||
*save_ptr = token;
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t format_replace_rule(const char * exec_para, struct replace_rule * replace, size_t n_replace)
|
|
||||||
{
|
|
||||||
char * tmp = ALLOC(char, strlen(exec_para) + 1);
|
|
||||||
char * token = NULL, * sub_token = NULL, * saveptr = NULL, * saveptr2 = NULL;
|
|
||||||
size_t idx = 0;
|
|
||||||
|
|
||||||
const char * str_zone = "zone=";
|
|
||||||
const char * str_subs = "substitute=";
|
|
||||||
memcpy(tmp, exec_para, strlen(exec_para));
|
|
||||||
|
|
||||||
for (token = tmp;; token = NULL)
|
|
||||||
{
|
|
||||||
sub_token = strtok_r(token, ";", &saveptr);
|
|
||||||
if (sub_token == NULL) break;
|
|
||||||
|
|
||||||
if (0 == strncasecmp(sub_token, str_zone, strlen(str_zone)))
|
|
||||||
{
|
|
||||||
replace[idx].zone = zone_name_to_id(sub_token + strlen(str_zone));
|
|
||||||
if (replace[idx].zone == kZoneMax)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub_token = strtok_r(NULL, ";", &saveptr);
|
|
||||||
if (0 == strncasecmp(sub_token, str_subs, strlen(str_subs)))
|
|
||||||
{
|
|
||||||
sub_token += strlen(str_subs) + 1;
|
|
||||||
replace[idx].find = tfe_strdup(strtok_r_esc(sub_token, '/', &saveptr2));
|
|
||||||
replace[idx].replace_with = tfe_strdup(strtok_r_esc(NULL, '/', &saveptr2));
|
|
||||||
|
|
||||||
idx++;
|
|
||||||
if (idx == n_replace)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free(tmp);
|
|
||||||
tmp = NULL;
|
|
||||||
return idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t select_replace_rule(enum replace_zone zone, const struct replace_rule * replace, size_t n_replace,
|
|
||||||
const struct replace_rule ** selected, size_t n_selected)
|
|
||||||
{
|
|
||||||
size_t i = 0, j = 0;
|
|
||||||
for (i = 0; i < n_replace && j < n_selected; i++)
|
|
||||||
{
|
|
||||||
if (replace[i].zone == zone)
|
|
||||||
{
|
|
||||||
selected[j] = replace + i;
|
|
||||||
j++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return j;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct evbuffer * replace_string(const char * in, const struct replace_rule * zone)
|
|
||||||
{
|
|
||||||
//Reference to https://www.lemoda.net/c/unix-regex/
|
|
||||||
// Regular Expression test: https://regex101.com/
|
|
||||||
regex_t reg;
|
|
||||||
int status = 0, is_replaced = 0;
|
|
||||||
struct evbuffer * out = NULL;
|
|
||||||
size_t in_sz = strlen(in);
|
|
||||||
|
|
||||||
size_t replace_len = strlen(zone->replace_with);
|
|
||||||
|
|
||||||
assert(strlen(zone->find) != 0);
|
|
||||||
status = regcomp(®, zone->find, REG_EXTENDED | REG_NEWLINE);
|
|
||||||
if (status != 0)
|
|
||||||
{
|
|
||||||
char error_message[TFE_STRING_MAX];
|
|
||||||
regerror(status, ®, error_message, sizeof(error_message));
|
|
||||||
TFE_LOG_ERROR(g_pangu_rt->local_logger, "Regex error compiling '%s': %s\n",
|
|
||||||
zone->find, error_message);
|
|
||||||
regfree(®);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* "p" is a pointer into the string which points to the end of the previous match. */
|
|
||||||
const char * p = in;
|
|
||||||
/* "pre_sub_expr_end" is a pointer into the string which points to the end of the previous sub expression match. */
|
|
||||||
const char * pre_sub_expr_end = NULL;
|
|
||||||
|
|
||||||
/* "N_matches" is the maximum number of matches allowed. */
|
|
||||||
const int n_matches = MAX_EDIT_MATCHES;
|
|
||||||
/* "M" contains the matches found. */
|
|
||||||
regmatch_t m[n_matches];
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
int nomatch = regexec(®, p, n_matches, m, 0);
|
|
||||||
if (nomatch)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (is_replaced == 0)
|
|
||||||
{
|
|
||||||
out = evbuffer_new();
|
|
||||||
is_replaced = 1;
|
|
||||||
}
|
|
||||||
assert(m[0].rm_so != -1);
|
|
||||||
pre_sub_expr_end = p;
|
|
||||||
if (m[1].rm_so == -1)//no sub expr, replace the entire expr.
|
|
||||||
{
|
|
||||||
evbuffer_add(out, pre_sub_expr_end, m[0].rm_so - (pre_sub_expr_end - p));
|
|
||||||
evbuffer_add(out, zone->replace_with, replace_len);
|
|
||||||
pre_sub_expr_end = p + m[0].rm_eo;
|
|
||||||
}
|
|
||||||
else //have sub expr, replace the sub expr.
|
|
||||||
{
|
|
||||||
for (i = 1, pre_sub_expr_end = p; i < n_matches; i++)
|
|
||||||
{
|
|
||||||
if (m[i].rm_so == -1)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
evbuffer_add(out, pre_sub_expr_end, m[i].rm_so - (pre_sub_expr_end - p));
|
|
||||||
evbuffer_add(out, zone->replace_with, replace_len);
|
|
||||||
pre_sub_expr_end = p + m[i].rm_eo;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p += m[0].rm_eo;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_replaced)
|
|
||||||
{
|
|
||||||
evbuffer_add(out, pre_sub_expr_end, in_sz - (pre_sub_expr_end - p));
|
|
||||||
}
|
|
||||||
|
|
||||||
regfree(®);
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct evbuffer * execute_replace_rule(const char * in, size_t in_sz,
|
|
||||||
enum replace_zone zone, const struct replace_rule * rules, size_t n_rule)
|
|
||||||
{
|
|
||||||
const struct replace_rule * todo[MAX_EDIT_ZONE_NUM];
|
|
||||||
size_t n_todo = 0, i = 0;
|
|
||||||
struct evbuffer * out = NULL;
|
|
||||||
const char * interator = NULL;
|
|
||||||
struct evbuffer * new_out = NULL, * pre_out = NULL;
|
|
||||||
if (in == 0)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
//Do not process buffer that contains '\0'.
|
|
||||||
if (0 != memchr(in, '\0', in_sz))
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
n_todo = select_replace_rule(zone, rules, n_rule, todo, MAX_EDIT_ZONE_NUM);
|
|
||||||
interator = in;
|
|
||||||
for (i = 0; i < n_todo; i++)
|
|
||||||
{
|
|
||||||
new_out = replace_string(interator, todo[i]);
|
|
||||||
if (new_out != NULL)
|
|
||||||
{
|
|
||||||
pre_out = out;
|
|
||||||
out = new_out;
|
|
||||||
interator = (char *) evbuffer_pullup(out, -1);
|
|
||||||
|
|
||||||
if (pre_out != NULL)
|
|
||||||
{
|
|
||||||
evbuffer_free(pre_out);
|
|
||||||
pre_out = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
void http_replace(const struct tfe_stream * stream, const struct tfe_http_session * session,
|
void http_replace(const struct tfe_stream * stream, const struct tfe_http_session * session,
|
||||||
enum tfe_http_event events, const unsigned char * body_frag, size_t frag_size, struct pangu_http_ctx * ctx)
|
enum tfe_http_event events, const unsigned char * body_frag, size_t frag_size, struct pangu_http_ctx * ctx)
|
||||||
|
|||||||
212
plugin/business/pangu-http/pattern_replace.cpp
Normal file
212
plugin/business/pangu-http/pattern_replace.cpp
Normal file
@@ -0,0 +1,212 @@
|
|||||||
|
#include "pattern_replace.h"
|
||||||
|
|
||||||
|
#include <tfe_utils.h>
|
||||||
|
|
||||||
|
#define PCRE2_CODE_UNIT_WIDTH 8
|
||||||
|
#include <pcre2.h>
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#define MAX_EDIT_MATCHES 16
|
||||||
|
|
||||||
|
enum replace_zone zone_name_to_id(const char * name)
|
||||||
|
{
|
||||||
|
const char * std_name[] = {"http_req_uri",
|
||||||
|
"http_req_header",
|
||||||
|
"http_req_body",
|
||||||
|
"http_resp_header",
|
||||||
|
"http_resp_body",
|
||||||
|
"http_resp_body"};
|
||||||
|
size_t i = 0;
|
||||||
|
for (i = 0; i < sizeof(std_name) / sizeof(const char *); i++)
|
||||||
|
{
|
||||||
|
if (0 == strcasecmp(name, std_name[i]))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (enum replace_zone) i;
|
||||||
|
}
|
||||||
|
static char * strchr_esc(char * s, const char delim)
|
||||||
|
{
|
||||||
|
char * token;
|
||||||
|
if (s == NULL)
|
||||||
|
return NULL;
|
||||||
|
for (token = s; *token != '\0'; token++)
|
||||||
|
{
|
||||||
|
if (*token == '\\')
|
||||||
|
{
|
||||||
|
token++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (*token == delim)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (*token == '\0')
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static char * strtok_r_esc(char * s, const char delim, char ** save_ptr)
|
||||||
|
{
|
||||||
|
char * token;
|
||||||
|
|
||||||
|
if (s == NULL) s = *save_ptr;
|
||||||
|
|
||||||
|
/* Scan leading delimiters. */
|
||||||
|
token = strchr_esc(s, delim);
|
||||||
|
if (token == NULL)
|
||||||
|
{
|
||||||
|
*save_ptr = token;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
/* Find the end of the token. */
|
||||||
|
*token = '\0';
|
||||||
|
token++;
|
||||||
|
*save_ptr = token;
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t format_replace_rule(const char * exec_para, struct replace_rule * replace, size_t n_replace)
|
||||||
|
{
|
||||||
|
char * tmp = ALLOC(char, strlen(exec_para) + 1);
|
||||||
|
char * token = NULL, * sub_token = NULL, * saveptr = NULL, * saveptr2 = NULL;
|
||||||
|
size_t idx = 0;
|
||||||
|
|
||||||
|
const char * str_zone = "zone=";
|
||||||
|
const char * str_subs = "substitute=";
|
||||||
|
memcpy(tmp, exec_para, strlen(exec_para));
|
||||||
|
|
||||||
|
for (token = tmp;; token = NULL)
|
||||||
|
{
|
||||||
|
sub_token = strtok_r(token, ";", &saveptr);
|
||||||
|
if (sub_token == NULL) break;
|
||||||
|
|
||||||
|
if (0 == strncasecmp(sub_token, str_zone, strlen(str_zone)))
|
||||||
|
{
|
||||||
|
replace[idx].zone = zone_name_to_id(sub_token + strlen(str_zone));
|
||||||
|
if (replace[idx].zone == kZoneMax)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub_token = strtok_r(NULL, ";", &saveptr);
|
||||||
|
if (0 == strncasecmp(sub_token, str_subs, strlen(str_subs)))
|
||||||
|
{
|
||||||
|
sub_token += strlen(str_subs) + 1;
|
||||||
|
replace[idx].find = tfe_strdup(strtok_r_esc(sub_token, '/', &saveptr2));
|
||||||
|
replace[idx].replace_with = tfe_strdup(strtok_r_esc(NULL, '/', &saveptr2));
|
||||||
|
|
||||||
|
idx++;
|
||||||
|
if (idx == n_replace)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(tmp);
|
||||||
|
tmp = NULL;
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t select_replace_rule(enum replace_zone zone, const struct replace_rule * replace, size_t n_replace,
|
||||||
|
const struct replace_rule ** selected, size_t n_selected)
|
||||||
|
{
|
||||||
|
size_t i = 0, j = 0;
|
||||||
|
for (i = 0; i < n_replace && j < n_selected; i++)
|
||||||
|
{
|
||||||
|
if (replace[i].zone == zone)
|
||||||
|
{
|
||||||
|
selected[j] = replace + i;
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct evbuffer * replace_string(const char * in, size_t in_sz, const struct replace_rule * zone)
|
||||||
|
{
|
||||||
|
|
||||||
|
int status = 0, is_replaced = 0;
|
||||||
|
struct evbuffer * out = NULL;
|
||||||
|
|
||||||
|
size_t replace_len = strlen(zone->replace_with);
|
||||||
|
|
||||||
|
assert(strlen(zone->find) != 0);
|
||||||
|
|
||||||
|
int error;
|
||||||
|
PCRE2_SIZE erroffset;
|
||||||
|
|
||||||
|
const PCRE2_SPTR pattern = (PCRE2_SPTR)zone->find;
|
||||||
|
const PCRE2_SPTR subject = (PCRE2_SPTR)in;
|
||||||
|
const PCRE2_SPTR replacement = (PCRE2_SPTR)zone->replace_with;
|
||||||
|
|
||||||
|
pcre2_code *re = pcre2_compile(pattern, PCRE2_ZERO_TERMINATED, 0, &error, &erroffset, 0);
|
||||||
|
if (re == 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
pcre2_jit_compile(re, PCRE2_JIT_COMPLETE);
|
||||||
|
|
||||||
|
PCRE2_SIZE outlen = in_sz*2;
|
||||||
|
PCRE2_UCHAR* output = (PCRE2_UCHAR*)malloc(sizeof(PCRE2_UCHAR)*outlen);
|
||||||
|
|
||||||
|
int rc = pcre2_substitute(re, subject, in_sz, 0, PCRE2_SUBSTITUTE_GLOBAL | PCRE2_SUBSTITUTE_EXTENDED, 0, 0, replacement, PCRE2_ZERO_TERMINATED, output, &outlen);
|
||||||
|
if (rc >= 0)
|
||||||
|
printf("%s\n", output);
|
||||||
|
|
||||||
|
pcre2_code_free(re);
|
||||||
|
free(output);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct evbuffer * execute_replace_rule(const char * in, size_t in_sz,
|
||||||
|
enum replace_zone zone, const struct replace_rule * rules, size_t n_rule)
|
||||||
|
{
|
||||||
|
const struct replace_rule * todo[n_rule];
|
||||||
|
size_t n_todo = 0, i = 0, interator_sz=0;
|
||||||
|
struct evbuffer * out = NULL;
|
||||||
|
const char * interator = NULL;
|
||||||
|
struct evbuffer * new_out = NULL, * pre_out = NULL;
|
||||||
|
if (in == 0)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
//Do not process buffer that contains '\0'.
|
||||||
|
if (0 != memchr(in, '\0', in_sz))
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
n_todo = select_replace_rule(zone, rules, n_rule, todo, n_rule);
|
||||||
|
interator = in;
|
||||||
|
interator_sz = in_sz;
|
||||||
|
for (i = 0; i < n_todo; i++)
|
||||||
|
{
|
||||||
|
new_out = replace_string(interator, interator_sz, todo[i]);
|
||||||
|
if (new_out != NULL)
|
||||||
|
{
|
||||||
|
pre_out = out;
|
||||||
|
out = new_out;
|
||||||
|
interator = (char *) evbuffer_pullup(out, -1);
|
||||||
|
interator_sz = evbuffer_get_length(out);
|
||||||
|
if (pre_out != NULL)
|
||||||
|
{
|
||||||
|
evbuffer_free(pre_out);
|
||||||
|
pre_out = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
26
plugin/business/pangu-http/pattern_replace.h
Normal file
26
plugin/business/pangu-http/pattern_replace.h
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <event2/buffer.h>
|
||||||
|
enum replace_zone
|
||||||
|
{
|
||||||
|
kZoneRequestUri = 0,
|
||||||
|
kZoneRequestHeaders,
|
||||||
|
kZoneRequestBody,
|
||||||
|
kZoneResponseHeader,
|
||||||
|
kZoneResponseBody,
|
||||||
|
kZoneMax
|
||||||
|
};
|
||||||
|
struct replace_rule
|
||||||
|
{
|
||||||
|
enum replace_zone zone;
|
||||||
|
char * find;
|
||||||
|
char * replace_with;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//@parm exec_para example input:
|
||||||
|
//zone=http_req_body; substitute=/中華民國/中华人民共和国;zone=http_resp_header; substitute=/Content-Type:\btext\/html/Content-Type:\bvideo\/mp4
|
||||||
|
//@return formated rule number.
|
||||||
|
size_t format_replace_rule(const char * exec_para, struct replace_rule * replace, size_t n_replace);
|
||||||
|
struct evbuffer * execute_replace_rule(const char * in, size_t in_sz, enum replace_zone zone, const struct replace_rule * rules, size_t n_rule);
|
||||||
|
|
||||||
69
plugin/business/pangu-http/test_data/facebook_index.html
Normal file
69
plugin/business/pangu-http/test_data/facebook_index.html
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
45
plugin/business/pangu-http/test_pattern_replace.cpp
Normal file
45
plugin/business/pangu-http/test_pattern_replace.cpp
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
#include "pattern_replace.h"
|
||||||
|
|
||||||
|
#include <sys/types.h>//fstat
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
TEST(PatternReplace, Pure)
|
||||||
|
{
|
||||||
|
const char* filename="./test_data/facebook_index.html";
|
||||||
|
const char* exec_para="zone=http_resp_body;substitute=/添加手机号/Mobile\bPhone";
|
||||||
|
size_t n_got_rule=0;
|
||||||
|
struct replace_rule rules[16];
|
||||||
|
n_got_rule=format_replace_rule(exec_para, rules, sizeof(rules)/sizeof(rules[0]));
|
||||||
|
EXPECT_EQ(n_got_rule, 1);
|
||||||
|
|
||||||
|
FILE* fp=NULL;
|
||||||
|
struct stat file_info;
|
||||||
|
stat(filename, &file_info);
|
||||||
|
size_t file_size=file_info.st_size;
|
||||||
|
|
||||||
|
fp=fopen(filename,"r");
|
||||||
|
ASSERT_FALSE(fp==NULL);
|
||||||
|
if(fp==NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
char* file_buff=(char*)malloc(file_size);
|
||||||
|
fread(file_buff,1,file_size,fp);
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
struct evbuffer* output=NULL;
|
||||||
|
output=execute_replace_rule(file_buff, file_size, kZoneResponseBody, rules,n_got_rule);
|
||||||
|
EXPECT_FALSE(output==NULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char ** argv)
|
||||||
|
{
|
||||||
|
|
||||||
|
::testing::InitGoogleTest(&argc, argv);
|
||||||
|
return RUN_ALL_TESTS();
|
||||||
|
}
|
||||||
|
|
||||||
14
vendor/CMakeLists.txt
vendored
14
vendor/CMakeLists.txt
vendored
@@ -193,3 +193,17 @@ add_library(ctemplate-static STATIC IMPORTED GLOBAL)
|
|||||||
add_dependencies(ctemplate-static ctemplate)
|
add_dependencies(ctemplate-static ctemplate)
|
||||||
set_property(TARGET ctemplate-static PROPERTY IMPORTED_LOCATION ${INSTALL_DIR}/lib/libctemplate.a)
|
set_property(TARGET ctemplate-static PROPERTY IMPORTED_LOCATION ${INSTALL_DIR}/lib/libctemplate.a)
|
||||||
set_property(TARGET ctemplate-static PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${INSTALL_DIR}/include)
|
set_property(TARGET ctemplate-static PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${INSTALL_DIR}/include)
|
||||||
|
|
||||||
|
### pcre2
|
||||||
|
ExternalProject_Add(pcre2 PREFIX pcre2
|
||||||
|
URL ${CMAKE_CURRENT_SOURCE_DIR}/pcre2-10.32.tar.gz
|
||||||
|
URL_MD5 a660db882ff171e6a0de5fb1decd5ff5
|
||||||
|
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=<INSTALL_DIR> -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE})
|
||||||
|
|
||||||
|
ExternalProject_Get_Property(pcre2 INSTALL_DIR)
|
||||||
|
file(MAKE_DIRECTORY ${INSTALL_DIR}/include)
|
||||||
|
|
||||||
|
add_library(pcre2-static STATIC IMPORTED GLOBAL)
|
||||||
|
add_dependencies(pcre2-static ctemplate)
|
||||||
|
set_property(TARGET pcre2-static PROPERTY IMPORTED_LOCATION ${INSTALL_DIR}/lib/libpcre2-8.a)
|
||||||
|
set_property(TARGET pcre2-static PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${INSTALL_DIR}/include)
|
||||||
|
|||||||
Reference in New Issue
Block a user