You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by zw...@apache.org on 2020/03/26 20:46:48 UTC
[trafficserver] 03/03: Adjusts the format for header_rewrite string
concatenation
This is an automated email from the ASF dual-hosted git repository.
zwoop pushed a commit to branch 8.1.x
in repository https://gitbox.apache.org/repos/asf/trafficserver.git
commit 37c56b0b2fcd8b89b066baafdb8e498ea72bcc9e
Author: Randall Meyer <ra...@yahoo.com>
AuthorDate: Mon Nov 5 16:52:28 2018 -0800
Adjusts the format for header_rewrite string concatenation
Drop the "+" from the syntax. This syntax was never released and
therefore doesn't have backwards compatibilty requirements.
eg
add-header X-Party "let's party like it's %{NOW:YEAR}!"
(quotes optional)
(cherry picked from commit 3a5763b1c0f649ec9fb2fe90c8c740b28ce0874e)
Conflicts:
doc/admin-guide/plugins/header_rewrite.en.rst
---
doc/admin-guide/plugins/header_rewrite.en.rst | 9 ++-
plugins/header_rewrite/header_rewrite.cc | 4 +-
plugins/header_rewrite/header_rewrite_test.cc | 91 +++++++++++++++++++++++++--
plugins/header_rewrite/parser.cc | 71 +++++++++++++++++----
plugins/header_rewrite/parser.h | 16 ++++-
plugins/header_rewrite/regex_helper.cc | 12 ----
plugins/header_rewrite/regex_helper.h | 2 -
plugins/header_rewrite/value.cc | 30 ++++-----
8 files changed, 186 insertions(+), 49 deletions(-)
diff --git a/doc/admin-guide/plugins/header_rewrite.en.rst b/doc/admin-guide/plugins/header_rewrite.en.rst
index 128f457..12f9b4a 100644
--- a/doc/admin-guide/plugins/header_rewrite.en.rst
+++ b/doc/admin-guide/plugins/header_rewrite.en.rst
@@ -806,9 +806,14 @@ QSA Append the results of the rule to the query string.
Values and Variable Expansion
-----------------------------
-You can concatenate values using strings, condition values and variable expansions via the ``+`` operator. Variables (eg %<tag>) in the concatenation must be enclosed in double quotes ``"``::
- add-header CustomHeader "Hello from " + %{IP:SERVER} + ":" + "%<INBOUND:LOCAL-PORT>"
+You can concatenate values using strings, condition values and variable expansions on the same line.
+
+ add-header CustomHeader "Hello from %{IP:SERVER}:%<INBOUND:LOCAL-PORT>"
+
+However, the above example is somewhat contrived to show the old tags, it should instead be written as
+
+ add-header CustomHeader "Hello from %{IP:SERVER}:%{INBOUND:LOCAL-PORT}"
Concatenation is not supported in condition testing.
diff --git a/plugins/header_rewrite/header_rewrite.cc b/plugins/header_rewrite/header_rewrite.cc
index af19305..60caecd 100644
--- a/plugins/header_rewrite/header_rewrite.cc
+++ b/plugins/header_rewrite/header_rewrite.cc
@@ -184,7 +184,7 @@ RulesConfig::parse_config(const std::string &fname, TSHttpHookID default_hook)
continue;
}
- Parser p(line, true); // Tokenize and parse this line preserving quotes from input
+ Parser p(line); // Tokenize and parse this line
if (p.empty()) {
continue;
}
@@ -470,6 +470,6 @@ TSRemapDoRemap(void *ih, TSHttpTxn rh, TSRemapRequestInfo *rri)
rule = rule->next;
}
- TSDebug(PLUGIN_NAME_DBG, "Returing from TSRemapDoRemap with status: %d", rval);
+ TSDebug(PLUGIN_NAME_DBG, "Returning from TSRemapDoRemap with status: %d", rval);
return rval;
}
diff --git a/plugins/header_rewrite/header_rewrite_test.cc b/plugins/header_rewrite/header_rewrite_test.cc
index c81113a..6a4e181 100644
--- a/plugins/header_rewrite/header_rewrite_test.cc
+++ b/plugins/header_rewrite/header_rewrite_test.cc
@@ -33,6 +33,12 @@ const char PLUGIN_NAME_DBG[] = "TEST_dbg_header_rewrite";
extern "C" void
TSError(const char *fmt, ...)
{
+ va_list args;
+
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
}
class ParserTest : public Parser
@@ -40,7 +46,7 @@ class ParserTest : public Parser
public:
ParserTest(const std::string &line) : Parser(line), res(true) { std::cout << "Finished parser test: " << line << std::endl; }
std::vector<std::string>
- getTokens()
+ getTokens() const
{
return _tokens;
}
@@ -58,17 +64,38 @@ public:
bool res;
};
+class SimpleTokenizerTest : public SimpleTokenizer
+{
+public:
+ SimpleTokenizerTest(const std::string &line) : SimpleTokenizer(line), res(true)
+ {
+ std::cout << "Finished tokenizer test: " << line << std::endl;
+ }
+
+ template <typename T, typename U>
+ void
+ do_parser_check(T x, U y, int line = 0)
+ {
+ if (x != y) {
+ std::cerr << "CHECK FAILED on line " << line << ": |" << x << "| != |" << y << "|" << std::endl;
+ res = false;
+ }
+ }
+
+ bool res;
+};
+
#define CHECK_EQ(x, y) \
do { \
p.do_parser_check((x), (y), __LINE__); \
- } while (false);
+ } while (false)
#define END_TEST(s) \
do { \
if (!p.res) { \
++errors; \
} \
- } while (false);
+ } while (false)
int
test_parsing()
@@ -336,6 +363,17 @@ test_parsing()
END_TEST();
}
+ {
+ ParserTest p(R"(set-header Alt-Svc "quic=\":443\"; v=\"35\"")");
+
+ CHECK_EQ(p.getTokens().size(), 3UL);
+ CHECK_EQ(p.getTokens()[0], "set-header");
+ CHECK_EQ(p.getTokens()[1], "Alt-Svc");
+ CHECK_EQ(p.getTokens()[2], R"(quic=":443"; v="35")");
+
+ END_TEST();
+ }
+
/*
* test some failure scenarios
*/
@@ -426,9 +464,54 @@ test_processing()
}
int
+test_tokenizer()
+{
+ int errors = 0;
+
+ {
+ SimpleTokenizerTest p("a simple test");
+ CHECK_EQ(p.get_tokens().size(), 1UL);
+ CHECK_EQ(p.get_tokens()[0], "a simple test");
+ }
+
+ {
+ SimpleTokenizerTest p(R"(quic=":443"; v="35")");
+ CHECK_EQ(p.get_tokens().size(), 1UL);
+ CHECK_EQ(p.get_tokens()[0], R"(quic=":443"; v="35")");
+ }
+
+ {
+ SimpleTokenizerTest p(R"(let's party like it's %{NOW:YEAR})");
+ CHECK_EQ(p.get_tokens().size(), 2UL);
+ CHECK_EQ(p.get_tokens()[0], "let's party like it's ");
+ CHECK_EQ(p.get_tokens()[1], "%{NOW:YEAR}");
+ }
+ {
+ SimpleTokenizerTest p("A racoon's favorite tag is %<cqhm> in %{NOW:YEAR}!");
+ CHECK_EQ(p.get_tokens().size(), 5UL);
+ CHECK_EQ(p.get_tokens()[0], "A racoon's favorite tag is ");
+ CHECK_EQ(p.get_tokens()[1], "%<cqhm>");
+ CHECK_EQ(p.get_tokens()[2], " in ");
+ CHECK_EQ(p.get_tokens()[3], "%{NOW:YEAR}");
+ CHECK_EQ(p.get_tokens()[4], "!");
+ }
+
+ {
+ SimpleTokenizerTest p(R"(Hello from %{IP:SERVER}:%{INBOUND:LOCAL-PORT})");
+ CHECK_EQ(p.get_tokens().size(), 4UL);
+ CHECK_EQ(p.get_tokens()[0], "Hello from ");
+ CHECK_EQ(p.get_tokens()[1], "%{IP:SERVER}");
+ CHECK_EQ(p.get_tokens()[2], ":");
+ CHECK_EQ(p.get_tokens()[3], "%{INBOUND:LOCAL-PORT}");
+ }
+
+ return errors;
+}
+
+int
main()
{
- if (test_parsing() || test_processing()) {
+ if (test_parsing() || test_processing() || test_tokenizer()) {
return 1;
}
diff --git a/plugins/header_rewrite/parser.cc b/plugins/header_rewrite/parser.cc
index fc821d3..4fc1bf4 100644
--- a/plugins/header_rewrite/parser.cc
+++ b/plugins/header_rewrite/parser.cc
@@ -28,9 +28,9 @@
#include "parser.h"
-enum ParserState { PARSER_DEFAULT, PARSER_IN_QUOTE, PARSER_IN_REGEX };
+enum ParserState { PARSER_DEFAULT, PARSER_IN_QUOTE, PARSER_IN_REGEX, PARSER_IN_EXPANSION };
-Parser::Parser(const std::string &original_line, bool preserve_quotes) : _cond(false), _empty(false)
+Parser::Parser(const std::string &original_line) : _cond(false), _empty(false)
{
std::string line = original_line;
ParserState state = PARSER_DEFAULT;
@@ -39,8 +39,7 @@ Parser::Parser(const std::string &original_line, bool preserve_quotes) : _cond(f
size_t cur_token_length = 0;
for (size_t i = 0; i < line.size(); ++i) {
- if ((state == PARSER_DEFAULT) &&
- (std::isspace(line[i]) || ((line[i] == '=') || (line[i] == '>') || (line[i] == '<') || (line[i] == '+')))) {
+ if ((state == PARSER_DEFAULT) && (std::isspace(line[i]) || ((line[i] == '=')))) {
if (extracting_token) {
cur_token_length = i - cur_token_start;
if (cur_token_length > 0) {
@@ -78,11 +77,7 @@ Parser::Parser(const std::string &original_line, bool preserve_quotes) : _cond(f
cur_token_start = i + 1; // Eat the leading quote
} else if ((state == PARSER_IN_QUOTE) && extracting_token) {
cur_token_length = i - cur_token_start;
- if (preserve_quotes) {
- _tokens.push_back(line.substr(cur_token_start - 1, i - cur_token_start + 2));
- } else {
- _tokens.push_back(line.substr(cur_token_start, cur_token_length));
- }
+ _tokens.push_back(line.substr(cur_token_start, cur_token_length));
state = PARSER_DEFAULT;
extracting_token = false;
} else {
@@ -99,7 +94,7 @@ Parser::Parser(const std::string &original_line, bool preserve_quotes) : _cond(f
break;
}
- if ((line[i] == '=') || (line[i] == '>') || (line[i] == '<') || (line[i] == '+')) {
+ if ((line[i] == '=') || (line[i] == '+')) {
// These are always a seperate token
_tokens.push_back(std::string(1, line[i]));
continue;
@@ -202,7 +197,7 @@ Parser::preprocess(std::vector<std::string> tokens)
}
} else {
// Syntax error
- TSError("[%s] mods have to be embraced in []", PLUGIN_NAME);
+ TSError("[%s] mods have to be enclosed in []", PLUGIN_NAME);
return;
}
}
@@ -251,3 +246,57 @@ Parser::get_tokens() const
{
return _tokens;
}
+
+SimpleTokenizer::SimpleTokenizer(const std::string &original_line)
+{
+ std::string line = original_line;
+ ParserState state = PARSER_DEFAULT;
+ bool extracting_token = false;
+ off_t cur_token_start = 0;
+ size_t cur_token_length = 0;
+
+ for (size_t i = 0; i < line.size(); ++i) {
+ extracting_token = true;
+ switch (state) {
+ case PARSER_DEFAULT:
+ if ((line[i] == '{') || (line[i] == '<')) {
+ if (line[i - 1] == '%') {
+ // pickup what we currently have
+ cur_token_length = i - cur_token_start - 1;
+ if (cur_token_length > 0) {
+ _tokens.push_back(line.substr(cur_token_start, cur_token_length));
+ }
+
+ cur_token_start = i - 1;
+ state = PARSER_IN_EXPANSION;
+ extracting_token = false;
+ }
+ }
+ break;
+ case PARSER_IN_EXPANSION:
+ if ((line[i] == '}') || (line[i] == '>')) {
+ cur_token_length = i - cur_token_start + 1;
+ if (cur_token_length > 0) {
+ _tokens.push_back(line.substr(cur_token_start, cur_token_length));
+ }
+ cur_token_start = i + 1;
+ state = PARSER_DEFAULT;
+ extracting_token = false;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ // take what was left behind
+ if (extracting_token) {
+ _tokens.push_back(line.substr(cur_token_start));
+ }
+}
+
+const std::vector<std::string> &
+SimpleTokenizer::get_tokens() const
+{
+ return _tokens;
+}
diff --git a/plugins/header_rewrite/parser.h b/plugins/header_rewrite/parser.h
index ce167fd..8ea4c30 100644
--- a/plugins/header_rewrite/parser.h
+++ b/plugins/header_rewrite/parser.h
@@ -33,7 +33,7 @@
class Parser
{
public:
- explicit Parser(const std::string &line, bool preserve_quotes = false);
+ explicit Parser(const std::string &line);
bool
empty() const
@@ -88,3 +88,17 @@ private:
protected:
std::vector<std::string> _tokens;
};
+
+class SimpleTokenizer
+{
+public:
+ explicit SimpleTokenizer(const std::string &line);
+
+ const std::vector<std::string> &get_tokens() const;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(SimpleTokenizer);
+
+protected:
+ std::vector<std::string> _tokens;
+};
diff --git a/plugins/header_rewrite/regex_helper.cc b/plugins/header_rewrite/regex_helper.cc
index c07d117..8b30361 100644
--- a/plugins/header_rewrite/regex_helper.cc
+++ b/plugins/header_rewrite/regex_helper.cc
@@ -40,18 +40,6 @@ regexHelper::setRegexMatch(const std::string &s)
return true;
}
-const std::string &
-regexHelper::getRegexString() const
-{
- return regexString;
-}
-
-int
-regexHelper::getRegexCcount() const
-{
- return regexCcount;
-}
-
int
regexHelper::regexMatch(const char *str, int len, int ovector[]) const
{
diff --git a/plugins/header_rewrite/regex_helper.h b/plugins/header_rewrite/regex_helper.h
index 0b88f11..ed00ac7 100644
--- a/plugins/header_rewrite/regex_helper.h
+++ b/plugins/header_rewrite/regex_helper.h
@@ -40,8 +40,6 @@ public:
}
bool setRegexMatch(const std::string &s);
- const std::string &getRegexString() const;
- int getRegexCcount() const;
int regexMatch(const char *, int, int ovector[]) const;
private:
diff --git a/plugins/header_rewrite/value.cc b/plugins/header_rewrite/value.cc
index ef15e43..bd664c6 100644
--- a/plugins/header_rewrite/value.cc
+++ b/plugins/header_rewrite/value.cc
@@ -43,26 +43,26 @@ Value::set_value(const std::string &val)
{
_value = val;
- if (_value.find("%{") != std::string::npos || _value.find("%<") != std::string::npos || _value.find("\"") != std::string::npos) {
- Parser parser(_value);
- auto tokens = parser.get_tokens();
+ if (_value.find("%{") != std::string::npos || _value.find("%<") != std::string::npos) {
+ SimpleTokenizer tokenizer(_value);
+
+ auto tokens = tokenizer.get_tokens();
for (auto it = tokens.begin(); it != tokens.end(); it++) {
- Parser tparser(*it);
+ std::string token = *it;
Condition *tcond_val = nullptr;
- if ((*it).substr(0, 2) == "%<") {
+ if (token.substr(0, 2) == "%<") {
tcond_val = new ConditionExpandableString(*it);
- } else if ((*it) == "+") {
- // Skip concat token
- continue;
- } else {
- tcond_val = condition_factory(tparser.get_op());
+ } else if (token.substr(0, 2) == "%{") {
+ std::string cond_token = token.substr(2, token.size() - 3);
+ tcond_val = condition_factory(cond_token);
+ }
- if (tcond_val) {
- tcond_val->initialize(tparser);
- } else {
- tcond_val = new ConditionStringLiteral(*it);
- }
+ if (tcond_val) {
+ Parser parser(_value);
+ tcond_val->initialize(parser);
+ } else {
+ tcond_val = new ConditionStringLiteral(token);
}
_cond_vals.push_back(tcond_val);
}