diff --git a/doc/admin-guide/plugins/regex_remap.en.rst b/doc/admin-guide/plugins/regex_remap.en.rst index 611dd034ef2..d5744ebe33e 100644 --- a/doc/admin-guide/plugins/regex_remap.en.rst +++ b/doc/admin-guide/plugins/regex_remap.en.rst @@ -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 :: diff --git a/plugins/regex_remap/regex_remap.cc b/plugins/regex_remap/regex_remap.cc index 27201407ca7..76aaa0a6727 100644 --- a/plugins/regex_remap/regex_remap.cc +++ b/plugins/regex_remap/regex_remap.cc @@ -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; } @@ -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; @@ -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]); } @@ -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(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(ih); int ovector[OVECCOUNT]; int lengths[OVECCOUNT / 2 + 1]; int dest_len; @@ -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); } diff --git a/tests/gold_tests/pluginTest/regex_remap/regex_remap.test.py b/tests/gold_tests/pluginTest/regex_remap/regex_remap.test.py index 5685402dadf..b85e57f3566 100644 --- a/tests/gold_tests/pluginTest/regex_remap/regex_remap.test.py +++ b/tests/gold_tests/pluginTest/regex_remap/regex_remap.test.py @@ -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({ @@ -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']