Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 7 additions & 0 deletions doc/admin-guide/plugins/cache_range_requests.en.rst
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ X-Crr-Ims header support

.. option:: --consider-ims
.. option:: -c
.. option:: --ims-header=[header name] (default: X-Crr-Ims)
.. option:: -i

To support slice plugin self healing an option to force revalidation
after cache lookup complete was added. This option is triggered by a
Expand All @@ -137,6 +139,11 @@ In order for this to properly work in a CDN each cache in the
chain *SHOULD* also contain a remap rule with the
:program:`cache_range_requests` plugin with this option set.

When used with the :program:`slice` plugin its `--crr-ims-header`
option must have the same value (or not be defined) in order to work.

Presence of the `--ims-header` automatically sets the `--consider-ims` option.

Don't modify the Cache Key
--------------------------

Expand Down
13 changes: 13 additions & 0 deletions doc/admin-guide/plugins/slice.en.rst
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,19 @@ The slice plugin supports the following options::
Requires setting up an intermediate loopback remap rule.
-r for short

--skip-header=<header name> (default: X-Slicer-Info)
Header name used by the slice plugin after the loopback
to indicate that the slice plugin should be skipped.
-s for short

--crr-ims-header=<header name> (default: X-Crr-Ims)
Header name used by the slice plugin to tell the
`cache_range_requests` plugin that a request should
be marked as STALE. Used for self healing.
This must match the `--ims-header` option used by the
`cache_range_requests` plugin.
-i for short

Examples::

@plugin=slice.so @pparam=--blockbytes=1000000 @plugin=cache_range_requests.so
Expand Down
41 changes: 26 additions & 15 deletions plugins/cache_range_requests/cache_range_requests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,14 @@ using parent_select_mode_t = enum parent_select_mode {
PS_CACHEKEY_URL, // Set parent selection url to cache_key url
};

constexpr std::string_view DefaultImsHeader = {"X-Crr-Ims"};

struct pluginconfig {
parent_select_mode_t ps_mode{PS_DEFAULT};
bool consider_ims_header{false};
bool modify_cache_key{true};
bool verify_cacheability{false};
std::string ims_header;
};

struct txndata {
Expand All @@ -61,9 +64,6 @@ struct txndata {
bool verify_cacheability{false};
};

// Header for optional revalidation
constexpr std::string_view X_IMS_HEADER = {"X-Crr-Ims"};

// pluginconfig struct (global plugin only)
pluginconfig *gPluginConfig = {nullptr};

Expand Down Expand Up @@ -99,9 +99,10 @@ create_pluginconfig(int argc, char *const argv[])
}

static const struct option longopts[] = {
{const_cast<char *>("ps-cachekey"), no_argument, nullptr, 'p'},
{const_cast<char *>("consider-ims"), no_argument, nullptr, 'c'},
{const_cast<char *>("ims-header"), required_argument, nullptr, 'i'},
{const_cast<char *>("no-modify-cachekey"), no_argument, nullptr, 'n'},
{const_cast<char *>("ps-cachekey"), no_argument, nullptr, 'p'},
{const_cast<char *>("verify-cacheability"), no_argument, nullptr, 'v'},
{nullptr, 0, nullptr, 0},
};
Expand All @@ -111,24 +112,29 @@ create_pluginconfig(int argc, char *const argv[])
--argv;

