TS-2316: header_rewrite: added cookie-based conditions Submitted by: Alexey Ivanov <aiva...@linkedin.com> Sponsored by: LinkedIn
Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/3d37f51d Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/3d37f51d Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/3d37f51d Branch: refs/heads/5.0.x Commit: 3d37f51d1b1be4222dbb33afd2692e4a6ab11de7 Parents: b79c907 Author: Alexey Ivanov <aiva...@linkedin.com> Authored: Tue Nov 5 12:55:10 2013 -0800 Committer: Alexey Ivanov <aiva...@linkedin.com> Committed: Sun Nov 10 18:07:53 2013 -0800 ---------------------------------------------------------------------- plugins/header_rewrite/conditions.cc | 65 +++++++++++++++++++++++++++++++ plugins/header_rewrite/conditions.h | 60 ++++++++++++++++++++++++++++ plugins/header_rewrite/factory.cc | 2 + 3 files changed, 127 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/trafficserver/blob/3d37f51d/plugins/header_rewrite/conditions.cc ---------------------------------------------------------------------- diff --git a/plugins/header_rewrite/conditions.cc b/plugins/header_rewrite/conditions.cc index fdbb309..25bbae6 100644 --- a/plugins/header_rewrite/conditions.cc +++ b/plugins/header_rewrite/conditions.cc @@ -385,3 +385,68 @@ ConditionDBM::eval(const Resources& res) return static_cast<const Matchers<std::string>*>(_matcher)->test(s); } + + +// ConditionCookie: request or response header +void ConditionCookie::initialize(Parser& p) +{ + Condition::initialize(p); + + Matchers<std::string>* match = new Matchers<std::string>(_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<const Matchers<std::string>*>(_matcher)->test(s); + TSDebug(PLUGIN_NAME, "Evaluating COOKIE(%s): %s: rval: %d", _qualifier.c_str(), s.c_str(), rval); + return rval; +} http://git-wip-us.apache.org/repos/asf/trafficserver/blob/3d37f51d/plugins/header_rewrite/conditions.h ---------------------------------------------------------------------- diff --git a/plugins/header_rewrite/conditions.h b/plugins/header_rewrite/conditions.h index 96d1db4..2f4d093 100644 --- a/plugins/header_rewrite/conditions.h +++ b/plugins/header_rewrite/conditions.h @@ -25,6 +25,7 @@ #include <string> #include <ts/ts.h> #include <boost/lexical_cast.hpp> +#include <cstring> #include "condition.h" #include "matcher.h" @@ -146,6 +147,65 @@ private: }; +// 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 { http://git-wip-us.apache.org/repos/asf/trafficserver/blob/3d37f51d/plugins/header_rewrite/factory.cc ---------------------------------------------------------------------- diff --git a/plugins/header_rewrite/factory.cc b/plugins/header_rewrite/factory.cc index 9af8f25..208d42a 100644 --- a/plugins/header_rewrite/factory.cc +++ b/plugins/header_rewrite/factory.cc @@ -89,6 +89,8 @@ 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") {