This repository has been archived on 2025-09-14. You can view files and clone it, but cannot push or open issues or pull requests.
Files
tango-tfe/plugin/business/pangu-http/pattern_replace.cpp

243 lines
5.3 KiB
C++
Raw Normal View History

#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)
{
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;
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-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)
{
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;
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-28 15:41:29 +08:00
return 0;
}
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-28 15:41:29 +08:00
continue;
}
if (pre_out != NULL)
{
free(pre_out);
pre_out = NULL;
}
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;
}
}
void simple_replace(const char* find, const char* replacement, const char* input, size_t in_sz, char** output, size_t *output_sz)
{
char* exec_para=NULL;
asprintf(&exec_para,"zone=http_resp_body;substitute=/%s/%s", find, replacement);
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]));
*output_sz=execute_replace_rule(input, strlen(input), kZoneResponseBody, rules, n_got_rule, output);
free(exec_para);
return;
}