MINOR: cache: Create res.cache_hit and res.cache_name sample fetches
Res.cache_hit sample fetch returns a boolean which is true when the HTTP response was built out of a cache. The cache's name is returned by the res.cache_name sample_fetch. This resolves GitHub issue #900.
This commit is contained in:
parent
53161d81b8
commit
bf97121f1c
|
@ -18195,6 +18195,15 @@ res.body_size : integer
|
|||
useful (and usable) in the health-check context. It may be used in tcp-check
|
||||
based expect rules.
|
||||
|
||||
res.cache_hit : boolean
|
||||
Returns the boolean "true" value if the response has been built out of an
|
||||
HTTP cache entry, otherwise returns boolean "false".
|
||||
|
||||
res.cache_name : string
|
||||
Returns a string containing the name of the HTTP cache that was used to
|
||||
build the HTTP response if res.cache_hit is true, otherwise returns an
|
||||
empty string.
|
||||
|
||||
res.comp : boolean
|
||||
Returns the boolean "true" value if the response has been compressed by
|
||||
HAProxy, otherwise returns boolean "false". This may be used to add
|
||||
|
|
|
@ -0,0 +1,130 @@
|
|||
|
||||
varnishtest "Basic cache test"
|
||||
|
||||
#REQUIRE_VERSION=1.9
|
||||
|
||||
feature ignore_unknown_macro
|
||||
|
||||
server s1 {
|
||||
rxreq
|
||||
txresp -nolen -hdr "Transfer-Encoding: chunked"
|
||||
chunkedlen 15
|
||||
chunkedlen 15
|
||||
chunkedlen 15
|
||||
chunkedlen 0
|
||||
} -start
|
||||
|
||||
server s2 {
|
||||
rxreq
|
||||
txresp -nolen -hdr "Transfer-Encoding: chunked"
|
||||
chunkedlen 16
|
||||
chunkedlen 16
|
||||
chunkedlen 16
|
||||
chunkedlen 0
|
||||
} -start
|
||||
|
||||
server s3 {
|
||||
rxreq
|
||||
txresp -nolen -hdr "Transfer-Encoding: chunked"
|
||||
chunkedlen 17
|
||||
chunkedlen 17
|
||||
chunkedlen 17
|
||||
chunkedlen 0
|
||||
|
||||
rxreq
|
||||
txresp -nolen -hdr "Transfer-Encoding: chunked"
|
||||
chunkedlen 17
|
||||
chunkedlen 17
|
||||
chunkedlen 17
|
||||
chunkedlen 0
|
||||
} -start
|
||||
|
||||
haproxy h1 -conf {
|
||||
defaults
|
||||
mode http
|
||||
${no-htx} option http-use-htx
|
||||
timeout connect 1s
|
||||
timeout client 1s
|
||||
timeout server 1s
|
||||
|
||||
frontend fe
|
||||
bind "fd@${fe}"
|
||||
use_backend first_be if { path_beg /first }
|
||||
use_backend nocache_be if { path_beg /nocache }
|
||||
default_backend second_be
|
||||
|
||||
backend first_be
|
||||
http-request cache-use first_cache
|
||||
server www ${s1_addr}:${s1_port}
|
||||
http-response cache-store first_cache
|
||||
http-response set-header X-Cache-Hit %[res.cache_hit]
|
||||
http-response set-header X-Cache-Name %[res.cache_name]
|
||||
|
||||
backend second_be
|
||||
http-request cache-use second_cache
|
||||
server www ${s2_addr}:${s2_port}
|
||||
http-response cache-store second_cache
|
||||
http-response set-header X-Cache-Hit %[res.cache_hit]
|
||||
http-response set-header X-Cache-Name %[res.cache_name]
|
||||
|
||||
backend nocache_be
|
||||
server www ${s3_addr}:${s3_port}
|
||||
http-response set-header X-Cache-Hit %[res.cache_hit]
|
||||
http-response set-header X-Cache-Name %[res.cache_name]
|
||||
|
||||
cache first_cache
|
||||
total-max-size 3
|
||||
max-age 40
|
||||
max-object-size 3000
|
||||
|
||||
cache second_cache
|
||||
total-max-size 3
|
||||
max-age 20
|
||||
max-object-size 3072
|
||||
} -start
|
||||
|
||||
|
||||
client c1 -connect ${h1_fe_sock} {
|
||||
txreq -url "/first"
|
||||
rxresp
|
||||
expect resp.status == 200
|
||||
expect resp.bodylen == 45
|
||||
expect resp.http.X-Cache-Hit == 0
|
||||
expect resp.http.X-Cache-Name == ""
|
||||
|
||||
txreq -url "/second"
|
||||
rxresp
|
||||
expect resp.status == 200
|
||||
expect resp.bodylen == 48
|
||||
expect resp.http.X-Cache-Hit == 0
|
||||
expect resp.http.X-Cache-Name == ""
|
||||
|
||||
txreq -url "/nocache"
|
||||
rxresp
|
||||
expect resp.status == 200
|
||||
expect resp.bodylen == 51
|
||||
expect resp.http.X-Cache-Hit == 0
|
||||
expect resp.http.X-Cache-Name == ""
|
||||
|
||||
# Response should come form the cache now
|
||||
txreq -url "/nocache"
|
||||
rxresp
|
||||
expect resp.status == 200
|
||||
expect resp.bodylen == 51
|
||||
expect resp.http.X-Cache-Hit == 0
|
||||
expect resp.http.X-Cache-Name == ""
|
||||
|
||||
txreq -url "/first"
|
||||
rxresp
|
||||
expect resp.status == 200
|
||||
expect resp.bodylen == 45
|
||||
expect resp.http.X-Cache-Hit == 1
|
||||
expect resp.http.X-Cache-Name == "first_cache"
|
||||
|
||||
txreq -url "/second"
|
||||
rxresp
|
||||
expect resp.status == 200
|
||||
expect resp.bodylen == 48
|
||||
expect resp.http.X-Cache-Hit == 1
|
||||
expect resp.http.X-Cache-Name == "second_cache"
|
||||
} -run
|
59
src/cache.c
59
src/cache.c
|
@ -28,6 +28,7 @@
|
|||
#include <haproxy/htx.h>
|
||||
#include <haproxy/net_helper.h>
|
||||
#include <haproxy/proxy.h>
|
||||
#include <haproxy/sample.h>
|
||||
#include <haproxy/shctx.h>
|
||||
#include <haproxy/stream.h>
|
||||
#include <haproxy/stream_interface.h>
|
||||
|
@ -1713,6 +1714,53 @@ static int cli_io_handler_show_cache(struct appctx *appctx)
|
|||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* boolean, returns true if response was built out of a cache entry.
|
||||
*/
|
||||
static int
|
||||
smp_fetch_res_cache_hit(const struct arg *args, struct sample *smp,
|
||||
const char *kw, void *private)
|
||||
{
|
||||
smp->data.type = SMP_T_BOOL;
|
||||
smp->data.u.sint = (smp->strm ? (smp->strm->target == &http_cache_applet.obj_type) : 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* string, returns cache name (if response came from a cache).
|
||||
*/
|
||||
static int
|
||||
smp_fetch_res_cache_name(const struct arg *args, struct sample *smp,
|
||||
const char *kw, void *private)
|
||||
{
|
||||
struct appctx *appctx = NULL;
|
||||
|
||||
struct cache_flt_conf *cconf = NULL;
|
||||
struct cache *cache = NULL;
|
||||
|
||||
if (!smp->strm || smp->strm->target != &http_cache_applet.obj_type)
|
||||
return 0;
|
||||
|
||||
/* Get appctx from the stream_interface. */
|
||||
appctx = si_appctx(&smp->strm->si[1]);
|
||||
if (appctx && appctx->rule) {
|
||||
cconf = appctx->rule->arg.act.p[0];
|
||||
if (cconf) {
|
||||
cache = cconf->c.cache;
|
||||
|
||||
smp->data.type = SMP_T_STR;
|
||||
smp->flags = SMP_F_CONST;
|
||||
smp->data.u.str.area = cache->id;
|
||||
smp->data.u.str.data = strlen(cache->id);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Declare the filter parser for "cache" keyword */
|
||||
static struct flt_kw_list filter_kws = { "CACHE", { }, {
|
||||
{ "cache", parse_cache_flt, NULL },
|
||||
|
@ -1757,3 +1805,14 @@ struct applet http_cache_applet = {
|
|||
/* config parsers for this section */
|
||||
REGISTER_CONFIG_SECTION("cache", cfg_parse_cache, cfg_post_parse_section_cache);
|
||||
REGISTER_POST_CHECK(post_check_cache);
|
||||
|
||||
|
||||
/* Note: must not be declared <const> as its list will be overwritten */
|
||||
static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
|
||||
{ "res.cache_hit", smp_fetch_res_cache_hit, 0, NULL, SMP_T_BOOL, SMP_USE_HRSHP, SMP_VAL_RESPONSE },
|
||||
{ "res.cache_name", smp_fetch_res_cache_name, 0, NULL, SMP_T_STR, SMP_USE_HRSHP, SMP_VAL_RESPONSE },
|
||||
{ /* END */ },
|
||||
}
|
||||
};
|
||||
|
||||
INITCALL1(STG_REGISTER, sample_register_fetches, &sample_fetch_keywords);
|
||||
|
|
Loading…
Reference in New Issue