MEDIUM: da: HTX mode support.

The DeviceAtlas module now can support both the legacy
mode and the new HTX's with the known set of support headers
for the latter.
This commit is contained in:
David CARLIER 2019-04-24 20:41:53 +01:00 committed by Willy Tarreau
parent 0470d704a7
commit 4de0eba848
1 changed files with 147 additions and 65 deletions

212
src/da.c
View File

@ -7,6 +7,7 @@
#include <types/global.h>
#include <proto/arg.h>
#include <proto/http_fetch.h>
#include <proto/http_htx.h>
#include <proto/log.h>
#include <proto/proto_http.h>
#include <proto/sample.h>
@ -285,83 +286,164 @@ static int da_haproxy_conv(const struct arg *args, struct sample *smp, void *pri
static int da_haproxy_fetch(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
struct hdr_idx *hidx;
struct hdr_ctx hctx;
const struct http_msg *hmsg;
da_evidence_t ev[DA_MAX_HEADERS];
da_deviceinfo_t devinfo;
da_status_t status;
struct channel *chn;
char vbuf[DA_MAX_HEADERS][1024] = {{ 0 }};
int i, nbh = 0;
if (global_deviceatlas.daset == 0) {
return 1;
return 0;
}
CHECK_HTTP_MESSAGE_FIRST((smp->strm ? &smp->strm->req : NULL));
smp->data.type = SMP_T_STR;
/**
* Here we go through the whole list of headers from start
* they will be filtered via the DeviceAtlas API itself
*/
hctx.idx = 0;
hidx = &smp->strm->txn->hdr_idx;
hmsg = &smp->strm->txn->req;
while (http_find_next_header(ci_head(hmsg->chn), hidx, &hctx) == 1 &&
nbh < DA_MAX_HEADERS) {
char *pval;
size_t vlen;
da_evidence_id_t evid = -1;
char hbuf[24] = { 0 };
/* The HTTP headers used by the DeviceAtlas API are not longer */
if (hctx.del >= sizeof(hbuf) || hctx.del <= 0 || hctx.vlen <= 0) {
continue;
chn = (smp->strm ? &smp->strm->req : NULL);
/* HTX Mode check */
if (smp->px->options2 & PR_O2_USE_HTX) {
struct htx_blk *blk;
struct htx *htx = smp_prefetch_htx(smp, chn, 1);
if (!htx) {
return 0;
}
vlen = hctx.vlen;
memcpy(hbuf, hctx.line, hctx.del);
hbuf[hctx.del] = 0;
pval = (hctx.line + hctx.val);
i = 0;
for (blk = htx_get_head_blk(htx); nbh < DA_MAX_HEADERS && blk; blk = htx_get_next_blk(htx, blk)) {
size_t vlen;
char *pval;
da_evidence_id_t evid;
enum htx_blk_type type;
struct ist n, v;
char hbuf[24] = { 0 };
char tval[1024] = { 0 };
if (strcmp(hbuf, "Accept-Language") == 0) {
evid = da_atlas_accept_language_evidence_id(&global_deviceatlas.
atlas);
} else if (strcmp(hbuf, "Cookie") == 0) {
char *p, *eval;
size_t pl;
type = htx_get_blk_type(blk);
eval = pval + hctx.vlen;
/**
* The cookie value, if it exists, is located between the current header's
* value position and the next one
*/
if (http_extract_cookie_value(pval, eval, global_deviceatlas.cookiename,
global_deviceatlas.cookienamelen, 1, &p, &pl) == NULL) {
if (type == HTX_BLK_HDR) {
n = htx_get_blk_name(htx, blk);
v = htx_get_blk_value(htx, blk);
} else if (type == HTX_BLK_EOH) {
break;
} else {
continue;
}
vlen = (size_t)pl;
pval = p;
evid = da_atlas_clientprop_evidence_id(&global_deviceatlas.atlas);
} else {
evid = da_atlas_header_evidence_id(&global_deviceatlas.atlas,
hbuf);
}
/* The HTTP headers used by the DeviceAtlas API are not longer */
if (n.len >= sizeof(hbuf)) {
continue;
}
if (evid == -1) {
continue;
}
memcpy(hbuf, n.ptr, n.len);
hbuf[n.len] = 0;
pval = v.ptr;
vlen = v.len;
evid = -1;
i = v.len > sizeof(tval) - 1 ? sizeof(tval) - 1 : v.len;
memcpy(tval, v.ptr, i);
tval[i] = 0;
pval = tval;
i = vlen > sizeof(vbuf[nbh]) ? sizeof(vbuf[nbh]) : vlen;
memcpy(vbuf[nbh], pval, i - 1);
vbuf[nbh][i - 1] = 0;
ev[nbh].key = evid;
ev[nbh].value = vbuf[nbh];
ev[nbh].value[vlen] = 0;
++ nbh;
if (strcasecmp(hbuf, "Accept-Language") == 0) {
evid = da_atlas_accept_language_evidence_id(&global_deviceatlas.atlas);
} else if (strcasecmp(hbuf, "Cookie") == 0) {
char *p, *eval;
size_t pl;
eval = pval + vlen;
/**
* The cookie value, if it exists, is located between the current header's
* value position and the next one
*/
if (http_extract_cookie_value(pval, eval, global_deviceatlas.cookiename,
global_deviceatlas.cookienamelen, 1, &p, &pl) == NULL) {
continue;
}
vlen -= global_deviceatlas.cookienamelen - 1;
pval = p;
evid = da_atlas_clientprop_evidence_id(&global_deviceatlas.atlas);
} else {
evid = da_atlas_header_evidence_id(&global_deviceatlas.atlas, hbuf);
}
if (evid == -1) {
continue;
}
i = vlen > sizeof(vbuf[nbh]) - 1 ? sizeof(vbuf[nbh]) - 1 : vlen;
memcpy(vbuf[nbh], pval, i);
vbuf[nbh][i] = 0;
ev[nbh].key = evid;
ev[nbh].value = vbuf[nbh];
++ nbh;
}
} else {
struct hdr_idx *hidx;
struct hdr_ctx hctx;
const struct http_msg *hmsg;
CHECK_HTTP_MESSAGE_FIRST(chn);
smp->data.type = SMP_T_STR;
/**
* Here we go through the whole list of headers from start
* they will be filtered via the DeviceAtlas API itself
*/
hctx.idx = 0;
hidx = &smp->strm->txn->hdr_idx;
hmsg = &smp->strm->txn->req;
while (http_find_next_header(ci_head(hmsg->chn), hidx, &hctx) == 1 &&
nbh < DA_MAX_HEADERS) {
char *pval;
size_t vlen;
da_evidence_id_t evid = -1;
char hbuf[24] = { 0 };
/* The HTTP headers used by the DeviceAtlas API are not longer */
if (hctx.del >= sizeof(hbuf) || hctx.del <= 0 || hctx.vlen <= 0) {
continue;
}
vlen = hctx.vlen;
memcpy(hbuf, hctx.line, hctx.del);
hbuf[hctx.del] = 0;
pval = (hctx.line + hctx.val);
if (strcmp(hbuf, "Accept-Language") == 0) {
evid = da_atlas_accept_language_evidence_id(&global_deviceatlas.
atlas);
} else if (strcmp(hbuf, "Cookie") == 0) {
char *p, *eval;
size_t pl;
eval = pval + hctx.vlen;
/**
* The cookie value, if it exists, is located between the current header's
* value position and the next one
*/
if (http_extract_cookie_value(pval, eval, global_deviceatlas.cookiename,
global_deviceatlas.cookienamelen, 1, &p, &pl) == NULL) {
continue;
}
vlen = (size_t)pl;
pval = p;
evid = da_atlas_clientprop_evidence_id(&global_deviceatlas.atlas);
} else {
evid = da_atlas_header_evidence_id(&global_deviceatlas.atlas,
hbuf);
}
if (evid == -1) {
continue;
}
i = vlen > sizeof(vbuf[nbh]) ? sizeof(vbuf[nbh]) : vlen;
memcpy(vbuf[nbh], pval, i - 1);
vbuf[nbh][i - 1] = 0;
ev[nbh].key = evid;
ev[nbh].value = vbuf[nbh];
++ nbh;
}
}
status = da_searchv(&global_deviceatlas.atlas, &devinfo,
@ -372,10 +454,10 @@ static int da_haproxy_fetch(const struct arg *args, struct sample *smp, const ch
static struct cfg_kw_list dacfg_kws = {{ }, {
{ CFG_GLOBAL, "deviceatlas-json-file", da_json_file },
{ CFG_GLOBAL, "deviceatlas-log-level", da_log_level },
{ CFG_GLOBAL, "deviceatlas-property-separator", da_property_separator },
{ CFG_GLOBAL, "deviceatlas-properties-cookie", da_properties_cookie },
{ 0, NULL, NULL },
{ CFG_GLOBAL, "deviceatlas-log-level", da_log_level },
{ CFG_GLOBAL, "deviceatlas-property-separator", da_property_separator },
{ CFG_GLOBAL, "deviceatlas-properties-cookie", da_properties_cookie },
{ 0, NULL, NULL },
}};
INITCALL1(STG_REGISTER, cfg_register_keywords, &dacfg_kws);
@ -383,7 +465,7 @@ INITCALL1(STG_REGISTER, cfg_register_keywords, &dacfg_kws);
/* Note: must not be declared <const> as its list will be overwritten */
static struct sample_fetch_kw_list fetch_kws = {ILH, {
{ "da-csv-fetch", da_haproxy_fetch, ARG12(1,STR,STR,STR,STR,STR,STR,STR,STR,STR,STR,STR,STR), NULL, SMP_T_STR, SMP_USE_HRQHV },
{ NULL, NULL, 0, 0, 0 },
{ NULL, NULL, 0, 0, 0 },
}};
INITCALL1(STG_REGISTER, sample_register_fetches, &fetch_kws);
@ -391,7 +473,7 @@ INITCALL1(STG_REGISTER, sample_register_fetches, &fetch_kws);
/* Note: must not be declared <const> as its list will be overwritten */
static struct sample_conv_kw_list conv_kws = {ILH, {
{ "da-csv-conv", da_haproxy_conv, ARG12(1,STR,STR,STR,STR,STR,STR,STR,STR,STR,STR,STR,STR), NULL, SMP_T_STR, SMP_T_STR },
{ NULL, NULL, 0, 0, 0 },
{ NULL, NULL, 0, 0, 0 },
}};
static void da_haproxy_register_build_options()