for (;;) {
int const opt = getopt_long(argc, argv, "", longopts, nullptr);
int const opt = getopt_long(argc, argv, "i:", longopts, nullptr);
if (-1 == opt) {
break;
}

switch (opt) {
case 'p': {
DEBUG_LOG("Plugin modifies parent selection key");
pc->ps_mode = PS_CACHEKEY_URL;
} break;
case 'c': {
DEBUG_LOG("Plugin considers the '%.*s' header", (int)X_IMS_HEADER.size(), X_IMS_HEADER.data());
DEBUG_LOG("Plugin considers the ims header");
pc->consider_ims_header = true;
} break;
case 'i': {
DEBUG_LOG("Plugin uses custom ims header: %s", optarg);
pc->ims_header.assign(optarg);
pc->consider_ims_header = true;
} break;
case 'n': {
DEBUG_LOG("Plugin doesn't modify cache key");
pc->modify_cache_key = false;
} break;
case 'p': {
DEBUG_LOG("Plugin modifies parent selection key");
pc->ps_mode = PS_CACHEKEY_URL;
} break;
case 'v': {
DEBUG_LOG("Plugin verifies whether the object in the transaction is cacheable");
pc->verify_cacheability = true;
Expand All @@ -144,6 +150,11 @@ create_pluginconfig(int argc, char *const argv[])
pc->ps_mode = PS_CACHEKEY_URL;
}

if (pc->consider_ims_header && pc->ims_header.empty()) {
pc->ims_header = DefaultImsHeader;
DEBUG_LOG("Plugin uses default ims header: %s", pc->ims_header.c_str());
}

return pc;
}

Expand Down Expand Up @@ -244,12 +255,12 @@ range_header_check(TSHttpTxn txnp, pluginconfig *const pc)
}
}

