#include <common/cfgparse.h>
#include <proto/arg.h>
#include <proto/log.h>
+#include <proto/proto_http.h>
#include <proto/sample.h>
#include <import/da.h>
return 0;
}
+static int da_properties_cookie(char **args, int section_type, struct proxy *curpx,
+ struct proxy *defpx, const char *file, int line,
+ char **err)
+{
+ if (*(args[1]) == 0) {
+ memprintf(err, "deviceatlas cookie name : expects a string argument.\n");
+ return -1;
+ } else {
+ global.deviceatlas.cookiename = strdup(args[1]);
+ }
+ global.deviceatlas.cookienamelen = strlen(global.deviceatlas.cookiename);
+ return 0;
+}
+
static size_t da_haproxy_read(void *ctx, size_t len, char *buf)
{
return fread(buf, 1, len, ctx);
}
}
+#define DA_COOKIENAME_DEFAULT "DAPROPS"
+
int init_deviceatlas(void)
{
da_status_t status = DA_SYS;
goto out;
}
+ if (global.deviceatlas.cookiename == 0) {
+ global.deviceatlas.cookiename = strdup(DA_COOKIENAME_DEFAULT);
+ global.deviceatlas.cookienamelen = strlen(global.deviceatlas.cookiename);
+ }
+
global.deviceatlas.useragentid = da_atlas_header_evidence_id(&global.deviceatlas.atlas,
"user-agent");
+ global.deviceatlas.daset = 1;
fprintf(stdout, "Deviceatlas module loaded.\n");
}
free(global.deviceatlas.jsonpath);
}
- if (global.deviceatlas.useragentid > 0) {
+ if (global.deviceatlas.daset == 1) {
+ free(global.deviceatlas.cookiename);
da_atlas_close(&global.deviceatlas.atlas);
free(global.deviceatlas.atlasimgptr);
}
da_fini();
}
-static int da_haproxy(const struct arg *args, struct sample *smp, void *private)
+static int da_haproxy(const struct arg *args, struct sample *smp, da_deviceinfo_t *devinfo)
{
struct chunk *tmp;
- da_deviceinfo_t devinfo;
da_propid_t prop, *pprop;
- da_type_t proptype;
da_status_t status;
- const char *useragent, *propname;
- char useragentbuf[1024];
+ da_type_t proptype;
+ const char *propname;
int i;
- if (global.deviceatlas.useragentid == 0) {
- return 1;
- }
-
tmp = get_trash_chunk();
chunk_reset(tmp);
- i = smp->data.u.str.len > sizeof(useragentbuf) ? sizeof(useragentbuf) : smp->data.u.str.len;
- memcpy(useragentbuf, smp->data.u.str.str, i - 1);
- useragentbuf[i - 1] = 0;
-
- useragent = (const char *)useragentbuf;
propname = (const char *)args[0].data.str.str;
i = 0;
- status = da_search(&global.deviceatlas.atlas, &devinfo,
- global.deviceatlas.useragentid, useragent, 0);
- if (status != DA_OK) {
- return 0;
- }
-
for (; propname != 0; i ++, propname = (const char *)args[i].data.str.str) {
status = da_atlas_getpropid(&global.deviceatlas.atlas,
propname, &prop);
switch (proptype) {
case DA_TYPE_BOOLEAN: {
bool val;
- status = da_getpropboolean(&devinfo, *pprop, &val);
+ status = da_getpropboolean(devinfo, *pprop, &val);
if (status == DA_OK) {
chunk_appendf(tmp, "%d", val);
}
case DA_TYPE_INTEGER:
case DA_TYPE_NUMBER: {
long val;
- status = da_getpropinteger(&devinfo, *pprop, &val);
+ status = da_getpropinteger(devinfo, *pprop, &val);
if (status == DA_OK) {
chunk_appendf(tmp, "%ld", val);
}
}
case DA_TYPE_STRING: {
const char *val;
- status = da_getpropstring(&devinfo, *pprop, &val);
+ status = da_getpropstring(devinfo, *pprop, &val);
if (status == DA_OK) {
chunk_appendf(tmp, "%s", val);
}
break;
- }
+ }
default:
break;
}
chunk_appendf(tmp, "%c", global.deviceatlas.separator);
}
- da_close(&devinfo);
+ da_close(devinfo);
if (tmp->len) {
--tmp->len;
}
smp->data.u.str.str = tmp->str;
- smp->data.u.str.len = strlen(tmp->str);
+ smp->data.u.str.len = tmp->len;
return 1;
}
+static int da_haproxy_conv(const struct arg *args, struct sample *smp, void *private)
+{
+ da_deviceinfo_t devinfo;
+ da_status_t status;
+ const char *useragent;
+ char useragentbuf[1024] = { 0 };
+ int i;
+
+ if (global.deviceatlas.daset == 0) {
+ return 1;
+ }
+
+ i = smp->data.u.str.len > sizeof(useragentbuf) ? sizeof(useragentbuf) : smp->data.u.str.len;
+ memcpy(useragentbuf, smp->data.u.str.str, i - 1);
+ useragentbuf[i - 1] = 0;
+
+ useragent = (const char *)useragentbuf;
+
+ status = da_search(&global.deviceatlas.atlas, &devinfo,
+ global.deviceatlas.useragentid, useragent, 0);
+
+ return status != DA_OK ? 0 : da_haproxy(args, smp, &devinfo);
+}
+
+#define DA_MAX_HEADERS 24
+
+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;
+ char vbuf[DA_MAX_HEADERS][1024] = {{ 0 }};
+ int i, nbh = 0;
+
+ if (global.deviceatlas.daset == 0) {
+ return 1;
+ }
+
+ CHECK_HTTP_MESSAGE_FIRST();
+ 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(hmsg->chn->buf->p, 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)) {
+ 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;
+ int 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 (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];
+ ev[nbh].value[vlen] = 0;
+ ++ nbh;
+ }
+
+ status = da_searchv(&global.deviceatlas.atlas, &devinfo,
+ ev, nbh);
+
+ return status != DA_OK ? 0 : da_haproxy(args, smp, &devinfo);
+}
+
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 },
}};
+/* 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, ARG5(1,STR,STR,STR,STR,STR), NULL, SMP_T_STR, SMP_USE_HRQHV },
+ { NULL, NULL, 0, 0, 0 },
+}};
+
/* Note: must not be declared <const> as its list will be overwritten */
static struct sample_conv_kw_list conv_kws = {ILH, {
- { "da-csv", da_haproxy, ARG5(1,STR,STR,STR,STR,STR), NULL, SMP_T_STR, SMP_T_STR },
+ { "da-csv-conv", da_haproxy_conv, ARG5(1,STR,STR,STR,STR,STR), NULL, SMP_T_STR, SMP_T_STR },
{ NULL, NULL, 0, 0, 0 },
}};
static void __da_init(void)
{
/* register sample fetch and format conversion keywords */
+ sample_register_fetches(&fetch_kws);
sample_register_convs(&conv_kws);
cfg_register_keywords(&dacfg_kws);
}