# HG changeset patch # User J Carter <jordanc.car...@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; +} _______________________________________________ nginx-devel mailing list nginx-devel@nginx.org https://mailman.nginx.org/mailman/listinfo/nginx-devel