ezelkow1 commented on code in PR #13776:
URL: https://github.com/apache/trafficserver/pull/13776#discussion_r4162909295
##########
plugins/compress/compress.cc:
##########
@@ -811,6 +816,190 @@ add_vary_header_to_client_response(TSHttpTxn txnp)
TSHandleMLocRelease(resp_buf, TS_NULL_MLOC, resp_loc);
}
+// A 304 carries the origin's strong ETag, which the cache would merge over
the weakened ETag of a
+// stored compressed copy. Keep it weak when both name the same entity and the
stored copy is
+// encoded; an identity copy's ETag is the origin's own, so it may
legitimately become strong.
+static void
+keep_cached_etag_weak(TSHttpTxn txnp)
+{
+ TSMBuffer srv_buf;
+ TSMLoc srv_loc;
+
+ if (TS_SUCCESS != TSHttpTxnServerRespGet(txnp, &srv_buf, &srv_loc)) {
+ return;
+ }
+ ts::PostScript srv_defer([&]() -> void { TSHandleMLocRelease(srv_buf,
TS_NULL_MLOC, srv_loc); });
+
+ if (TSHttpHdrStatusGet(srv_buf, srv_loc) != TS_HTTP_STATUS_NOT_MODIFIED) {
+ return;
+ }
+
+ TSMBuffer cached_buf;
+ TSMLoc cached_loc;
+
+ if (TS_SUCCESS != TSHttpTxnCachedRespGet(txnp, &cached_buf, &cached_loc)) {
+ return;
+ }
+ ts::PostScript cached_defer([&]() -> void { TSHandleMLocRelease(cached_buf,
TS_NULL_MLOC, cached_loc); });
+
+ TSMLoc cached_ce = TSMimeHdrFieldFind(cached_buf, cached_loc,
TS_MIME_FIELD_CONTENT_ENCODING, TS_MIME_LEN_CONTENT_ENCODING);
+
+ if (cached_ce == TS_NULL_MLOC) {
+ return;
+ }
+ TSHandleMLocRelease(cached_buf, cached_loc, cached_ce);
+
+ TSMLoc srv_etag = TSMimeHdrFieldFind(srv_buf, srv_loc, TS_MIME_FIELD_ETAG,
TS_MIME_LEN_ETAG);
+
+ if (srv_etag == TS_NULL_MLOC) {
+ return;
+ }
+ ts::PostScript srv_etag_defer([&]() -> void { TSHandleMLocRelease(srv_buf,
srv_loc, srv_etag); });
+
+ TSMLoc cached_etag = TSMimeHdrFieldFind(cached_buf, cached_loc,
TS_MIME_FIELD_ETAG, TS_MIME_LEN_ETAG);
+
+ if (cached_etag == TS_NULL_MLOC) {
+ return;
+ }
+ ts::PostScript cached_etag_defer([&]() -> void {
TSHandleMLocRelease(cached_buf, cached_loc, cached_etag); });
+
+ int srv_len;
+ const char *srv_str = TSMimeHdrFieldValueStringGet(srv_buf, srv_loc,
srv_etag, -1, &srv_len);
+ int cached_len;
+ const char *cached_str = TSMimeHdrFieldValueStringGet(cached_buf,
cached_loc, cached_etag, -1, &cached_len);
+ std::string_view srv_value{srv_str, static_cast<size_t>(srv_len)};
+ std::string_view cached_value{cached_str, static_cast<size_t>(cached_len)};
+
+ if (cached_value.starts_with("W/") && cached_value.substr(2) == srv_value) {
+ TSMimeHdrFieldValueStringSet(srv_buf, srv_loc, srv_etag, -1,
cached_value.data(), cached_value.size());
+ }
+}
+
+// No transform runs on a bodyless 304, so it goes out with the origin's or
the cached identity
+// copy's strong ETag. A 304 must carry the ETag its 200 would (RFC 9110
15.4.5), and this
+// request's 200 would have been compressed, so weaken it to match.
+static void
+weaken_client_not_modified_etag(TSHttpTxn txnp)
+{
+ TSMBuffer resp_buf;
+ TSMLoc resp_loc;
+
+ if (TS_SUCCESS != TSHttpTxnClientRespGet(txnp, &resp_buf, &resp_loc)) {
+ return;
+ }
+ ts::PostScript resp_defer([&]() -> void { TSHandleMLocRelease(resp_buf,
TS_NULL_MLOC, resp_loc); });
+
+ if (TSHttpHdrStatusGet(resp_buf, resp_loc) == TS_HTTP_STATUS_NOT_MODIFIED) {
+ etag_header(resp_buf, resp_loc);
+ }
+}
+
+static int
+not_modified_etag_plugin(TSCont contp, TSEvent event, void *edata)
+{
+ TSHttpTxn txnp = static_cast<TSHttpTxn>(edata);
+
+ switch (event) {
+ case TS_EVENT_HTTP_SEND_RESPONSE_HDR:
+ weaken_client_not_modified_etag(txnp);
+ break;
+
+ case TS_EVENT_HTTP_TXN_CLOSE:
+ TSContDestroy(contp);
+ break;
+
+ default:
+ fatal("compress 304 ETag unknown event");
+ }
+
+ TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
+
+ return 0;
+}
+
+// With nothing stored, an origin 304 has no representation to judge it by. It
does say the
+// representation is unchanged, so if this request qualifies for compression
by the same rules a 200
+// would, and the client holds the weak form of the origin's strong ETag (a
copy this plugin
+// compressed), answer with the tag the client holds.
+static void
+weaken_unjudged_origin_not_modified(TSHttpTxn txnp, HostConfiguration *hc)
+{
+ TSMBuffer srv_buf;
+ TSMLoc srv_loc;
+
+ if (TS_SUCCESS != TSHttpTxnServerRespGet(txnp, &srv_buf, &srv_loc)) {
+ return;
+ }
+ ts::PostScript srv_defer([&]() -> void { TSHandleMLocRelease(srv_buf,
TS_NULL_MLOC, srv_loc); });
+
+ if (TSHttpHdrStatusGet(srv_buf, srv_loc) != TS_HTTP_STATUS_NOT_MODIFIED) {
+ return;
+ }
+
+ TSMBuffer cached_buf;
+ TSMLoc cached_loc;
+
+ if (TS_SUCCESS == TSHttpTxnCachedRespGet(txnp, &cached_buf, &cached_loc)) {
+ TSHandleMLocRelease(cached_buf, TS_NULL_MLOC, cached_loc);
+ return;
+ }
+
+ TSMBuffer req_buf;
+ TSMLoc req_loc;
+
+ if (TS_SUCCESS != TSHttpTxnClientReqGet(txnp, &req_buf, &req_loc)) {
+ return;
+ }
+ ts::PostScript req_defer([&]() -> void { TSHandleMLocRelease(req_buf,
TS_NULL_MLOC, req_loc); });
+
+ int compress_type = COMPRESSION_TYPE_DEFAULT;
+ int algorithms = ALGORITHM_DEFAULT;
+
+ if (!is_compressible_method(req_buf, req_loc) ||
!client_accepts_compression(txnp, true, hc, &compress_type, &algorithms)) {
Review Comment:
This is reachable only if the client already holds `W/"p1"` for a
non-compressible response. Through this plugin that can only happen if the
origin itself issued `W/"p1"` and later switched to a strong `"p1"` (or a
content type was removed from `compressible-content-type`): the plugin never
weakens an ETag for a response `transformable()` rejects. In that case the
weakened 304 matches the copy the client holds, which is unchanged, so it's
harmless. Keeping the origin's tag whenever compressibility can't be
established would instead give every compressed client on this path a strong
ETag it can't match its stored weak copy against (RFC 9111 ยง4.3.4), forcing
refetches. That's the trade-off listed under Known limitations. Added a
non-compressible direct-304 case that documents the current behavior.
--
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]