TS-2316: header_rewrite: added variable expansion support to add-header Submitted by: Thomas Jackson <[email protected]> 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/3f4e1c74 Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/3f4e1c74 Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/3f4e1c74 Branch: refs/heads/5.0.x Commit: 3f4e1c74527f5ecaed0b9f1d116ba29dd6c419f5 Parents: 236c52c Author: Alexey Ivanov <[email protected]> Authored: Mon Nov 4 20:29:19 2013 -0800 Committer: Alexey Ivanov <[email protected]> Committed: Sun Nov 10 18:07:53 2013 -0800 ---------------------------------------------------------------------- plugins/header_rewrite/operator.h | 137 +++++++++++++++++++++++++++++++ plugins/header_rewrite/operators.cc | 3 + 2 files changed, 140 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/trafficserver/blob/3f4e1c74/plugins/header_rewrite/operator.h ---------------------------------------------------------------------- diff --git a/plugins/header_rewrite/operator.h b/plugins/header_rewrite/operator.h index aba2f11..5c24925 100644 --- a/plugins/header_rewrite/operator.h +++ b/plugins/header_rewrite/operator.h @@ -29,6 +29,9 @@ #include "statement.h" #include "parser.h" +#include <iostream> +#include <arpa/inet.h> +#include <sstream> // Operator modifiers enum OperModifiers { @@ -94,4 +97,138 @@ private: }; +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 == "%<proto>") { + // 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 == "%<port>") { + // 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 == "%<chi>") { + // IP address of the client's host machine + resolved_variable = getIP(TSHttpTxnClientAddrGet(res.txnp)); + } else if (variable == "%<cqhl>") { + // 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 == "%<cqhm>") { + // 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 == "%<cquup>") { + // 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<const struct sockaddr_in *>(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<const struct sockaddr_in6 *>(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 http://git-wip-us.apache.org/repos/asf/trafficserver/blob/3f4e1c74/plugins/header_rewrite/operators.cc ---------------------------------------------------------------------- diff --git a/plugins/header_rewrite/operators.cc b/plugins/header_rewrite/operators.cc index 69c6bec..881e058 100644 --- a/plugins/header_rewrite/operators.cc +++ b/plugins/header_rewrite/operators.cc @@ -384,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?)