// optionally consider an X-CRR-IMS header
// optionally consider an ims header
if (pc->consider_ims_header) {
TSMLoc const imsloc = TSMimeHdrFieldFind(hdr_buf, hdr_loc, X_IMS_HEADER.data(), X_IMS_HEADER.size());
TSMLoc const imsloc = TSMimeHdrFieldFind(hdr_buf, hdr_loc, pc->ims_header.data(), pc->ims_header.size());
if (TS_NULL_MLOC != imsloc) {
time_t const itime = TSMimeHdrFieldValueDateGet(hdr_buf, hdr_loc, imsloc);
DEBUG_LOG("Servicing the '%.*s' header", (int)X_IMS_HEADER.size(), X_IMS_HEADER.data());
DEBUG_LOG("Servicing the '%s' header", pc->ims_header.c_str());
TSHandleMLocRelease(hdr_buf, hdr_loc, imsloc);
if (0 < itime) {
txn_state->ims_time = itime;
Expand Down Expand Up @@ -303,7 +314,7 @@ handle_send_origin_request(TSCont contp, TSHttpTxn txnp, txndata *const txn_stat
}

if (TS_SUCCESS == TSHttpTxnServerReqGet(txnp, &hdr_buf, &hdr_loc) && !rv.empty()) {
if (set_header(hdr_buf, hdr_loc, TS_MIME_FIELD_RANGE, TS_MIME_LEN_RANGE, rv.data(), rv.length())) {
if (set_header(hdr_buf, hdr_loc, TS_MIME_FIELD_RANGE, TS_MIME_LEN_RANGE, rv.data(), rv.size())) {
DEBUG_LOG("Added range header: %s", rv.c_str());
TSHttpTxnHookAdd(txnp, TS_HTTP_READ_RESPONSE_HDR_HOOK, contp);
}
Expand Down Expand Up @@ -345,7 +356,7 @@ handle_client_send_response(TSHttpTxn txnp, txndata *const txn_state)
TSMLoc req_loc = TS_NULL_MLOC;
if (TS_SUCCESS == TSHttpTxnClientReqGet(txnp, &req_buf, &req_loc)) {
DEBUG_LOG("Adding range header: %s", rv.c_str());
if (!set_header(req_buf, req_loc, TS_MIME_FIELD_RANGE, TS_MIME_LEN_RANGE, rv.data(), rv.length())) {
if (!set_header(req_buf, req_loc, TS_MIME_FIELD_RANGE, TS_MIME_LEN_RANGE, rv.data(), rv.size())) {
DEBUG_LOG("set_header() failed.");
}
TSHandleMLocRelease(req_buf, TS_NULL_MLOC, req_loc);
Expand Down
26 changes: 25 additions & 1 deletion plugins/experimental/slice/Config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@

#include "ts/experimental.h"

namespace
{
constexpr std::string_view DefaultSliceSkipHeader = {"X-Slicer-Info"};
constexpr std::string_view DefaultCrrImsHeader = {"X-Crr-Ims"};
} // namespace

Config::~Config()
{
if (nullptr != m_regex_extra) {
Expand Down Expand Up @@ -108,20 +114,22 @@ Config::fromArgs(int const argc, char const *const argv[])
// standard parsing
constexpr struct option longopts[] = {
{const_cast<char *>("blockbytes"), required_argument, nullptr, 'b'},
{const_cast<char *>("crr-ims-header"), required_argument, nullptr, 'c'},
{const_cast<char *>("disable-errorlog"), no_argument, nullptr, 'd'},
{const_cast<char *>("exclude-regex"), required_argument, nullptr, 'e'},
{const_cast<char *>("include-regex"), required_argument, nullptr, 'i'},
{const_cast<char *>("ref-relative"), no_argument, nullptr, 'l'},
{const_cast<char *>("pace-errorlog"), required_argument, nullptr, 'p'},
{const_cast<char *>("remap-host"), required_argument, nullptr, 'r'},
{const_cast<char *>("skip-header"), required_argument, nullptr, 's'},
{const_cast<char *>("blockbytes-test"), required_argument, nullptr, 't'},
{nullptr, 0, nullptr, 0},
};

// getopt assumes args start at '1' so this hack is needed
char *const *argvp = (const_cast<char *const *>(argv) - 1);
for (;;) {
int const opt = getopt_long(argc + 1, argvp, "b:de:i:lp:r:t:", longopts, nullptr);
int const opt = getopt_long(argc + 1, argvp, "b:dc:e:i:lp:r:s:t:", longopts, nullptr);
if (-1 == opt) {
break;
}
Expand All @@ -138,6 +146,10 @@ Config::fromArgs(int const argc, char const *const argv[])
ERROR_LOG("Invalid blockbytes: %s", optarg);
}
} break;
case 'c': {
m_crr_ims_header.assign(optarg);
DEBUG_LOG("Using override crr ims header %s", optarg);
} break;
case 'd': {
m_paceerrsecs = -1;
} break;
Expand Down Expand Up @@ -193,6 +205,10 @@ Config::fromArgs(int const argc, char const *const argv[])
m_remaphost = optarg;
DEBUG_LOG("Using loopback remap host override: %s", m_remaphost.c_str());
} break;
case 's': {
m_skip_header.assign(optarg);
DEBUG_LOG("Using slice skip header %s", optarg);
} break;
case 't': {
if (0 == blockbytes) {
int64_t const bytesread = bytesFrom(optarg);
Expand Down Expand Up @@ -225,6 +241,14 @@ Config::fromArgs(int const argc, char const *const argv[])
} else {
DEBUG_LOG("Block stitching error logs at most every %d sec(s)", m_paceerrsecs);
}
if (m_crr_ims_header.empty()) {
m_crr_ims_header = DefaultCrrImsHeader;
DEBUG_LOG("Using default crr ims header %s", m_crr_ims_header.c_str());
}
if (m_skip_header.empty()) {
m_skip_header = DefaultSliceSkipHeader;
DEBUG_LOG("Using default slice skip header %s", m_skip_header.c_str());
}

return true;
}
Expand Down
3 changes: 3 additions & 0 deletions plugins/experimental/slice/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ struct Config {
enum RefType { First, Relative };
RefType m_reftype{First}; // reference slice is relative to request

std::string m_skip_header;
std::string m_crr_ims_header;

// Convert optarg to bytes
static int64_t bytesFrom(char const *const valstr);

Expand Down
2 changes: 0 additions & 2 deletions plugins/experimental/slice/HttpHeader.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@

#include <string>

static char const *const SLICER_MIME_FIELD_INFO = "X-Slicer-Info";

/**
Designed to be a cheap throwaway struct which allows a
consumer to make various calls to manipulate headers.
Expand Down
15 changes: 8 additions & 7 deletions plugins/experimental/slice/client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,13 @@ handle_client_req(TSCont contp, TSEvent event, Data *const data)
Range rangebe;

char rangestr[1024];
int rangelen = sizeof(rangestr);
bool const hasRange = header.valueForKey(TS_MIME_FIELD_RANGE, TS_MIME_LEN_RANGE, rangestr, &rangelen,
int rangelen = sizeof(rangestr);
bool const hasRange = header.valueForKey(TS_MIME_FIELD_RANGE, TS_MIME_LEN_RANGE, rangestr, &rangelen,
0); // <-- first range only
Config const *const conf = data->m_config;
if (hasRange) {
// write parsed header into slicer meta tag
header.setKeyVal(SLICER_MIME_FIELD_INFO, strlen(SLICER_MIME_FIELD_INFO), rangestr, rangelen);
header.setKeyVal(conf->m_skip_header.c_str(), conf->m_skip_header.size(), rangestr, rangelen);
bool const isRangeGood = rangebe.fromStringClosed(rangestr);

if (isRangeGood) {
Expand All @@ -74,21 +75,21 @@ handle_client_req(TSCont contp, TSEvent event, Data *const data)
data->m_statustype = TS_HTTP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE;

// First block will give Content-Length
rangebe = Range(0, data->m_config->m_blockbytes);
rangebe = Range(0, conf->m_blockbytes);
}
} else {
DEBUG_LOG("%p Full content request", data);
static char const *const valstr = "-";
static size_t const vallen = strlen(valstr);
header.setKeyVal(SLICER_MIME_FIELD_INFO, strlen(SLICER_MIME_FIELD_INFO), valstr, vallen);
header.setKeyVal(conf->m_skip_header.data(), conf->m_skip_header.size(), valstr, vallen);
data->m_statustype = TS_HTTP_STATUS_OK;
rangebe = Range(0, Range::maxval);
}

if (Config::RefType::First == data->m_config->m_reftype) {
if (Config::RefType::First == conf->m_reftype) {
data->m_blocknum = 0;
} else {
data->m_blocknum = rangebe.firstBlockFor(data->m_config->m_blockbytes);
data->m_blocknum = rangebe.firstBlockFor(conf->m_blockbytes);
}

data->m_req_range = rangebe;
Expand Down
20 changes: 11 additions & 9 deletions plugins/experimental/slice/server.cc
Original file line number Diff line number Diff line change
Expand Up @@ -223,9 +223,9 @@ handleFirstServerHeader(Data *const data, TSCont const contp)
void
logSliceError(char const *const message, Data const *const data, HttpHeader const &header_resp)
{
Config *const config = data->m_config;
Config *const conf = data->m_config;

bool const logToError = config->canLogError();
bool const logToError = conf->canLogError();

// always write block stitch errors while in debug mode
if (!logToError && !TSIsDebugTagSet(PLUGIN_NAME)) {
Expand Down Expand Up @@ -259,7 +259,7 @@ logSliceError(char const *const message, Data const *const data, HttpHeader cons
// raw range request
char rangestr[1024];
int rangelen = sizeof(rangestr);
header_req.valueForKey(SLICER_MIME_FIELD_INFO, strlen(SLICER_MIME_FIELD_INFO), rangestr, &rangelen);
header_req.valueForKey(conf->m_skip_header.data(), conf->m_skip_header.size(), rangestr, &rangelen);

// Normalized range request
ContentRange const crange(data->m_req_range.m_beg, data->m_req_range.m_end, data->m_contentlen);
Expand All @@ -268,8 +268,8 @@ logSliceError(char const *const message, Data const *const data, HttpHeader cons
crange.toStringClosed(normstr, &normlen);

// block range request
int64_t const blockbeg = data->m_blocknum * data->m_config->m_blockbytes;
int64_t const blockend = std::min(blockbeg + data->m_config->m_blockbytes, data->m_contentlen);
int64_t const blockbeg = data->m_blocknum * conf->m_blockbytes;
int64_t const blockend = std::min(blockbeg + conf->m_blockbytes, data->m_contentlen);

// Block response data
TSHttpStatus const statusgot = header_resp.status();
Expand Down Expand Up @@ -416,8 +416,9 @@ handleNextServerHeader(Data *const data, TSCont const contp)

// add special CRR IMS header to the request
HttpHeader headerreq(data->m_req_hdrmgr.m_buffer, data->m_req_hdrmgr.m_lochdr);
if (!headerreq.setKeyTime(X_CRR_IMS_HEADER.data(), X_CRR_IMS_HEADER.size(), dateims)) {
ERROR_LOG("Failed setting '%.*s'", (int)X_CRR_IMS_HEADER.size(), X_CRR_IMS_HEADER.data());
Config const *const conf = data->m_config;
if (!headerreq.setKeyTime(conf->m_crr_ims_header.data(), conf->m_crr_ims_header.size(), dateims)) {
ERROR_LOG("Failed setting '%s'", conf->m_crr_ims_header.c_str());
return false;
}

Expand All @@ -438,8 +439,9 @@ handleNextServerHeader(Data *const data, TSCont const contp)

// add special CRR IMS header to the request
HttpHeader headerreq(data->m_req_hdrmgr.m_buffer, data->m_req_hdrmgr.m_lochdr);
if (!headerreq.setKeyTime(X_CRR_IMS_HEADER.data(), X_CRR_IMS_HEADER.size(), dateims)) {
ERROR_LOG("Failed setting '%.*s'", (int)X_CRR_IMS_HEADER.size(), X_CRR_IMS_HEADER.data());
Config const *const conf = data->m_config;
if (!headerreq.setKeyTime(conf->m_crr_ims_header.data(), conf->m_crr_ims_header.size(), dateims)) {
ERROR_LOG("Failed setting '%s'", conf->m_crr_ims_header.c_str());
return false;
}

Expand Down
11 changes: 3 additions & 8 deletions plugins/experimental/slice/slice.cc
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,7 @@ read_request(TSHttpTxn txnp, Config *const config)
HttpHeader const header(hdrmgr.m_buffer, hdrmgr.m_lochdr);

if (TS_HTTP_METHOD_GET == header.method()) {
static int const SLICER_MIME_LEN_INFO = strlen(SLICER_MIME_FIELD_INFO);
if (!header.hasKey(SLICER_MIME_FIELD_INFO, SLICER_MIME_LEN_INFO)) {
if (!header.hasKey(config->m_skip_header.data(), config->m_skip_header.size())) {
// check if any previous plugin has monkeyed with the transaction status
TSHttpStatus const txnstat = TSHttpTxnStatusGet(txnp);
if (TS_HTTP_STATUS_NONE != txnstat) {
Expand Down Expand Up @@ -233,9 +232,7 @@ TSReturnCode
TSRemapNewInstance(int argc, char *argv[], void **ih, char * /* errbuf */, int /* errbuf_size */)
{
Config *const config = new Config;
if (2 < argc) {
config->fromArgs(argc - 2, argv + 2);
}
config->fromArgs(argc - 2, argv + 2);
*ih = static_cast<void *>(config);
return TS_SUCCESS;
}
Expand Down Expand Up @@ -274,9 +271,7 @@ TSPluginInit(int argc, char const *argv[])
return;
}

if (1 < argc) {
globalConfig.fromArgs(argc - 1, argv + 1);
}
globalConfig.fromArgs(argc - 1, argv + 1);

TSCont const contp(TSContCreate(global_read_request_hook, nullptr));

Expand Down
2 changes: 0 additions & 2 deletions plugins/experimental/slice/slice.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@
#define PLUGIN_NAME "slice"
#endif

constexpr std::string_view X_CRR_IMS_HEADER = {"X-Crr-Ims"};

#if !defined(UNITTEST)

#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
Expand Down
Loading