diff --git a/plugins/header_rewrite/README b/plugins/header_rewrite/README index 6b5f5356066..fba6693ae07 100644 --- a/plugins/header_rewrite/README +++ b/plugins/header_rewrite/README @@ -4,9 +4,6 @@ perform various header "rewrite" rules (operations) on a request or response. Currently, only one operation is supported, since we had to get this rolling asap. -Note that currently only static string "values" are supported. We'll add -advanced features to allow for expansions in a future release. - Using the plugin ---------------- @@ -28,7 +25,7 @@ during the origin response header parsing, using READ_RESPONSE_HDR_HOOK. Operators --------- -The following operators are available: +The following operators are available: rm-header header-name [flags] add-header header [flags] @@ -36,6 +33,7 @@ The following operators are available: set-status-reason [flags] set-config config [flags] no-op [flags] + counter counter-name [flags] The following operator(s) currently only works when instantiating the plugin as a remap plugin: @@ -60,6 +58,18 @@ Operator flags [L] Last rule, do not continue +Variable expansion +------------------ +Currntly only limited variable expansion is supported in add-header. Supported +substitutions include: + % Protocol + % Port + % Client IP + % Client request length + % Client HTTP method + % Client unmapped URI + + Conditions ---------- The conditions are used as qualifiers: The operators specified will @@ -71,8 +81,8 @@ only be evaluated if the condition(s) are met. cond %{TRUE} [flags] cond %{FALSE} [flags] cond %{HEADER:header-name} operand [flags] + cond %{COOKIE:cookie-name} operand [flags] cond %{CLIENT-HEADER:header-name} operand [flags] - cond %{METHOD} operand [flags] cond %{PROTOCOL} operand [flags] cond %{PORT} operand [flags] cond %{HOST} operand [flags] @@ -103,7 +113,7 @@ configuration, but being the default it is also optional. Condition flags --------------- - [NC] Not ase sensitive condition (when applicable) + [NC] Not case sensitive condition (when applicable) [AND] AND with next condition (default) [OR] OR with next condition [NOT] Invert this condition @@ -133,11 +143,12 @@ Examples -------- cond %{HEADER:X-Y-Foobar} -cond %{METHOD} =GET [OR] -cond %{METHOD} =POST +cond %{COOKIE:X-DC} =DC1 add-header X-Y-Fiefum %{HEADER:X-Y-Foobar} +add-header X-Forwarded-For % rm-header X-Y-Foobar rm-header Set-Cookie +counter plugin.header_rewrite.x-y-foobar-dc1 cond %{HEADER:X-Y-Foobar} "Some string" [AND,NC] @@ -164,13 +175,13 @@ Version 1.6.9 (10,17,11,cdoshi) - Support for PATH condition Version 1.6.8 (10/17/11,cdoshi) - - Replace the INKHttpHdrStatusSet with INKHttptxnSetHttpRetStatus + - Replace the INKHttpHdrStatusSet with INKHttptxnSetHttpRetStatus Version 1.6.7 (07/21/11, bcall) - [bug 4699620] - Removed some extra printf()'s Version 1.6.6 (cdoshi) - - when Host adder is added setHostChange will be called + - when Host adder is added setHostChange will be called Version 1.6.5 (cdoshi) - fix QSA for set-destination @@ -185,7 +196,7 @@ Version 1.6.2 (cdoshi) - Support for regex matcher Version 1.6.1 (09/15/10, leif) - - [bug 3985913] + - [bug 3985913] Version 1.6.0 (07/14/10, leif) - Added support for the timeout-out operator. diff --git a/plugins/header_rewrite/condition.cc b/plugins/header_rewrite/condition.cc index d7c05ebbb59..bcece21c8ec 100644 --- a/plugins/header_rewrite/condition.cc +++ b/plugins/header_rewrite/condition.cc @@ -30,20 +30,20 @@ parse_matcher_op(std::string& arg) { switch (arg[0]) { case '=': - arg.erase(0,1); + arg.erase(0, 1); return MATCH_EQUAL; break; case '<': - arg.erase(0,1); + arg.erase(0, 1); return MATCH_LESS_THEN; break; case '>': - arg.erase(0,1); + arg.erase(0, 1); return MATCH_GREATER_THEN; break; case '/': - arg.erase(0,1); - arg.erase(arg.length() -1 , arg.length()); + arg.erase(0, 1); + arg.erase(arg.length() - 1, arg.length()); return MATCH_REGULAR_EXPRESSION; break; default: diff --git a/plugins/header_rewrite/condition.h b/plugins/header_rewrite/condition.h index e832a87f7ba..a33786c9730 100644 --- a/plugins/header_rewrite/condition.h +++ b/plugins/header_rewrite/condition.h @@ -16,7 +16,7 @@ limitations under the License. */ ////////////////////////////////////////////////////////////////////////////////////////////// -// +// // Implement the classes for the various types of hash keys we support. // #ifndef __CONDITION_H__ diff --git a/plugins/header_rewrite/conditions.cc b/plugins/header_rewrite/conditions.cc index 6faac6fa6a3..25bbae6d304 100644 --- a/plugins/header_rewrite/conditions.cc +++ b/plugins/header_rewrite/conditions.cc @@ -46,21 +46,24 @@ ConditionStatus::initialize(Parser& p) void -ConditionStatus::initialize_hooks() { +ConditionStatus::initialize_hooks() +{ add_allowed_hook(TS_HTTP_READ_RESPONSE_HDR_HOOK); add_allowed_hook(TS_HTTP_SEND_RESPONSE_HDR_HOOK); } bool -ConditionStatus::eval(const Resources& res) { +ConditionStatus::eval(const Resources& res) +{ TSDebug(PLUGIN_NAME, "Evaluating STATUS()"); // TODO: It'd be nice to get the args here ... return static_cast*>(_matcher)->test(res.resp_status); } void -ConditionStatus::append_value(std::string& s, const Resources& res) { +ConditionStatus::append_value(std::string& s, const Resources& res) +{ s += boost::lexical_cast(res.resp_status); TSDebug(PLUGIN_NAME, "Appending STATUS(%d) to evaluation value -> %s", res.resp_status, s.c_str()); } @@ -86,7 +89,8 @@ ConditionRandom::initialize(Parser& p) bool -ConditionRandom::eval(const Resources& /* res ATS_UNUSED */) { +ConditionRandom::eval(const Resources& /* res ATS_UNUSED */) +{ TSDebug(PLUGIN_NAME, "Evaluating RANDOM(%d)", _max); return static_cast*>(_matcher)->test(rand_r(&_seed) % _max); } @@ -188,10 +192,10 @@ ConditionHeader::append_value(std::string& s, const Resources& res) field_loc = TSMimeHdrFieldFind(bufp, hdr_loc, _qualifier.c_str(), _qualifier.size()); TSDebug(PLUGIN_NAME, "Getting Header: %s, field_loc: %p", _qualifier.c_str(), field_loc); if (field_loc != NULL) { - value = TSMimeHdrFieldValueStringGet(res.bufp, res.hdr_loc, field_loc, 0, &len); + value = TSMimeHdrFieldValueStringGet(bufp, res.hdr_loc, field_loc, 0, &len); TSDebug(PLUGIN_NAME, "Appending HEADER(%s) to evaluation value -> %.*s", _qualifier.c_str(), len, value); s.append(value, len); - TSHandleMLocRelease(res.bufp, res.hdr_loc, field_loc); + TSHandleMLocRelease(bufp, res.hdr_loc, field_loc); } } } @@ -220,13 +224,19 @@ ConditionPath::initialize(Parser& p) _matcher = match; } -void -ConditionPath::append_value(std::string& s, const Resources& res) -{ - int path_len = 0; - const char *path = TSUrlPathGet(res._rri->requestBufp, res._rri->requestUrl, &path_len); - TSDebug(PLUGIN_NAME, "Appending PATH to evaluation value: %.*s", path_len, path); - s.append(path, path_len); +void ConditionPath::append_value(std::string& s, const Resources& res) { + TSMBuffer bufp; + TSMLoc url_loc; + + if (TSHttpTxnPristineUrlGet(res.txnp, &bufp, &url_loc) == TS_SUCCESS) { + int path_length; + const char *path = TSUrlPathGet(bufp, url_loc, &path_length); + + if (path && path_length) + s.append(path, path_length); + + TSHandleMLocRelease(bufp, TS_NULL_MLOC, url_loc); + } } bool @@ -288,7 +298,8 @@ ConditionUrl::initialize(Parser& /* p ATS_UNUSED */) void -ConditionUrl::set_qualifier(const std::string& q) { +ConditionUrl::set_qualifier(const std::string& q) +{ Condition::set_qualifier(q); _url_qual = parse_url_qualifier(q); @@ -374,3 +385,68 @@ ConditionDBM::eval(const Resources& res) return static_cast*>(_matcher)->test(s); } + + +// ConditionCookie: request or response header +void ConditionCookie::initialize(Parser& p) +{ + Condition::initialize(p); + + Matchers* match = new Matchers(_cond_op); + match->set(p.get_arg()); + + _matcher = match; + + require_resources(RSRC_CLIENT_REQUEST_HEADERS); +} + +void ConditionCookie::append_value(std::string& s, const Resources& res) +{ + TSMBuffer bufp = res.client_bufp; + TSMLoc hdr_loc = res.client_hdr_loc; + TSMLoc field_loc; + int error; + int cookies_len; + int cookie_value_len; + const char *cookies; + const char *cookie_value; + const char * const cookie_name = _qualifier.c_str(); + const int cookie_name_len = _qualifier.length(); + + // Sanity + if (bufp == NULL || hdr_loc == NULL) + return; + + // Find Cookie + field_loc = TSMimeHdrFieldFind(bufp, hdr_loc, TS_MIME_FIELD_COOKIE, TS_MIME_LEN_COOKIE); + if (field_loc == NULL) + return; + + // Get all cookies + // NB! Cookie field does not support commas, so we use index == 0 + cookies = TSMimeHdrFieldValueStringGet(bufp, hdr_loc, field_loc, 0, &cookies_len); + if (cookies == NULL || cookies_len <= 0) + goto out_release_field; + + // Find particular cookie's value + error = get_cookie_value(cookies, cookies_len, cookie_name, cookie_name_len, &cookie_value, &cookie_value_len); + if (error == TS_ERROR) + goto out_release_field; + + TSDebug(PLUGIN_NAME, "Appending COOKIE(%s) to evaluation value -> %.*s", cookie_name, cookie_value_len, cookie_value); + s.append(cookie_value, cookie_value_len); + + // Unwind +out_release_field: + TSHandleMLocRelease(bufp, hdr_loc, field_loc); +} + +bool ConditionCookie::eval(const Resources& res) +{ + std::string s; + + append_value(s, res); + bool rval = static_cast*>(_matcher)->test(s); + TSDebug(PLUGIN_NAME, "Evaluating COOKIE(%s): %s: rval: %d", _qualifier.c_str(), s.c_str(), rval); + return rval; +} diff --git a/plugins/header_rewrite/conditions.h b/plugins/header_rewrite/conditions.h index 904533d2181..2f4d09331b5 100644 --- a/plugins/header_rewrite/conditions.h +++ b/plugins/header_rewrite/conditions.h @@ -16,7 +16,7 @@ limitations under the License. */ ////////////////////////////////////////////////////////////////////////////////////////////// -// +// // Declarations for all conditionals / conditional values we support. // #ifndef __CONDITIONS_H__ @@ -25,6 +25,7 @@ #include #include #include +#include #include "condition.h" #include "matcher.h" @@ -146,6 +147,65 @@ class ConditionAccess : public Condition }; +// cookie(name) +class ConditionCookie: public Condition +{ +public: + ConditionCookie() + { + TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for ConditionCookie"); + } + void initialize(Parser& p); + void append_value(std::string& s, const Resources& res); + +protected: + bool eval(const Resources& res); + +private: + DISALLOW_COPY_AND_ASSIGN(ConditionCookie); + + // Nginx-style cookie parsing: + // nginx/src/http/ngx_http_parse.c:ngx_http_parse_multi_header_lines() + inline int + get_cookie_value(const char *buf, int buf_len, const char *name, int name_len, + const char **value, int *value_len) + { + const char *start, *last, *end; + + // Sanity + if (buf == NULL || name == NULL || value == NULL || value_len == NULL) + return TS_ERROR; + + start = buf; + end = buf + buf_len; + + while (start < end) { + if (strncasecmp(start, name, name_len) != 0) + goto skip; + + for (start += name_len; start < end && *start == ' '; start++); + + if (start == end || *start++ != '=') + goto skip; + + while (start < end && *start == ' ') { start++; } + for (last = start; last < end && *last != ';'; last++); + + *value_len = last - start; + *value = start; + return TS_SUCCESS; +skip: + while (start < end) { + char ch = *start++; + if (ch == ';' || ch == ',') + break; + } + while (start < end && *start == ' ') { start++; } + } + return TS_ERROR; + }; +}; + // header class ConditionHeader : public Condition { @@ -168,7 +228,7 @@ class ConditionHeader : public Condition bool _client; }; -// path +// path class ConditionPath : public Condition { public: @@ -188,19 +248,7 @@ class ConditionPath : public Condition }; - - - - - - - - - - - - - +// query class ConditionQuery : public Condition { public: @@ -251,7 +299,7 @@ class ConditionDBM : public Condition { public: ConditionDBM() - : + : //_dbm(NULL), _file("") { diff --git a/plugins/header_rewrite/factory.cc b/plugins/header_rewrite/factory.cc index d7f0d6d01cd..208d42a8a09 100644 --- a/plugins/header_rewrite/factory.cc +++ b/plugins/header_rewrite/factory.cc @@ -53,8 +53,10 @@ operator_factory(const std::string& op) o = new OperatorSetTimeoutOut(); } else if (op == "no-op") { o = new OperatorNoOp(); + } else if (op == "counter") { + o = new OperatorCounter(); } else { - TSError("%s:unknown operator in header_rewrite: %s", PLUGIN_NAME, op.c_str()); + TSError("%s: unknown operator: %s", PLUGIN_NAME, op.c_str()); return NULL; } @@ -87,22 +89,24 @@ condition_factory(const std::string& cond) c = new ConditionRandom(); } else if (c_name == "ACCESS") { c = new ConditionAccess(); + } else if (c_name == "COOKIE") { + c = new ConditionCookie(); } else if (c_name == "HEADER") { // This condition adapts to the hook c = new ConditionHeader(); - }else if (c_name == "PATH"){ - c= new ConditionPath(); + } else if (c_name == "PATH") { + c = new ConditionPath(); } else if (c_name == "CLIENT-HEADER") { c = new ConditionHeader(true); - } else if (c_name == "QUERY") { - c = new ConditionQuery(); - } else if (c_name == "URL") { // This condition adapts to the hook + } else if (c_name == "QUERY") { + c = new ConditionQuery(); + } else if (c_name == "URL") { // This condition adapts to the hook c = new ConditionUrl(); } else if (c_name == "CLIENT-URL") { c = new ConditionUrl(true); } else if (c_name == "DBM") { c = new ConditionDBM(); } else { - TSError("%s: unknown condition in header_rewrite: %s", PLUGIN_NAME, c_name.c_str()); + TSError("%s: unknown condition: %s", PLUGIN_NAME, c_name.c_str()); return NULL; } diff --git a/plugins/header_rewrite/factory.h b/plugins/header_rewrite/factory.h index d10280a100b..e22944937db 100644 --- a/plugins/header_rewrite/factory.h +++ b/plugins/header_rewrite/factory.h @@ -16,7 +16,7 @@ limitations under the License. */ ////////////////////////////////////////////////////////////////////////////////////////////// -// +// // Implement the classes for the various types of hash keys we support. // #ifndef __FACTORY_H__ diff --git a/plugins/header_rewrite/lulu.h b/plugins/header_rewrite/lulu.h index 99876ec600f..0dd3cb1cfb0 100644 --- a/plugins/header_rewrite/lulu.h +++ b/plugins/header_rewrite/lulu.h @@ -16,7 +16,7 @@ limitations under the License. */ ////////////////////////////////////////////////////////////////////////////////////////////// -// +// // Implement the classes for the various types of hash keys we support. // #ifndef __LULU_H__ diff --git a/plugins/header_rewrite/matcher.h b/plugins/header_rewrite/matcher.h index d9648c818af..29906a99a4b 100644 --- a/plugins/header_rewrite/matcher.h +++ b/plugins/header_rewrite/matcher.h @@ -16,7 +16,7 @@ limitations under the License. */ ////////////////////////////////////////////////////////////////////////////////////////////// -// +// // Implement the classes for the various types of hash keys we support. // #ifndef __MATCHER_H__ @@ -51,7 +51,8 @@ class Matcher TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for Matcher"); } - virtual ~Matcher() { + virtual ~Matcher() + { TSDebug(PLUGIN_NAME_DBG, "Calling DTOR for Matcher"); free_pdata(); } @@ -79,7 +80,7 @@ class Matchers : public Matcher // Getters / setters const T get() const { return _data; }; - + void setRegex(const std::string /* data ATS_UNUSED */) { if (!helper.setRegexMatch(_data)) { @@ -93,7 +94,7 @@ class Matchers : public Matcher void setRegex(const TSHttpStatus /* t ATS_UNUSED */) { return; } void set (const T d) - { + { _data = d; if(_op == MATCH_REGULAR_EXPRESSION) setRegex(d); @@ -124,30 +125,36 @@ class Matchers : public Matcher private: // For basic types - bool test_eq(const T t) const { + bool test_eq(const T t) const + { // std::cout << "Testing: " << t << " == " << _data << std::endl; return t == _data; } - bool test_lt(const T t) const { + bool test_lt(const T t) const + { // std::cout << "Testing: " << t << " < " << _data << std::endl; return t < _data; } - bool test_gt(const T t) const { + bool test_gt(const T t) const + { // std::cout << "Testing: " << t << " > " << _data << std::endl; return t > _data; } - bool test_reg(const unsigned int /* t ATS_UNUSED */) const { + bool test_reg(const unsigned int /* t ATS_UNUSED */) const + { // Not supported return false; } - bool test_reg(const TSHttpStatus /* t ATS_UNUSED */) const { + bool test_reg(const TSHttpStatus /* t ATS_UNUSED */) const + { // Not supported return false; } - - bool test_reg(const std::string t) const { + + bool test_reg(const std::string t) const + { TSDebug(PLUGIN_NAME, "Test regular expression %s : %s", _data.c_str(), t.c_str()); int ovector[OVECCOUNT]; if (helper.regexMatch(t.c_str(), t.length(), ovector) > 0) { diff --git a/plugins/header_rewrite/operator.cc b/plugins/header_rewrite/operator.cc index 77adbfd5ecf..4297c93f688 100644 --- a/plugins/header_rewrite/operator.cc +++ b/plugins/header_rewrite/operator.cc @@ -24,7 +24,8 @@ #include "operator.h" const OperModifiers -Operator::get_oper_modifiers() const { +Operator::get_oper_modifiers() const +{ if (_next) return static_cast(_mods | static_cast(_next)->get_oper_modifiers()); @@ -32,7 +33,8 @@ Operator::get_oper_modifiers() const { } void -Operator::initialize(Parser& p) { +Operator::initialize(Parser& p) +{ Statement::initialize(p); if (p.mod_exist("L")) { @@ -46,7 +48,8 @@ Operator::initialize(Parser& p) { } void -OperatorHeaders::initialize(Parser& p) { +OperatorHeaders::initialize(Parser& p) +{ Operator::initialize(p); _header = p.get_arg(); diff --git a/plugins/header_rewrite/operator.h b/plugins/header_rewrite/operator.h index 6ef2e7382d8..5c24925b939 100644 --- a/plugins/header_rewrite/operator.h +++ b/plugins/header_rewrite/operator.h @@ -29,13 +29,16 @@ #include "statement.h" #include "parser.h" +#include +#include +#include // Operator modifiers enum OperModifiers { OPER_NONE = 0, OPER_LAST = 1, OPER_NEXT = 2, - OPER_QSA=4 + OPER_QSA = 4 }; @@ -94,4 +97,138 @@ class OperatorHeaders : public Operator }; +class VariableExpander { +private: + std::string _source; +public: + VariableExpander(const std::string &source) : + _source(source) { + } + + std::string expand(const Resources& res) { + std::string result; + result.reserve(512); // TODO: Can be optimized + result.assign(_source); + + while (true) { + std::string::size_type start = result.find("%<"); + if (start == std::string::npos) + break; + + std::string::size_type end = result.find(">", start); + if (end == std::string::npos) + break; + + std::string first_part = result.substr(0, start); + std::string last_part = result.substr(end + 1); + + // Now evaluate the variable + std::string variable = result.substr(start, end - start + 1); + + // This will be the value to replace the "variable" section of the string with + std::string resolved_variable = ""; + + // Initialize some stuff + TSMBuffer bufp; + TSMLoc hdr_loc; + TSMLoc url_loc; + + if (variable == "%") { + // Protocol of the incoming request + if (TSHttpTxnPristineUrlGet(res.txnp, &bufp, &url_loc) == TS_SUCCESS) { + int len; + resolved_variable = TSUrlSchemeGet(bufp, url_loc, &len); + } + } else if (variable == "%") { + // Original port of the incoming request + if (TSHttpTxnClientReqGet(res.txnp, &bufp, &hdr_loc) == TS_SUCCESS) { + if (TSHttpHdrUrlGet(bufp, hdr_loc, &url_loc) == TS_SUCCESS) { + std::stringstream out; + out << TSUrlPortGet(bufp, url_loc); + resolved_variable = out.str(); + TSHandleMLocRelease(bufp, hdr_loc, url_loc); + } + TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); + } + } else if (variable == "%") { + // IP address of the client's host machine + resolved_variable = getIP(TSHttpTxnClientAddrGet(res.txnp)); + } else if (variable == "%") { + // The client request header length; the header length in the client request to Traffic Server. + std::stringstream out; + out << TSHttpHdrLengthGet(res.client_bufp, res.client_hdr_loc); + resolved_variable = out.str(); + } else if (variable == "%") { + // The HTTP method in the client request to Traffic Server: GET, POST, and so on (subset of cqtx). + int method_len; + const char *methodp = TSHttpHdrMethodGet(res.client_bufp, res.client_hdr_loc, &method_len); + if (methodp && method_len) { + resolved_variable.assign(methodp, method_len); + } + } else if (variable == "%") { + // The client request unmapped URL path. This field records a URL path + // before it is remapped (reverse proxy mode). + if (TSHttpTxnPristineUrlGet(res.txnp, &bufp, &url_loc) == TS_SUCCESS) { + int path_len; + const char *path = TSUrlPathGet(bufp, url_loc, &path_len); + + if (path && path_len) { + resolved_variable.assign(path, path_len); + } + TSHandleMLocRelease(bufp, TS_NULL_MLOC, url_loc); + } + } + + // TODO(SaveTheRbtz): Can be optimized + result.assign(first_part); + result.append(resolved_variable); + result.append(last_part); + } + + return result; + } + +private: + std::string getIP(sockaddr const * s_sockaddr) { + const struct sockaddr_in *s_sockaddr_in; + const struct sockaddr_in6 *s_sockaddr_in6; + + if (s_sockaddr == NULL) + return ""; + + char res[INET6_ADDRSTRLEN] = { '\0' }; + + switch (s_sockaddr->sa_family) { + case AF_INET: + s_sockaddr_in = reinterpret_cast(s_sockaddr); + inet_ntop(s_sockaddr_in->sin_family, &s_sockaddr_in->sin_addr, res, INET_ADDRSTRLEN); + break; + case AF_INET6: + s_sockaddr_in6 = reinterpret_cast(s_sockaddr); + inet_ntop(s_sockaddr_in6->sin6_family, &s_sockaddr_in6->sin6_addr, res, INET6_ADDRSTRLEN); + break; + } + + return std::string(res); + } + + std::string getURL(const Resources& res) { + TSMBuffer bufp; + TSMLoc url_loc; + + if (TSHttpTxnPristineUrlGet(res.txnp, &bufp, &url_loc) != TS_SUCCESS) + return ""; + + int url_len; + char *url = TSUrlStringGet(bufp, url_loc, &url_len); + std::string ret; + if (url && url_len) + ret.assign(url, url_len); + TSfree(url); + TSHandleMLocRelease(bufp, TS_NULL_MLOC, url_loc); + + return ret; + } +}; + #endif // __OPERATOR_H diff --git a/plugins/header_rewrite/operators.cc b/plugins/header_rewrite/operators.cc index 54ac221877b..f06b1d07ca1 100644 --- a/plugins/header_rewrite/operators.cc +++ b/plugins/header_rewrite/operators.cc @@ -27,7 +27,8 @@ // OperatorConfig void -OperatorSetConfig::initialize(Parser& p) { +OperatorSetConfig::initialize(Parser& p) +{ Operator::initialize(p); _config = p.get_arg(); @@ -121,13 +122,15 @@ OperatorSetStatusReason::initialize(Parser& p) void -OperatorSetStatusReason::initialize_hooks() { +OperatorSetStatusReason::initialize_hooks() +{ add_allowed_hook(TS_HTTP_READ_RESPONSE_HDR_HOOK); add_allowed_hook(TS_HTTP_SEND_RESPONSE_HDR_HOOK); } void -OperatorSetStatusReason::exec(const Resources& res) const { +OperatorSetStatusReason::exec(const Resources& res) const +{ if (res.bufp && res.hdr_loc) { std::string reason; @@ -255,10 +258,10 @@ OperatorSetRedirect::exec(const Resources& res) const std::string value; _location.append_value(value, res); - + // Replace %{PATH} to original path size_t pos_path = 0; - + if ((pos_path = value.find("%{PATH}")) != std::string::npos) { value.erase(pos_path, 7); // erase %{PATH} from the rewritten to url int path_len = 0; @@ -268,7 +271,7 @@ OperatorSetRedirect::exec(const Resources& res) const value.insert(pos_path, path, path_len); } } - + // Append the original query string int query_len = 0; const char *query = TSUrlHttpQueryGet(res._rri->requestBufp, res._rri->requestUrl, &query_len); @@ -284,10 +287,10 @@ OperatorSetRedirect::exec(const Resources& res) const const char *start = value.c_str(); const char *end = value.size() + start; TSUrlParse(res._rri->requestBufp, res._rri->requestUrl, &start, end); - TSDebug(PLUGIN_NAME, "OperatorSetRedirect::exec() invoked with destination=%s and status code=%d", + TSDebug(PLUGIN_NAME, "OperatorSetRedirect::exec() invoked with destination=%s and status code=%d", value.c_str(), _status.get_int_value()); } - + } else { // TODO: Handle the non-remap case here (InkAPI hooks) } @@ -381,6 +384,9 @@ OperatorAddHeader::exec(const Resources& res) const { std::string value; + VariableExpander ve(value); + value = ve.expand(res); + _value.append_value(value, res); // Never set an empty header (I don't think that ever makes sense?) @@ -460,3 +466,40 @@ OperatorSetHeader::exec(const Resources& res) const } } } + +// OperatorCounter +void +OperatorCounter::initialize(Parser& p) { + Operator::initialize(p); + + _counter_name = p.get_arg(); + + // Sanity + if (_counter_name.length() == 0) { + TSError("%s: counter name is empty", PLUGIN_NAME); + return; + } + + // Check if counter already created by another rule + if (TSStatFindName(_counter_name.c_str(), &_counter) == TS_ERROR) { + _counter = TSStatCreate(_counter_name.c_str(), TS_RECORDDATATYPE_INT, TS_STAT_NON_PERSISTENT, TS_STAT_SYNC_COUNT); + if (_counter == TS_ERROR) { + TSError("%s: TSStatCreate() failed. Can't create counter: %s", PLUGIN_NAME, _counter_name.c_str()); + return; + } + TSDebug(PLUGIN_NAME, "OperatorCounter::initialize(%s) created counter with id: %d", _counter_name.c_str(), _counter); + } else { + TSDebug(PLUGIN_NAME, "OperatorCounter::initialize(%s) reusing id: %d", _counter_name.c_str(), _counter); + } +} + +void +OperatorCounter::exec(const Resources& res) const +{ + // Sanity + if (_counter == TS_ERROR) + return; + + TSDebug(PLUGIN_NAME, "OperatorCounter::exec() invoked on counter %s", _counter_name.c_str()); + TSStatIntIncrement(_counter, 1); +} diff --git a/plugins/header_rewrite/operators.h b/plugins/header_rewrite/operators.h index 925b23ed32e..6ab67ffc423 100644 --- a/plugins/header_rewrite/operators.h +++ b/plugins/header_rewrite/operators.h @@ -16,7 +16,7 @@ limitations under the License. */ ////////////////////////////////////////////////////////////////////////////////////////////// -// +// // Implement the classes for the various types of hash keys we support. // #ifndef __OPERATORS_H__ @@ -240,5 +240,24 @@ class OperatorSetHeader : public OperatorHeaders Value _value; }; +class OperatorCounter : public Operator +{ +public: + OperatorCounter() + : _counter_name(""), _counter(TS_ERROR) + { + TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for OperatorCounter"); + } + void initialize(Parser& p); + +protected: + void exec(const Resources& res) const; + +private: + DISALLOW_COPY_AND_ASSIGN(OperatorCounter); + + std::string _counter_name; + int _counter; +}; #endif // __OPERATORS_H diff --git a/plugins/header_rewrite/parser.h b/plugins/header_rewrite/parser.h index 0417fffcc45..65ff38a728f 100644 --- a/plugins/header_rewrite/parser.h +++ b/plugins/header_rewrite/parser.h @@ -16,7 +16,7 @@ limitations under the License. */ ////////////////////////////////////////////////////////////////////////////////////////////// -// +// // Interface for the config line parser // #ifndef __PARSER_H__ diff --git a/plugins/header_rewrite/regex_helper.cc b/plugins/header_rewrite/regex_helper.cc index 4bfdb238fa8..bf3eaca25f4 100644 --- a/plugins/header_rewrite/regex_helper.cc +++ b/plugins/header_rewrite/regex_helper.cc @@ -18,7 +18,7 @@ #include "regex_helper.h" bool -regexHelper::setRegexMatch(const std::string& s) +regexHelper::setRegexMatch(const std::string& s) { const char* errorComp = NULL; @@ -28,12 +28,12 @@ regexHelper::setRegexMatch(const std::string& s) regexString = s; regex = pcre_compile(regexString.c_str(), 0, &errorComp, &erroffset, NULL); - if (regex == NULL) + if (regex == NULL) { return false; } regexExtra = pcre_study(regex, 0, &errorStudy); - if ((regexExtra == NULL) && (errorStudy != 0)) + if ((regexExtra == NULL) && (errorStudy != 0)) { return false; } @@ -43,13 +43,13 @@ regexHelper::setRegexMatch(const std::string& s) } const std::string& -regexHelper::getRegexString() const +regexHelper::getRegexString() const { return regexString; } int -regexHelper::getRegexCcount() const +regexHelper::getRegexCcount() const { return regexCcount; } diff --git a/plugins/header_rewrite/regex_helper.h b/plugins/header_rewrite/regex_helper.h index 5d5099ae5c0..7d24da4af5a 100644 --- a/plugins/header_rewrite/regex_helper.h +++ b/plugins/header_rewrite/regex_helper.h @@ -25,15 +25,16 @@ const int OVECCOUNT = 30; // We support $1 - $9 only, and this needs to be 3x that -class regexHelper{ +class regexHelper +{ public: regexHelper(): regex(NULL),regexExtra(NULL),regexCcount(0) { - + } - ~regexHelper() + ~regexHelper() { if (regex) pcre_free(regex); diff --git a/plugins/header_rewrite/resources.cc b/plugins/header_rewrite/resources.cc index c33dfbf198b..d89149a8ca1 100644 --- a/plugins/header_rewrite/resources.cc +++ b/plugins/header_rewrite/resources.cc @@ -97,8 +97,8 @@ Resources::gather(const ResourceIDs ids, TSHttpHookID hook) hdr_loc = client_hdr_loc; } break; - - + + default: break; } diff --git a/plugins/header_rewrite/resources.h b/plugins/header_rewrite/resources.h index d63b4e79320..cb9d062845a 100644 --- a/plugins/header_rewrite/resources.h +++ b/plugins/header_rewrite/resources.h @@ -16,7 +16,7 @@ limitations under the License. */ ////////////////////////////////////////////////////////////////////////////////////////////// -// +// // Implement the classes for the various types of hash keys we support. // #ifndef __RESOURCES_H__ diff --git a/plugins/header_rewrite/ruleset.cc b/plugins/header_rewrite/ruleset.cc index 4a32c8b8830..9c6bc06e0cd 100644 --- a/plugins/header_rewrite/ruleset.cc +++ b/plugins/header_rewrite/ruleset.cc @@ -29,7 +29,8 @@ // Class implementation (no reason to have these inline) // void -RuleSet::append(RuleSet* rule) { +RuleSet::append(RuleSet* rule) +{ RuleSet* tmp = this; TSReleaseAssert(rule->next == NULL); @@ -41,7 +42,8 @@ RuleSet::append(RuleSet* rule) { void -RuleSet::add_condition(Parser& p) { +RuleSet::add_condition(Parser& p) +{ Condition* c = condition_factory(p.get_op()); if (NULL != c) { @@ -65,7 +67,8 @@ RuleSet::add_condition(Parser& p) { void -RuleSet::add_operator(Parser& p) { +RuleSet::add_operator(Parser& p) +{ Operator* o = operator_factory(p.get_op()); if (NULL != o) { diff --git a/plugins/header_rewrite/ruleset.h b/plugins/header_rewrite/ruleset.h index b530b7f49e6..5197a9d6307 100644 --- a/plugins/header_rewrite/ruleset.h +++ b/plugins/header_rewrite/ruleset.h @@ -16,7 +16,7 @@ limitations under the License. */ ////////////////////////////////////////////////////////////////////////////////////////////// -// +// // Implement the classes for the various types of hash keys we support. // #ifndef __RULESET_H__ @@ -54,11 +54,13 @@ class RuleSet const TSHttpHookID get_hook() const { return _hook; } // Inline - const ResourceIDs get_all_resource_ids() const { + const ResourceIDs get_all_resource_ids() const + { return _ids; } - bool eval(const Resources& res) const { + bool eval(const Resources& res) const + { if (NULL == _cond) { return true; } else { @@ -66,11 +68,13 @@ class RuleSet } } - bool last() const { + bool last() const + { return _last; } - OperModifiers exec(const Resources& res) const { + OperModifiers exec(const Resources& res) const + { _oper->do_exec(res); return _opermods; } diff --git a/plugins/header_rewrite/statement.cc b/plugins/header_rewrite/statement.cc index a9053ff8e1e..1538f52a598 100644 --- a/plugins/header_rewrite/statement.cc +++ b/plugins/header_rewrite/statement.cc @@ -52,7 +52,8 @@ Statement::get_resource_ids() const bool -Statement::set_hook(TSHttpHookID hook) { +Statement::set_hook(TSHttpHookID hook) +{ bool ret = std::find(_allowed_hooks.begin(), _allowed_hooks.end(), hook) != _allowed_hooks.end(); if (ret) @@ -64,7 +65,8 @@ Statement::set_hook(TSHttpHookID hook) { // This should be overridden for any Statement which only supports some hooks void -Statement::initialize_hooks() { +Statement::initialize_hooks() +{ add_allowed_hook(TS_HTTP_READ_RESPONSE_HDR_HOOK); add_allowed_hook(TS_HTTP_READ_REQUEST_PRE_REMAP_HOOK); add_allowed_hook(TS_HTTP_READ_REQUEST_HDR_HOOK); @@ -76,7 +78,8 @@ Statement::initialize_hooks() { // Parse URL qualifiers UrlQualifiers -Statement::parse_url_qualifier(const std::string& q) { +Statement::parse_url_qualifier(const std::string& q) +{ UrlQualifiers qual = URL_QUAL_NONE; if (q == "HOST") diff --git a/plugins/header_rewrite/statement.h b/plugins/header_rewrite/statement.h index 15fdf1135ac..0db1eb231b7 100644 --- a/plugins/header_rewrite/statement.h +++ b/plugins/header_rewrite/statement.h @@ -16,7 +16,7 @@ limitations under the License. */ ////////////////////////////////////////////////////////////////////////////////////////////// -// +// // Base class for all Conditions and Operations. We share the "linked" list, and the // resource management / requirements. // diff --git a/plugins/header_rewrite/value.h b/plugins/header_rewrite/value.h index ef8c4011d5f..cbdd7f83dab 100644 --- a/plugins/header_rewrite/value.h +++ b/plugins/header_rewrite/value.h @@ -17,7 +17,7 @@ */ ////////////////////////////////////////////////////////////////////////////////////////////// // Public interface for creating all values. -// +// // #ifndef __VALUE_H__ #define __VALUE_H__ 1