213 lines
4.6 KiB
C++
213 lines
4.6 KiB
C++
#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;
|
|
}
|
|
|
|
|