Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions doc/admin-guide/plugins/regex_remap.en.rst
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,16 @@ profile dump, you can do ::
$ sudo touch remap.config
$ sudo traffic_ctl config reload

By default, this plugin operates on the post-remap URL (including any
remappings done by preceding plugins in the remap rule). This behavior
can be modified with the optional parameter ::

@pparam=[no-]pristine [default: off]

With ``@pparam=pristine``, the plugin will operate on the pre-remap, or
pristine, URL. (But, if no regular expression in the config file is
matched, the resulting URL will still be the post-remap URL.)

By default, only the path and query string of the URL are provided for
the regular expressions to match. The following optional parameters can
be used to modify the plugin instance behavior ::
Expand Down
49 changes: 39 additions & 10 deletions plugins/regex_remap/regex_remap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -78,14 +78,14 @@ struct UrlComponents {
UrlComponents() = default;

void
populate(TSRemapRequestInfo *rri)
populate(TSMBuffer bufp, TSMLoc url)
{
scheme = TSUrlSchemeGet(rri->requestBufp, rri->requestUrl, &scheme_len);
host = TSUrlHostGet(rri->requestBufp, rri->requestUrl, &host_len);
path = TSUrlPathGet(rri->requestBufp, rri->requestUrl, &path_len);
query = TSUrlHttpQueryGet(rri->requestBufp, rri->requestUrl, &query_len);
matrix = TSUrlHttpParamsGet(rri->requestBufp, rri->requestUrl, &matrix_len);
port = TSUrlPortGet(rri->requestBufp, rri->requestUrl);
scheme = TSUrlSchemeGet(bufp, url, &scheme_len);
host = TSUrlHostGet(bufp, url, &host_len);
path = TSUrlPathGet(bufp, url, &path_len);
query = TSUrlHttpQueryGet(bufp, url, &query_len);
matrix = TSUrlHttpParamsGet(bufp, url, &matrix_len);
port = TSUrlPortGet(bufp, url);

url_len = scheme_len + host_len + path_len + query_len + matrix_len + 32;
}
Expand Down Expand Up @@ -626,6 +626,7 @@ struct RemapInstance {

RemapRegex *first = nullptr;
RemapRegex *last = nullptr;
bool pristine_url = false;
bool profile = false;
bool method = false;
bool query_string = true;
Expand Down Expand Up @@ -726,6 +727,10 @@ TSRemapNewInstance(int argc, char *argv[], void **ih, char * /* errbuf ATS_UNUSE
ri->host = true;
} else if (strncmp(argv[i], "no-host", 7) == 0) {
ri->host = false;
} else if (strcmp(argv[i], "pristine") == 0) {
ri->pristine_url = true;
} else if (strcmp(argv[i], "no-pristine") == 0) {
ri->pristine_url = false;
} else {
TSError("[%s] invalid option '%s'", PLUGIN_NAME, argv[i]);
}
Expand Down Expand Up @@ -913,12 +918,36 @@ TSRemapDoRemap(void *ih, TSHttpTxn txnp, TSRemapRequestInfo *rri)
TSDebug(PLUGIN_NAME, "Falling back to default URL on regex remap without rules");
return TSREMAP_NO_REMAP;
}
RemapInstance *ri = static_cast<RemapInstance *>(ih);

struct SrcUrl {
TSMBuffer bufp;
TSMLoc loc;
bool bad;
};

const SrcUrl src_url([=]() -> SrcUrl {
SrcUrl u;

if (ri->pristine_url) {
u.bufp = rri->requestBufp;
u.loc = rri->requestUrl;
u.bad = false;

} else {
u.bad = TSHttpTxnPristineUrlGet(txnp, &u.bufp, &u.loc) != TS_SUCCESS;
}
return u;
}());

if (src_url.bad) {
return TSREMAP_NO_REMAP;
}

// Populate the request url
UrlComponents req_url;
req_url.populate(rri);
req_url.populate(src_url.bufp, src_url.loc);

RemapInstance *ri = static_cast<RemapInstance *>(ih);
int ovector[OVECCOUNT];
int lengths[OVECCOUNT / 2 + 1];
int dest_len;
Expand Down Expand Up @@ -1061,7 +1090,7 @@ TSRemapDoRemap(void *ih, TSHttpTxn txnp, TSRemapRequestInfo *rri)
const char *start = dest;

// Setup the new URL
if (TS_PARSE_ERROR == TSUrlParse(rri->requestBufp, rri->requestUrl, &start, start + dest_len)) {
if (TS_PARSE_ERROR == TSUrlParse(src_url.bufp, src_url.loc, &start, start + dest_len)) {
TSHttpTxnStatusSet(txnp, TS_HTTP_STATUS_INTERNAL_SERVER_ERROR);
TSError("[%s] can't parse substituted URL string", PLUGIN_NAME);
}
Expand Down
15 changes: 13 additions & 2 deletions tests/gold_tests/pluginTest/regex_remap/regex_remap.test.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,19 @@
regex_remap_conf_path = os.path.join(ts.Variables.CONFIGDIR, 'regex_remap.conf')
curl_and_args = 'curl -s -D - -v --proxy localhost:{} '.format(ts.Variables.port)

path1_rule = 'path1 {}\n'.format(int(time.time()) + 600)

ts.Disk.File(regex_remap_conf_path, typename="ats:config").AddLines([
"# regex_remap configuration\n"
"^/alpha/bravo/[?]((?!action=(newsfeed|calendar|contacts|notepad)).)*$ http://example.one @status=301\n"
"^/charlie http://example.one @status=301\n"
])

ts.Disk.remap_config.AddLine(
"map http://example.one/ http://localhost:{}/ @plugin=regex_remap.so @pparam=regex_remap.conf\n".format(server.Variables.Port)
)
ts.Disk.remap_config.AddLine(
"map http://example.two/charlie http://localhost:{}/delta ".format(server.Variables.Port) +
"@plugin=regex_remap.so @pparam=regex_remap.conf @pparam=pristine\n"
)

# minimal configuration
ts.Disk.records_config.update({
Expand All @@ -80,6 +83,14 @@
tr.Processes.Default.Streams.stdout = "gold/regex_remap_smoke.gold"
tr.StillRunningAfter = ts

tr = Test.AddTestRun("pristine test")
tr.Processes.Default.Command = (
curl_and_args + '--header "uuid: {}" http://example.two/charlie'.format(creq["headers"]["fields"][1][1])
)
tr.Processes.Default.ReturnCode = 0
tr.Processes.Default.Streams.stdout = "gold/regex_remap_smoke.gold"
tr.StillRunningAfter = ts

# Crash test.
tr = Test.AddTestRun("crash test")
creq = replay_txns[1]['client-request']
Expand Down