Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
357a4ca
add bypass header config option to maxmind_acl plugin (#13160)
traeak Jun 8, 2026
f5deb14
Clamp HTTP3 frame type buf size to reader bytes (#13242)
JosiahWI Jun 8, 2026
fafb8bd
slice: fix stpcpy off-by-one for header value extraction (#13181)
traeak Jun 9, 2026
08102c0
Move some directory helpers to `Directory` (#13245)
JosiahWI Jun 9, 2026
8fea504
Fix compilation under `LOOP_CHECK_MODE` (#13250)
JosiahWI Jun 10, 2026
7b5db79
authproxy: Release client request handle in StateAuthorized (#13258)
maskit Jun 11, 2026
6208545
Remove unused EThread members (#13268)
JosiahWI Jun 15, 2026
bdbea81
Fix tsapi build with ENABLE_PROBES=ON (#13276)
Clendenin Jun 16, 2026
c897a6f
Remove TsBuffer.h (#13281)
JosiahWI Jun 16, 2026
5e15f08
Fix txn_box unused find result (#13291)
bneradt Jun 18, 2026
0beee2c
Add unit tests for `Continuation` logic (#13283)
JosiahWI Jun 22, 2026
4454dc5
Add TSMutex lock guard (#13188)
bneradt Jun 23, 2026
a4666a6
redo_cache_lookup: move to examples; fix `fallback` lifetime (#13209)
bneradt Jun 23, 2026
d91895f
Update FastLZ to b1342da (#13230)
phongn Jun 23, 2026
2bdef3a
Use fixture listener in test_EventSystem (#13308)
JosiahWI Jun 23, 2026
56d477c
Downgrade inbound H2 stream error log (#13316)
bneradt Jun 25, 2026
48a18a0
Fix stale_response FORCE_SIE enum (#13326)
bneradt Jun 25, 2026
108f5ad
Clarify HttpSM cache action cleanup (#13327)
bneradt Jun 25, 2026
097879f
docs: add call condition note for TSUrlHostGet (#13313)
mmustafasenoglu Jul 6, 2026
e2633c5
Track remaining length while decoding qpack header block (#13361)
dxbjavid Jul 7, 2026
78e4961
jax_fingerprint: Reduce allocations and gate methods at build time (#…
maskit Jul 9, 2026
f5569b0
Fix CLFUS RAM cache value metric broken by integer division (#13233)
phongn Jul 13, 2026
da0e4d7
Improve testing and documentation for client firewall marks (#13383)
JosiahWI Jul 15, 2026
9523ffd
Generalize client packet mark test (#13384)
JosiahWI Jul 16, 2026
d34f7df
prefetch: admit --fetch-query requests only when the key is present (…
mlibbey Jul 18, 2026
50ae689
Improve testing and documentation for server firewall marks (#13385)
JosiahWI Jul 20, 2026
b4b9a7a
Avoid Diags lock for syslog output (#13398)
bneradt Jul 20, 2026
c09c61d
doc: fix Via decoder ring URL (/tools/via moved to /via.html) (#13399)
bryancall Jul 20, 2026
30e5bb7
Remove unused RemapProcessor.h include from RemapPlugins.h (#13403)
blurman-ai Jul 20, 2026
a306331
copy only len_in bytes in the escapify no-escape path (#13404)
dxbjavid Jul 20, 2026
968eeec
ssl: remove the dead SSL_HOOK_OP_TERMINATE op (#13407)
moonchen Jul 20, 2026
cc19b74
Document `HTTPHdr` methods for #13420 review (#13422)
JosiahWI Jul 23, 2026
d1cc4e2
Add unit tests for `Action` logic (#13332)
JosiahWI Jul 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions NOTICE
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ https://github.com/jbeder/yaml-cpp
~~

fastlz: an ANSI C/C90 implementation of Lempel-Ziv 77 algorithm (LZ77) of lossless data compression.
Copyright (C) 2005-2020 Ariya Hidayat (MIT License)
https://github.com/ariya/FastLZ

~~
Expand Down
1 change: 0 additions & 1 deletion cmake/ExperimentalPlugins.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ auto_option(
)
auto_option(RATE_LIMIT FEATURE_VAR BUILD_RATE_LIMIT DEFAULT ${_DEFAULT})
auto_option(REALIP FEATURE_VAR BUILD_REALIP DEFAULT ${_DEFAULT})
auto_option(REDO_CACHE_LOOKUP FEATURE_VAR BUILD_REDO_CACHE_LOOKUP DEFAULT ${_DEFAULT})
auto_option(SSLHEADERS FEATURE_VAR BUILD_SSLHEADERS DEFAULT ${_DEFAULT})
auto_option(STALE_RESPONSE FEATURE_VAR BUILD_STALE_RESPONSE DEFAULT ${_DEFAULT})
auto_option(
Expand Down
4 changes: 2 additions & 2 deletions doc/admin-guide/files/records.yaml.en.rst
Original file line number Diff line number Diff line change
Expand Up @@ -982,7 +982,7 @@ allow-plain

.. note::

The ``Via`` transaction codes can be decoded with the `Via Decoder Ring <https://trafficserver.apache.org/tools/via>`_.
The ``Via`` transaction codes can be decoded with the `Via Decoder Ring <https://trafficserver.apache.org/via.html>`_.

.. ts:cv:: CONFIG proxy.config.http.request_via_str STRING ApacheTrafficServer/${PACKAGE_VERSION}
:reloadable:
Expand All @@ -1008,7 +1008,7 @@ allow-plain

.. note::

The ``Via`` transaction code can be decoded with the `Via Decoder Ring <https://trafficserver.apache.org/tools/via>`_.
The ``Via`` transaction code can be decoded with the `Via Decoder Ring <https://trafficserver.apache.org/via.html>`_.

.. ts:cv:: CONFIG proxy.config.http.response_via_str STRING ApacheTrafficServer/${PACKAGE_VERSION}
:reloadable:
Expand Down
47 changes: 46 additions & 1 deletion doc/admin-guide/plugins/maxmind_acl.en.rst
Original file line number Diff line number Diff line change
Expand Up @@ -113,4 +113,49 @@ The plugin also supports optional fields from GeoGuard databases which includes:
``vpn_datacenter``
``relay_proxy``
``proxy_over_vpn``
``smart_dns_proxy``
``smart_dns_proxy``

Bypass
======

An optional ``bypass`` field allows a request to skip all geo checks entirely and pass through
unmodified. Both a header name and an expected value must be configured; when the named header
is present in the request **and** its value matches exactly, the plugin returns immediately
without performing any country, IP, regex, or anonymous evaluation.

``header``
Required sub-key. The name of the HTTP request header to look for, e.g. ``@GeoBypass``.

``value``
Required sub-key. The header field value must match this string exactly for the bypass to
trigger. Both ``header`` and ``value`` must be present and non-empty; omitting either
disables the bypass entirely and a warning is emitted to the ATS error log.

The comparison uses the complete, raw field value of the first occurrence of the named header.
Duplicate headers with the same name (repeated lines) are ignored — only the first is evaluated.
Within that first field, the entire value must match exactly, so a comma-separated multi-value
(e.g. ``@GeoBypass: 1, extra``) in a single header line will not match a simple configured value.

An example configuration ::

maxmind:
database: GeoIP2-City.mmdb
bypass:
header: "@GeoBypass"
value: "1"
allow:
country:
- US

This is useful for internal or trusted upstream services that should not be subject to geo
restrictions. If ``bypass`` is absent from the configuration, or if either ``header`` or
``value`` is missing, bypass is disabled and all requests are evaluated normally.

.. warning::

Because the bypass skips **all** ACL checks, the configured header must be
unforgeable by external clients. Use an internal ``@``-prefixed header (e.g.
``@GeoBypass``) that is set by ATS itself or a trusted upstream, or
ensure the edge strips/overwrites the header before it reaches this plugin.
Configuring a normal client-supplied header allows end users to opt out of
geo restrictions by simply sending the header in their request.
2 changes: 1 addition & 1 deletion doc/appendices/faq.en.rst
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ Please refer to the :ref:`forward-proxy` documentation.
How do I interpret the Via: header code?
----------------------------------------

The ``Via`` header string can be decoded with the `Via Decoder Ring <https://trafficserver.apache.org/tools/via>`_.
The ``Via`` header string can be decoded with the `Via Decoder Ring <https://trafficserver.apache.org/via.html>`_.

The Via header is an optional HTTP header added by Traffic Server and other HTTP proxies. If a request goes through multiple proxies, each one appends its Via header content to the end of the existing Via header. Via header content is for general information and diagnostic use only and should not be used as a programmatic interface to Traffic Server. The header is cached by each intermediary with the object as received from its downstream node. Thus, the last node in the list to report a cache hit is the end of the transaction for that specific request. Nodes reported earlier were from a previous transaction.

Expand Down
16 changes: 16 additions & 0 deletions doc/developer-guide/api/functions/TSHttpHdrHostGet.en.rst
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,19 @@ header field.

This is much faster than calling :func:`TSHttpTxnEffectiveUrlStringGet` and
extracting the host from the result.

.. note::

:func:`TSHttpHdrHostGet` checks both the URL and the ``Host`` header field,
making it reliable at any hook stage. In contrast, :func:`TSUrlHostGet`
operates only on the URL object obtained from :func:`TSHttpHdrUrlGet`. In
early hooks such as ``TS_HTTP_READ_REQUEST_HDR_HOOK``, the URL object may
not yet be fully parsed, and :func:`TSUrlHostGet` may return ``NULL`` even
when a ``Host`` header is present.

See Also
========

:func:`TSUrlHostGet`,
:func:`TSHttpHdrUrlGet`,
:func:`TSHttpTxnEffectiveUrlStringGet`
14 changes: 13 additions & 1 deletion doc/developer-guide/api/functions/TSHttpHdrUrlGet.en.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,23 @@ The value placed in :arg:`locp` is stable only for a single callback, as other c
change the URL object itself (see :func:`TSHttpHdrUrlSet`), not just the data in it. That value is
also valid only if this function return ``TS_SUCCESS``.

.. note::

Not all URL components may be available at every hook stage. In early hooks
such as ``TS_HTTP_READ_REQUEST_HDR_HOOK``, the URL object may not yet be
fully parsed. In particular, the host component retrieved via
:func:`TSUrlHostGet` may be ``NULL`` even when a ``Host`` header is present.
For reliable host retrieval across all hook stages, use
:func:`TSHttpHdrHostGet` instead, which checks both the URL and the ``Host``
header field.

See Also
========

:manpage:`TSAPI(3ts)`,
:manpage:`TSHttpTxnClientReqGet(3ts)`,
:manpage:`TSHttpTxnServerReqGet(3ts)`,
:manpage:`TSHttpTxnServerRespGet(3ts)`,
:manpage:`TSHttpTxnClientRespGet(3ts)`
:manpage:`TSHttpTxnClientRespGet(3ts)`,
:manpage:`TSHttpHdrHostGet(3ts)`,
:manpage:`TSUrlHostGet(3ts)`
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,24 @@ Synopsis
Description
===========

Change packet firewall :arg:`mark` for the client side connection.
Change the packet firewall :arg:`mark` for the client side connection. The
entire firewall mark is replaced with :arg:`mark`, which is interpreted as a
32-bit unsigned bit pattern.

Returns :const:`TS_SUCCESS` when the client connection was modified, and
:const:`TS_ERROR` when there is no client connection to modify.

.. note::

The firewall mark is only honored on platforms whose OS supports it,
specifically Linux via ``SO_MARK``. On platforms without ``SO_MARK`` support
the call still returns :const:`TS_SUCCESS` when a client connection is
present, but setting the mark has no effect at the OS layer (it is a safe
no-op).

.. note::

Changes take effect immediately.
The change takes effect immediately on the live client connection.

See Also
========
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@
TSHttpTxnServerPacketMarkSet
****************************

Change packet firewall mark for the server side connection.

Synopsis
========

Expand All @@ -34,13 +32,25 @@ Synopsis
Description
===========

Change the packet firewall :arg:`mark` for the server side (origin) connection.
The entire firewall mark is replaced with :arg:`mark`, which is interpreted as a
32-bit unsigned bit pattern.

Always returns :const:`TS_SUCCESS`, including when no server connection has been
established yet.

.. note::

The change takes effect immediately. If no OS connection has been
made, then this sets the mark that will be used. If an OS connection
is established
The firewall mark is only honored on platforms whose OS supports it,
specifically Linux via ``SO_MARK``. On platforms without ``SO_MARK`` support
the call still returns :const:`TS_SUCCESS`, but setting the mark has no effect
at the OS layer (it is a safe no-op).

.. note::

.. XXX Third sentence above needs to be completed.
If a live server connection exists, the mark is applied to it immediately; the
mark is also recorded on the transaction so that any subsequent server
connection for this transaction uses it.

See Also
========
Expand Down
11 changes: 11 additions & 0 deletions doc/developer-guide/api/functions/TSUrlHostGet.en.rst
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,16 @@ scheme.
:arg:`offset` within the marshal buffer :arg:`bufp`. If there is no explicit
port number in the URL, zero is returned.

.. note::

:func:`TSUrlHostGet` operates on a URL object obtained from
:func:`TSHttpHdrUrlGet`. In early hooks such as
``TS_HTTP_READ_REQUEST_HDR_HOOK``, the URL object may not yet be fully
parsed, and :func:`TSUrlHostGet` may return ``NULL`` even when a ``Host``
header is present. For reliable host retrieval at any hook stage, use
:func:`TSHttpHdrHostGet` instead, which checks both the URL and the
``Host`` header field.

Return Values
=============

Expand All @@ -90,6 +100,7 @@ See Also
:manpage:`TSAPI(3ts)`,
:manpage:`TSUrlCreate(3ts)`,
:manpage:`TSHttpHdrUrlGet(3ts)`,
:manpage:`TSHttpHdrHostGet(3ts)`,
:manpage:`TSUrlHostSet(3ts)`,
:manpage:`TSUrlStringGet(3ts)`,
:manpage:`TSUrlPercentEncode(3ts)`
8 changes: 8 additions & 0 deletions example/plugins/c-api/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ add_atsplugin(secure_link ./secure_link/secure_link.cc)
target_link_libraries(secure_link PRIVATE OpenSSL::SSL)
add_atsplugin(remap ./remap/remap.cc)
add_atsplugin(redirect_1 ./redirect_1/redirect_1.cc)
add_atsplugin(redo_cache_lookup ./redo_cache_lookup/redo_cache_lookup.cc)
add_atsplugin(query_remap ./query_remap/query_remap.cc)
add_atsplugin(thread_pool ./thread_pool/psi.cc ./thread_pool/thread.cc)
add_atsplugin(bnull_transform ./bnull_transform/bnull_transform.cc)
Expand Down Expand Up @@ -66,3 +67,10 @@ add_atsplugin(protocol_stack ./protocol_stack/protocol_stack.cc)
add_atsplugin(client_context_dump ./client_context_dump/client_context_dump.cc)
target_link_libraries(client_context_dump PRIVATE OpenSSL::SSL libswoc::libswoc)
add_atsplugin(custom_logfield ./custom_logfield/custom_logfield.cc)

if(BUILD_TESTING)
add_executable(test_redo_cache_lookup ./redo_cache_lookup/unit_tests/test_redo_cache_lookup_config.cc)
target_include_directories(test_redo_cache_lookup PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/redo_cache_lookup)
target_link_libraries(test_redo_cache_lookup PRIVATE Catch2::Catch2WithMain)
add_catch2_test(NAME test_redo_cache_lookup COMMAND test_redo_cache_lookup)
endif()
13 changes: 2 additions & 11 deletions example/plugins/c-api/redirect_1/redirect_1.cc
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ static void
handle_client_lookup(TSHttpTxn txnp, TSCont contp)
{
TSMBuffer bufp;
TSMLoc hdr_loc, url_loc;
TSMLoc hdr_loc;
int host_length;

in_addr_t clientip = 0;
Expand Down Expand Up @@ -130,16 +130,9 @@ handle_client_lookup(TSHttpTxn txnp, TSCont contp)
goto done;
}

if (TSHttpHdrUrlGet(bufp, hdr_loc, &url_loc) != TS_SUCCESS) {
TSError("[%s] Couldn't retrieve request url", PLUGIN_NAME);
TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
goto done;
}

host = TSUrlHostGet(bufp, url_loc, &host_length);
host = TSHttpHdrHostGet(bufp, hdr_loc, &host_length);
if (!host) {
TSError("[%s] Couldn't retrieve request hostname", PLUGIN_NAME);
TSHandleMLocRelease(bufp, hdr_loc, url_loc);
TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
goto done;
}
Expand All @@ -148,7 +141,6 @@ handle_client_lookup(TSHttpTxn txnp, TSCont contp)
* Check to see if the client is already headed to the redirect site.
*/
if (strncmp(host, url_redirect, host_length) == 0) {
TSHandleMLocRelease(bufp, hdr_loc, url_loc);
TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
goto done;
}
Expand All @@ -159,7 +151,6 @@ handle_client_lookup(TSHttpTxn txnp, TSCont contp)

update_redirected_method_stats(bufp, hdr_loc);

TSHandleMLocRelease(bufp, hdr_loc, url_loc);
TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);

/*
Expand Down
13 changes: 13 additions & 0 deletions example/plugins/c-api/redo_cache_lookup/readme.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Redo Cache Lookup Example Plugin

This plugin shows how to use the `TSHttpTxnRedoCacheLookup` C API. It
checks cache lookup results and asks ATS to retry the lookup with a fallback
URL when the original lookup misses or is skipped.

## Configuration

Add this plugin to `plugin.config` with the `--fallback` option:

```
redo_cache_lookup.so --fallback http://example.com/fallback_url
```
91 changes: 91 additions & 0 deletions example/plugins/c-api/redo_cache_lookup/redo_cache_lookup.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/** @file

An example plugin to redo cache lookups with a fallback URL.

@section license License

Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#include <string>
#include <string_view>

#include "ts/ts.h"
#include "redo_cache_lookup_config.h"

#define PLUGIN_NAME "redo_cache_lookup"

namespace
{
DbgCtl dbg_ctl{PLUGIN_NAME};

struct RedoCacheLookupConfig {
RedoCacheLookupConfig(std::string_view fallback) : fallback(fallback) {}

std::string fallback;
};

int
handle_cache_lookup_complete(TSCont contp, TSEvent event, void *edata)
{
if (event != TS_EVENT_HTTP_CACHE_LOOKUP_COMPLETE) {
return 0;
}

TSHttpTxn txnp = static_cast<TSHttpTxn>(edata);
auto *config = static_cast<RedoCacheLookupConfig *>(TSContDataGet(contp));
int status = TS_CACHE_LOOKUP_MISS;

if (TSHttpTxnCacheLookupStatusGet(txnp, &status) != TS_SUCCESS || status == TS_CACHE_LOOKUP_MISS ||
status == TS_CACHE_LOOKUP_SKIPPED) {
Dbg(dbg_ctl, "rewinding to check for fallback url: %s", config->fallback.c_str());
TSHttpTxnRedoCacheLookup(txnp, config->fallback.c_str(), static_cast<int>(config->fallback.size()));
}

TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
return 0;
}
} // namespace

void
TSPluginInit(int argc, const char *argv[])
{
TSPluginRegistrationInfo info;

Dbg(dbg_ctl, "Init");
info.plugin_name = PLUGIN_NAME;
info.vendor_name = "Apache Software Foundation";
info.support_email = "dev@trafficserver.apache.org";

if (TSPluginRegister(&info) != TS_SUCCESS) {
TSError("[%s] Plugin registration failed", PLUGIN_NAME);
return;
}

auto fallback = redo_cache_lookup::parse_fallback_url(argc, argv);

if (!fallback) {
Dbg(dbg_ctl, "Missing fallback option.");
TSError("[%s] Missing fallback option", PLUGIN_NAME);
return;
}
Dbg(dbg_ctl, "Initialized with fallback: %s", fallback->c_str());

TSCont contp = TSContCreate(handle_cache_lookup_complete, nullptr);
TSContDataSet(contp, new RedoCacheLookupConfig(*fallback));
TSHttpHookAdd(TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK, contp);
}
Loading