bryancall opened a new pull request, #13704:
URL: https://github.com/apache/trafficserver/pull/13704

   ### The bug
   
   `BgFetchConfig::bgFetchAllowed()` decides whether a transaction is a range
   request by looking for a `Range` or conditional header. The lookup had a
   misplaced closing paren:
   
   ```cpp
   if (TSMimeHdrFieldFind(bufp, hdr_loc, header.data(), header.size() == 
TS_SUCCESS)) {
   ```
   
   `TSMimeHdrFieldFind()` returns a `TSMLoc`, not a `TSReturnCode`, so the
   `== TS_SUCCESS` belonged on the call rather than on the length argument.
   `TS_SUCCESS` is `0`, so `header.size() == TS_SUCCESS` evaluated to `false`,
   which converted to a length of `0`. The plugin was searching every request 
for
   a zero-length field name, which never matches.
   
   A zero-length name is not merely a lookup that misses. 
`mime_hdr_field_find()`
   asserts on it:
   
   ```
   Fatal: src/proxy/hdrs/MIME.cc:1224: failed assertion `!field_name.empty()`
   traffic_server: received signal 6 (Aborted)
   ```
   
   That is an `ink_assert`, which is compiled out in release builds, so the
   behaviour split by build type:
   
   - **debug builds abort** on the first request through a remap rule that sets
     either option
   - **release builds** carry on with `hasRangeHdrs` always `false`, leaving 
both
     options broken in opposite directions:
   
   | Option | Intended | Actual (release) |
   |---|---|---|
   | `--range-req-only=true` | background fill only for range requests | never 
filled, including for range requests |
   | `--cache-range-req=false` | suppress the fill for range requests | never 
suppressed anything |
   
   ### The fix
   
   Pass the name length and test the returned handle. Since the broken call 
could
   only ever return `TS_NULL_MLOC`, it never had a handle to release; now that 
the
   lookup can succeed, the field handle is released, as is the header handle 
from
   `TSHttpTxnClientReqGet()`. `TSMimeHdrFieldFind()`'s contract in `ts.h` asks 
for
   the former; the latter was already leaking on every call into this block.
   
   Also reject a `Content-Length` condition that carries no size value, the way
   `plugins/background_fetch` already does. Without it, `++cfg_value` leaves the
   view empty, `swoc::svtou()` sets `parsed` empty too, so the
   `parsed.size() != cfg_value.size()` guard compares `0 != 0`, passes, and a
   `<= 0` rule is installed from a config line that specified no size at all.
   
   ### Testing
   
   New autest `cache_fill_range_req_only`, driving both directions of the
   `--range-req-only=true` decision so that a fix which simply always filled 
would
   not pass:
   
   - a range request must fill the cache (second request is `hit-fresh` / `206`)
   - a plain request must not (stays a miss)
   
   Verified it discriminates, by rebuilding the plugin with the paren restored 
and
   re-running: the test fails, and the autest build aborts on the assertion 
above.
   With the fix, `cache_fill` and `cache_fill_range_req_only` both pass and no
   crash log is produced.
   
   The existing `cache_fill` gold test is unaffected, and that is itself the
   reason this survived: `_range_req_only` defaults to `false` and
   `_cache_range_req` to `true`, so `if (_range_req_only || !_cache_range_req)`
   is false under the default config and the whole block was never entered by 
any
   existing test.
   
   Neither of these was flagged by Coverity. They turned up while reading
   `plugins/background_fetch` and `plugins/experimental/cache_fill` side by 
side,
   which is worth doing on its own -- `cache_fill` was forked from
   `background_fetch` and the two have drifted.
   


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