[PATCH] Memcached: memcached_flags_set directive
J Carter
jordanc.carter at outlook.com
Mon May 27 03:30:53 UTC 2024
# HG changeset patch
# User J Carter <jordanc.carter at outlook.com>
# Date 1716779649 -3600
# Mon May 27 04:14:09 2024 +0100
# Node ID e90301dd1516b6dfa5b2b0beec05cfe2b567ea1e
# Parent f58b6f6362387eeace46043a6fc0bceb56a6786a
Memcached: memcached_flags_set directive.
This directive creates a variable that returns the masked value of
memcached response flags, by bitwise ANDing flags with specified
mask.
The optional 'shift' parameter may be used right bit-shift extracted
value, for unpacking values.
memcached_flags_set <variable> <mask> <shift>
This directive may be specified in http context only.
The purpose of this directive is to provide a more generalized form
of the memcached_gzip_flag directive, to provide the means of
conditionally adding other headers to response, such as cache control
headers, and of setting their value dynamically using packed values
in flags.
Example #1:
memcached_flags_set $flags_expire 1;
map $flags_expire $expires_value {
0 off;
1 epoch;
}
server {
location / {
expires $expires_value;
memcached_pass ...;
}
}
Example #2:
memcached_flags_set $flags_expire 1 0;
memcached_flags_set $flags_expire 62 1;
map $flags_expire $expires_value {
0 off;
1 ${flags_expire_hour}h; #0-24h
}
server {
location / {
expires $expires_value;
memcached_pass ...;
}
}
diff --git a/src/http/modules/ngx_http_memcached_module.c b/src/http/modules/ngx_http_memcached_module.c
--- a/src/http/modules/ngx_http_memcached_module.c
+++ b/src/http/modules/ngx_http_memcached_module.c
@@ -21,9 +21,16 @@
size_t rest;
ngx_http_request_t *request;
ngx_str_t key;
+ ngx_uint_t flags;
} ngx_http_memcached_ctx_t;
+typedef struct {
+ ngx_uint_t mask;
+ ngx_uint_t shift;
+} ngx_http_memcached_set_t;
+
+
static ngx_int_t ngx_http_memcached_create_request(ngx_http_request_t *r);
static ngx_int_t ngx_http_memcached_reinit_request(ngx_http_request_t *r);
static ngx_int_t ngx_http_memcached_process_header(ngx_http_request_t *r);
@@ -33,12 +40,16 @@
static void ngx_http_memcached_finalize_request(ngx_http_request_t *r,
ngx_int_t rc);
+static ngx_int_t ngx_http_memcached_variable_set(ngx_http_request_t *r,
+ ngx_http_variable_value_t *v, uintptr_t data);
static void *ngx_http_memcached_create_loc_conf(ngx_conf_t *cf);
static char *ngx_http_memcached_merge_loc_conf(ngx_conf_t *cf,
void *parent, void *child);
static char *ngx_http_memcached_pass(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
+static char *ngx_http_memcached_set(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
static ngx_conf_bitmask_t ngx_http_memcached_next_upstream_masks[] = {
@@ -130,6 +141,13 @@
offsetof(ngx_http_memcached_loc_conf_t, gzip_flag),
NULL },
+ { ngx_string("memcached_flags_set"),
+ NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE23,
+ ngx_http_memcached_set,
+ 0,
+ 0,
+ NULL },
+
ngx_null_command
};
@@ -219,6 +237,7 @@
}
ctx->request = r;
+ ctx->flags = 0;
ngx_http_set_ctx(r, ctx, ngx_http_memcached_module);
@@ -370,20 +389,12 @@
start = p;
- while (*p) {
- if (*p++ == ' ') {
- if (mlcf->gzip_flag) {
- goto flags;
- } else {
- goto length;
- }
+ while (*p++ != ' ') {
+ if (*p == '\0') {
+ goto no_valid;
}
}
- goto no_valid;
-
- flags:
-
flags = ngx_atoi(start, p - start - 1);
if (flags == (ngx_uint_t) NGX_ERROR) {
@@ -407,7 +418,9 @@
r->headers_out.content_encoding = h;
}
- length:
+ ctx->flags = flags;
+
+ /* length */
start = p;
p = line.data + line.len;
@@ -587,6 +600,38 @@
}
+static ngx_int_t
+ngx_http_memcached_variable_set(ngx_http_request_t *r,
+ ngx_http_variable_value_t *v, uintptr_t data)
+{
+ ngx_http_memcached_ctx_t *ctx;
+ ngx_http_memcached_set_t *set;
+
+ set = (ngx_http_memcached_set_t *) data;
+
+ ctx = ngx_http_get_module_ctx(r, ngx_http_memcached_module);
+ if (ctx == NULL) {
+ v->not_found = 1;
+ return NGX_OK;
+ }
+
+ v->data = ngx_pnalloc(r->pool, sizeof("4294967295") - 1);
+ if (v->data == NULL) {
+ return NGX_ERROR;
+ }
+
+ v->len = 0;
+ v->valid = 1;
+ v->no_cacheable = 1;
+ v->not_found = 0;
+
+ v->len = ngx_sprintf(v->data, "%ui",
+ (ctx->flags & set->mask) >> set->shift) - v->data;
+
+ return NGX_OK;
+}
+
+
static void *
ngx_http_memcached_create_loc_conf(ngx_conf_t *cf)
{
@@ -734,3 +779,59 @@
return NGX_CONF_OK;
}
+
+
+static char *
+ngx_http_memcached_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_str_t *value;
+ ngx_http_variable_t *v;
+ ngx_http_memcached_set_t *set;
+
+ value = cf->args->elts;
+
+ if (value[1].data[0] != '$') {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid variable name \"%V\"", &value[1]);
+ return NGX_CONF_ERROR;
+ }
+
+ value[1].len--;
+ value[1].data++;
+
+ v = ngx_http_add_variable(cf, &value[1], NGX_HTTP_VAR_NOCACHEABLE);
+ if (v == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ set = ngx_palloc(cf->pool, sizeof(ngx_http_memcached_set_t));
+ if (set == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ set->mask = ngx_atoi(value[2].data, value[2].len);
+
+ if (set->mask == (ngx_uint_t) NGX_ERROR) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid mask \"%V\"", &value[2]);
+ return NGX_CONF_ERROR;
+ }
+
+ set->shift = 0;
+
+ if (cf->args->nelts > 3) {
+
+ set->shift = ngx_atoi(value[3].data, value[3].len);
+
+ if (set->shift == (ngx_uint_t) NGX_ERROR || set->shift > 31) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid shift \"%V\"", &value[3]);
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ v->data = (uintptr_t) set;
+ v->get_handler = ngx_http_memcached_variable_set;
+
+ return NGX_CONF_OK;
+}
More information about the nginx-devel
mailing list