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?)

Reply via email to