bneradt commented on code in PR #13790:
URL: https://github.com/apache/trafficserver/pull/13790#discussion_r4197888826


##########
plugins/header_rewrite/operators.cc:
##########
@@ -532,6 +523,320 @@ OperatorRMDestination::exec(const Resources &res) const
   return true;
 }
 
+// OperatorSortDestination
+void
+OperatorSortDestination::initialize(Parser &p)
+{
+  Operator::initialize(p);
+
+  _url_qual = parse_url_qualifier(p.get_arg());
+
+  require_resources(RSRC_CLIENT_REQUEST_HEADERS);
+  require_resources(RSRC_SERVER_REQUEST_HEADERS);
+}
+
+bool
+OperatorSortDestination::exec(const Resources &res) const
+{
+  if (res._rri || (res.bufp && res.hdr_loc)) {
+    TSMBuffer bufp;
+    TSMLoc    url_m_loc;
+
+    // Determine which TSMBuffer and TSMLoc to use
+    if (res._rri && !res.changed_url) {
+      bufp      = res._rri->requestBufp;
+      url_m_loc = res._rri->requestUrl;
+    } else {
+      bufp = res.bufp;
+      if (TSHttpHdrUrlGet(res.bufp, res.hdr_loc, &url_m_loc) != TS_SUCCESS) {
+        Dbg(pi_dbg_ctl, "TSHttpHdrUrlGet was unable to return the url m_loc");
+        return true;
+      }
+    }
+
+    switch (_url_qual) {
+    case URL_QUAL_QUERY: {
+      int              q_len = 0;
+      const char      *q_ptr = TSUrlHttpQueryGet(bufp, url_m_loc, &q_len);
+      std::string_view query = q_len > 0 ? std::string_view(q_ptr, 
static_cast<size_t>(q_len)) : std::string_view();
+
+      if (is_query_sorted(query)) {
+        Dbg(pi_dbg_ctl, "OperatorSortDestination::exec() QUERY already sorted, 
leaving it unchanged");
+        break;
+      }
+
+      std::string sorted = sort_query(query);
+
+      if (TSUrlHttpQuerySet(bufp, url_m_loc, sorted.c_str(), sorted.size()) != 
TS_SUCCESS) {
+        Dbg(pi_dbg_ctl, "OperatorSortDestination::exec() unable to set QUERY");
+        break;
+      }
+      const_cast<Resources &>(res).changed_url = true;
+      res.reset_query_cache();
+      Dbg(pi_dbg_ctl, "OperatorSortDestination::exec() rewrote QUERY to 
\"%s\"", sorted.c_str());
+      break;
+    }
+    default:
+      Dbg(pi_dbg_ctl, "Sort destination %i has no handler", _url_qual);
+      break;
+    }
+  } else {
+    Dbg(pi_dbg_ctl, "OperatorSortDestination::exec() unable to continue due to 
missing bufp=%p or hdr_loc=%p, rri=%p!", res.bufp,
+        res.hdr_loc, res._rri);
+  }
+  return true;
+}
+
+// OperatorSetKey
+void
+OperatorSetKey::initialize(Parser &p)
+{
+  Operator::initialize(p);
+
+  _url_qual = parse_url_qualifier(p.get_arg());
+  switch (_url_qual) {
+  case URL_QUAL_HOST:
+  case URL_QUAL_PORT:
+  case URL_QUAL_PATH:
+  case URL_QUAL_QUERY:
+  case URL_QUAL_SCHEME:
+    break;
+  default:
+    throw std::runtime_error("set-cache-key accepts HOST, PORT, PATH, QUERY, 
or SCHEME, got: " + p.get_arg());
+  }
+
+  _value.set_value(p.get_value(), this);
+  require_resources(RSRC_CLIENT_REQUEST_HEADERS);
+}
+
+void
+OperatorSetKey::initialize_hooks()
+{
+  add_allowed_hook(TS_REMAP_PSEUDO_HOOK);
+  add_allowed_hook(TS_HTTP_POST_REMAP_HOOK);
+}
+
+bool
+OperatorSetKey::exec(const Resources &res) const
+{
+  if (!res.ensure_key_url()) {
+    Dbg(pi_dbg_ctl, "OperatorSetKey::exec() unable to create the cache URL");
+    return true;
+  }
+
+  UrlKeyState &key = res.cache_key;
+  std::string  value;
+
+  _value.append_value(value, res);
+
+  // Unlike set-destination, an empty value is applied: it clears the 
component.
+  switch (_url_qual) {
+  case URL_QUAL_HOST:
+    TSUrlHostSet(key.bufp, key.url_loc, value.data(), value.size());
+    break;
+  case URL_QUAL_PATH:
+    TSUrlPathSet(key.bufp, key.url_loc, value.data(), value.size());
+    break;
+  case URL_QUAL_QUERY:
+    TSUrlHttpQuerySet(key.bufp, key.url_loc, value.data(), value.size());
+    break;
+  case URL_QUAL_SCHEME:
+    TSUrlSchemeSet(key.bufp, key.url_loc, value.data(), value.size());
+    break;
+  case URL_QUAL_PORT: {
+    int port = 0;
+
+    if (!value.empty()) {
+      auto [end, ec] = std::from_chars(value.data(), value.data() + 
value.size(), port);
+
+      if (ec != std::errc() || end != value.data() + value.size() || port < 0 
|| port > 0xFFFF) {
+        Dbg(pi_dbg_ctl, "OperatorSetKey::exec() invalid PORT \"%s\", 
skipping", value.c_str());
+        return true;
+      }
+    }
+    TSUrlPortSet(key.bufp, key.url_loc, port);
+    break;
+  }
+  default:
+    return true;
+  }
+
+  key.active = true;
+  Dbg(pi_dbg_ctl, "OperatorSetKey::exec() set component %d to \"%s\"", 
_url_qual, value.c_str());
+  return true;
+}
+
+// OperatorAddKey
+void
+OperatorAddKey::initialize(Parser &p)
+{
+  Operator::initialize(p);
+
+  _value.set_value(p.get_arg(), this);
+  require_resources(RSRC_CLIENT_REQUEST_HEADERS);
+}
+
+void
+OperatorAddKey::initialize_hooks()
+{
+  add_allowed_hook(TS_REMAP_PSEUDO_HOOK);
+  add_allowed_hook(TS_HTTP_POST_REMAP_HOOK);
+}
+
+bool
+OperatorAddKey::exec(const Resources &res) const
+{
+  if (!res.ensure_key_url()) {
+    Dbg(pi_dbg_ctl, "OperatorAddKey::exec() unable to create the cache URL");
+    return true;
+  }
+
+  std::string value;
+
+  // An empty value still adds a segment, so segment i always holds the same 
input.
+  _value.append_value(value, res);
+  Dbg(pi_dbg_ctl, "OperatorAddKey::exec() adding segment \"%s\"", 
value.c_str());
+  res.cache_key.key_data.push_back(std::move(value));

Review Comment:
   [P2] Include queued segments in CACHE-URL reads
   
   This only updates key_data; ConditionUrl::append_value(CACHE) reads 
cache_key.url_loc, and the queued segments are not appended to that URL until 
finalize_key_ops() runs after all rules. With a base path p, `add-cache-key 
"en"` followed by `set-header X-Key "%{CACHE-URL:PATH}"` emits p even though 
the committed key has path p/en. A subsequent CACHE-URL:PATH condition can 
consequently skip the intended rule. This contradicts the documented promise 
that later CACHE-URL conditions see preceding cache-key edits. Please make 
PATH/full-URL reads project the pending segments (while preserving 
clear-cache-key semantics), and add replay coverage that reads and conditions 
on the key between add-cache-key and the hook's final commit.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to