2018-09-27 19:06:57 +08:00
|
|
|
#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;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-28 15:41:29 +08:00
|
|
|
size_t replace_string(const char * in, size_t in_sz, const struct replace_rule * zone, char** out)
|
2018-09-27 19:06:57 +08:00
|
|
|
{
|
|
|
|
|
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)
|
2018-09-28 15:41:29 +08:00
|
|
|
return -1;
|
2018-09-27 19:06:57 +08:00
|
|
|
|
|
|
|
|
pcre2_jit_compile(re, PCRE2_JIT_COMPLETE);
|
|
|
|
|
|
2018-09-28 15:41:29 +08:00
|
|
|
PCRE2_SIZE outbuff_size = in_sz+sizeof(replacement)*MAX_EDIT_MATCHES;
|
|
|
|
|
PCRE2_SIZE outlen = 0;
|
|
|
|
|
PCRE2_UCHAR* out_buffer = NULL;
|
|
|
|
|
not_enough_mem_retry:
|
|
|
|
|
out_buffer = (PCRE2_UCHAR*)malloc(sizeof(PCRE2_UCHAR)*outbuff_size);
|
|
|
|
|
outlen = outbuff_size;
|
|
|
|
|
int rc = pcre2_substitute(re, subject, in_sz, 0, PCRE2_SUBSTITUTE_GLOBAL | PCRE2_SUBSTITUTE_EXTENDED | PCRE2_SUBSTITUTE_OVERFLOW_LENGTH, 0, 0, replacement, PCRE2_ZERO_TERMINATED, out_buffer, &outlen);
|
|
|
|
|
if(outlen>outbuff_size)
|
|
|
|
|
{
|
|
|
|
|
outbuff_size=outlen;
|
|
|
|
|
free(out_buffer);
|
|
|
|
|
out_buffer=NULL;
|
|
|
|
|
goto not_enough_mem_retry;
|
|
|
|
|
}
|
|
|
|
|
if(rc<=0)
|
|
|
|
|
{
|
|
|
|
|
free(out_buffer);
|
|
|
|
|
outlen=rc;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
*out=(char*)out_buffer;
|
|
|
|
|
}
|
|
|
|
|
pcre2_code_free(re);
|
|
|
|
|
return outlen;
|
2018-09-27 19:06:57 +08:00
|
|
|
}
|
|
|
|
|
|
2018-09-28 15:41:29 +08:00
|
|
|
size_t execute_replace_rule(const char * in, size_t in_sz,
|
|
|
|
|
enum replace_zone zone, const struct replace_rule * rules, size_t n_rule, char** out)
|
2018-09-27 19:06:57 +08:00
|
|
|
{
|
|
|
|
|
const struct replace_rule * todo[n_rule];
|
2018-09-28 15:41:29 +08:00
|
|
|
size_t n_todo = 0, i = 0, interator_sz=0, pre_out_sz=0;
|
2018-09-27 19:06:57 +08:00
|
|
|
const char * interator = NULL;
|
2018-09-28 15:41:29 +08:00
|
|
|
char* new_out = NULL, * pre_out = NULL;
|
|
|
|
|
size_t output_size=0;
|
|
|
|
|
if (in_sz == 0 || in==NULL)
|
2018-09-27 19:06:57 +08:00
|
|
|
{
|
2018-09-28 15:41:29 +08:00
|
|
|
return 0;
|
2018-09-27 19:06:57 +08:00
|
|
|
}
|
|
|
|
|
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++)
|
|
|
|
|
{
|
2018-09-28 15:41:29 +08:00
|
|
|
output_size = replace_string(interator, interator_sz, todo[i], &new_out);
|
|
|
|
|
if (output_size == 0)
|
2018-09-27 19:06:57 +08:00
|
|
|
{
|
2018-09-28 15:41:29 +08:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (pre_out != NULL)
|
|
|
|
|
{
|
|
|
|
|
free(pre_out);
|
|
|
|
|
pre_out = NULL;
|
2018-09-27 19:06:57 +08:00
|
|
|
}
|
2018-09-28 15:41:29 +08:00
|
|
|
pre_out = new_out;
|
|
|
|
|
pre_out_sz = output_size;
|
|
|
|
|
|
|
|
|
|
interator = new_out;
|
|
|
|
|
interator_sz = output_size;
|
|
|
|
|
|
|
|
|
|
new_out=NULL;
|
|
|
|
|
output_size=0;
|
|
|
|
|
}
|
|
|
|
|
if(pre_out_sz>0)
|
|
|
|
|
{
|
|
|
|
|
*out=pre_out;
|
|
|
|
|
return pre_out_sz;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
2018-09-27 19:06:57 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|