blob: 969dfaa1ab86cb356381109744d733924cac44aa [file] [log] [blame]
David Carlier8167f302015-06-01 13:50:06 +02001#include <stdio.h>
David Carlier629cbdf2022-01-21 20:51:20 +00002#include <fcntl.h>
3#include <sys/mman.h>
4#include <errno.h>
David Carlier8167f302015-06-01 13:50:06 +02005
Willy Tarreau4c7e4b72020-05-27 12:58:42 +02006#include <haproxy/api.h>
Willy Tarreaub2551052020-06-09 09:07:15 +02007#include <haproxy/arg.h>
Willy Tarreau6be78492020-06-05 00:00:29 +02008#include <haproxy/cfgparse.h>
Willy Tarreau8d366972020-05-27 16:10:29 +02009#include <haproxy/errors.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020010#include <haproxy/global.h>
Willy Tarreaucd72d8c2020-06-02 19:11:26 +020011#include <haproxy/http.h>
Willy Tarreauc2b1ff02020-06-04 21:21:03 +020012#include <haproxy/http_ana.h>
Willy Tarreau126ba3a2020-06-04 18:26:43 +020013#include <haproxy/http_fetch.h>
Willy Tarreau87735332020-06-04 09:08:41 +020014#include <haproxy/http_htx.h>
Willy Tarreauc2b1ff02020-06-04 21:21:03 +020015#include <haproxy/htx.h>
Willy Tarreaue6ce10b2020-06-04 15:33:47 +020016#include <haproxy/sample.h>
Willy Tarreau36979d92020-06-05 17:27:29 +020017#include <haproxy/tools.h>
Willy Tarreaubee9dde2016-12-21 21:25:06 +010018#include <dac.h>
19
David Carlier629cbdf2022-01-21 20:51:20 +000020#define ATLASTOKSZ PATH_MAX
21#define ATLASMAPNM "/hapdeviceatlas"
22
Willy Tarreaubee9dde2016-12-21 21:25:06 +010023static struct {
24 void *atlasimgptr;
David Carlier629cbdf2022-01-21 20:51:20 +000025 void *atlasmap;
Willy Tarreaubee9dde2016-12-21 21:25:06 +010026 char *jsonpath;
27 char *cookiename;
28 size_t cookienamelen;
David Carlier629cbdf2022-01-21 20:51:20 +000029 int atlasfd;
Willy Tarreaubee9dde2016-12-21 21:25:06 +010030 da_atlas_t atlas;
31 da_evidence_id_t useragentid;
32 da_severity_t loglevel;
33 char separator;
34 unsigned char daset:1;
35} global_deviceatlas = {
36 .loglevel = 0,
37 .jsonpath = 0,
38 .cookiename = 0,
39 .cookienamelen = 0,
David Carlier629cbdf2022-01-21 20:51:20 +000040 .atlasmap = NULL,
41 .atlasfd = -1,
Willy Tarreaubee9dde2016-12-21 21:25:06 +010042 .useragentid = 0,
43 .daset = 0,
44 .separator = '|',
45};
David Carlier8167f302015-06-01 13:50:06 +020046
David Carlier629cbdf2022-01-21 20:51:20 +000047__decl_thread(HA_SPINLOCK_T dadwsch_lock);
48
David Carlier8167f302015-06-01 13:50:06 +020049static int da_json_file(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010050 const struct proxy *defpx, const char *file, int line,
David Carlier8167f302015-06-01 13:50:06 +020051 char **err)
52{
53 if (*(args[1]) == 0) {
54 memprintf(err, "deviceatlas json file : expects a json path.\n");
55 return -1;
56 }
Willy Tarreaubee9dde2016-12-21 21:25:06 +010057 global_deviceatlas.jsonpath = strdup(args[1]);
David Carlier8167f302015-06-01 13:50:06 +020058 return 0;
59}
60
61static int da_log_level(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010062 const struct proxy *defpx, const char *file, int line,
David Carlier8167f302015-06-01 13:50:06 +020063 char **err)
64{
65 int loglevel;
66 if (*(args[1]) == 0) {
67 memprintf(err, "deviceatlas log level : expects an integer argument.\n");
68 return -1;
69 }
70
71 loglevel = atol(args[1]);
72 if (loglevel < 0 || loglevel > 3) {
73 memprintf(err, "deviceatlas log level : expects a log level between 0 and 3, %s given.\n", args[1]);
74 } else {
Willy Tarreaubee9dde2016-12-21 21:25:06 +010075 global_deviceatlas.loglevel = (da_severity_t)loglevel;
David Carlier8167f302015-06-01 13:50:06 +020076 }
77
78 return 0;
79}
80
81static int da_property_separator(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010082 const struct proxy *defpx, const char *file, int line,
David Carlier8167f302015-06-01 13:50:06 +020083 char **err)
84{
85 if (*(args[1]) == 0) {
86 memprintf(err, "deviceatlas property separator : expects a character argument.\n");
87 return -1;
88 }
Willy Tarreaubee9dde2016-12-21 21:25:06 +010089 global_deviceatlas.separator = *args[1];
David Carlier8167f302015-06-01 13:50:06 +020090 return 0;
91}
92
David Carlier608c65a2015-09-25 14:16:30 +010093static int da_properties_cookie(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010094 const struct proxy *defpx, const char *file, int line,
David Carlier608c65a2015-09-25 14:16:30 +010095 char **err)
96{
97 if (*(args[1]) == 0) {
98 memprintf(err, "deviceatlas cookie name : expects a string argument.\n");
99 return -1;
100 } else {
Willy Tarreaubee9dde2016-12-21 21:25:06 +0100101 global_deviceatlas.cookiename = strdup(args[1]);
David Carlier608c65a2015-09-25 14:16:30 +0100102 }
Willy Tarreaubee9dde2016-12-21 21:25:06 +0100103 global_deviceatlas.cookienamelen = strlen(global_deviceatlas.cookiename);
David Carlier608c65a2015-09-25 14:16:30 +0100104 return 0;
105}
106
David Carlier8167f302015-06-01 13:50:06 +0200107static size_t da_haproxy_read(void *ctx, size_t len, char *buf)
108{
109 return fread(buf, 1, len, ctx);
110}
111
112static da_status_t da_haproxy_seek(void *ctx, off_t off)
113{
114 return fseek(ctx, off, SEEK_SET) != -1 ? DA_OK : DA_SYS;
115}
116
117static void da_haproxy_log(da_severity_t severity, da_status_t status,
118 const char *fmt, va_list args)
119{
Willy Tarreaubee9dde2016-12-21 21:25:06 +0100120 if (global_deviceatlas.loglevel && severity <= global_deviceatlas.loglevel) {
David Carlier8167f302015-06-01 13:50:06 +0200121 char logbuf[256];
122 vsnprintf(logbuf, sizeof(logbuf), fmt, args);
Christopher Faulet767a84b2017-11-24 16:50:31 +0100123 ha_warning("deviceatlas : %s.\n", logbuf);
David Carlier8167f302015-06-01 13:50:06 +0200124 }
125}
126
David Carlier608c65a2015-09-25 14:16:30 +0100127#define DA_COOKIENAME_DEFAULT "DAPROPS"
128
Willy Tarreau876054d2016-12-21 20:39:16 +0100129/*
130 * module init / deinit functions. Returns 0 if OK, or a combination of ERR_*.
131 */
132static int init_deviceatlas(void)
David Carlier8167f302015-06-01 13:50:06 +0200133{
Christopher Fauletfc633b62020-11-06 15:24:23 +0100134 int err_code = ERR_NONE;
Willy Tarreau876054d2016-12-21 20:39:16 +0100135
Willy Tarreaubee9dde2016-12-21 21:25:06 +0100136 if (global_deviceatlas.jsonpath != 0) {
David Carlier8167f302015-06-01 13:50:06 +0200137 FILE *jsonp;
138 da_property_decl_t extraprops[] = {{0, 0}};
139 size_t atlasimglen;
140 da_status_t status;
141
Willy Tarreaubee9dde2016-12-21 21:25:06 +0100142 jsonp = fopen(global_deviceatlas.jsonpath, "r");
David Carlier8167f302015-06-01 13:50:06 +0200143 if (jsonp == 0) {
Christopher Faulet767a84b2017-11-24 16:50:31 +0100144 ha_alert("deviceatlas : '%s' json file has invalid path or is not readable.\n",
145 global_deviceatlas.jsonpath);
Willy Tarreau876054d2016-12-21 20:39:16 +0100146 err_code |= ERR_ALERT | ERR_FATAL;
David Carlier8167f302015-06-01 13:50:06 +0200147 goto out;
148 }
149
150 da_init();
151 da_seterrorfunc(da_haproxy_log);
152 status = da_atlas_compile(jsonp, da_haproxy_read, da_haproxy_seek,
Willy Tarreaubee9dde2016-12-21 21:25:06 +0100153 &global_deviceatlas.atlasimgptr, &atlasimglen);
David Carlier8167f302015-06-01 13:50:06 +0200154 fclose(jsonp);
155 if (status != DA_OK) {
Christopher Faulet767a84b2017-11-24 16:50:31 +0100156 ha_alert("deviceatlas : '%s' json file is invalid.\n",
157 global_deviceatlas.jsonpath);
Willy Tarreau876054d2016-12-21 20:39:16 +0100158 err_code |= ERR_ALERT | ERR_FATAL;
David Carlier8167f302015-06-01 13:50:06 +0200159 goto out;
160 }
161
Willy Tarreaubee9dde2016-12-21 21:25:06 +0100162 status = da_atlas_open(&global_deviceatlas.atlas, extraprops,
163 global_deviceatlas.atlasimgptr, atlasimglen);
David Carlier8167f302015-06-01 13:50:06 +0200164
165 if (status != DA_OK) {
Christopher Faulet767a84b2017-11-24 16:50:31 +0100166 ha_alert("deviceatlas : data could not be compiled.\n");
Willy Tarreau876054d2016-12-21 20:39:16 +0100167 err_code |= ERR_ALERT | ERR_FATAL;
David Carlier8167f302015-06-01 13:50:06 +0200168 goto out;
169 }
170
Willy Tarreaubee9dde2016-12-21 21:25:06 +0100171 if (global_deviceatlas.cookiename == 0) {
172 global_deviceatlas.cookiename = strdup(DA_COOKIENAME_DEFAULT);
173 global_deviceatlas.cookienamelen = strlen(global_deviceatlas.cookiename);
David Carlier608c65a2015-09-25 14:16:30 +0100174 }
175
Willy Tarreaubee9dde2016-12-21 21:25:06 +0100176 global_deviceatlas.useragentid = da_atlas_header_evidence_id(&global_deviceatlas.atlas,
David Carlier8167f302015-06-01 13:50:06 +0200177 "user-agent");
David Carlier629cbdf2022-01-21 20:51:20 +0000178 if ((global_deviceatlas.atlasfd = shm_open(ATLASMAPNM, O_RDWR, 0660)) != -1) {
179 global_deviceatlas.atlasmap = mmap(NULL, ATLASTOKSZ, PROT_READ | PROT_WRITE, MAP_SHARED, global_deviceatlas.atlasfd, 0);
180 if (global_deviceatlas.atlasmap == MAP_FAILED) {
181 close(global_deviceatlas.atlasfd);
182 global_deviceatlas.atlasfd = -1;
183 global_deviceatlas.atlasmap = NULL;
184 } else {
185 fprintf(stdout, "Deviceatlas : scheduling support enabled.\n");
186 }
187 }
Willy Tarreaubee9dde2016-12-21 21:25:06 +0100188 global_deviceatlas.daset = 1;
David Carlier8167f302015-06-01 13:50:06 +0200189
190 fprintf(stdout, "Deviceatlas module loaded.\n");
191 }
192
193out:
Willy Tarreau876054d2016-12-21 20:39:16 +0100194 return err_code;
David Carlier8167f302015-06-01 13:50:06 +0200195}
196
Willy Tarreaub149eed2016-12-21 21:03:49 +0100197static void deinit_deviceatlas(void)
David Carlier8167f302015-06-01 13:50:06 +0200198{
Willy Tarreaubee9dde2016-12-21 21:25:06 +0100199 if (global_deviceatlas.jsonpath != 0) {
200 free(global_deviceatlas.jsonpath);
David Carlier8167f302015-06-01 13:50:06 +0200201 }
202
Willy Tarreaubee9dde2016-12-21 21:25:06 +0100203 if (global_deviceatlas.daset == 1) {
204 free(global_deviceatlas.cookiename);
205 da_atlas_close(&global_deviceatlas.atlas);
206 free(global_deviceatlas.atlasimgptr);
David Carlier8167f302015-06-01 13:50:06 +0200207 }
208
David Carlier629cbdf2022-01-21 20:51:20 +0000209 if (global_deviceatlas.atlasfd != -1) {
210 munmap(global_deviceatlas.atlasmap, ATLASTOKSZ);
211 close(global_deviceatlas.atlasfd);
212 shm_unlink(ATLASMAPNM);
213 }
214
David Carlier8167f302015-06-01 13:50:06 +0200215 da_fini();
216}
217
David Carlier629cbdf2022-01-21 20:51:20 +0000218static void da_haproxy_checkinst(void)
219{
220 if (global_deviceatlas.atlasmap != 0) {
221 char *base;
222 base = (char *)global_deviceatlas.atlasmap;
223
224 if (base[0] != 0) {
225 void *cnew;
226 size_t atlassz;
227 char atlasp[ATLASTOKSZ] = {0};
228 da_atlas_t inst;
229 da_property_decl_t extraprops[1] = {{NULL, 0}};
230#ifdef USE_THREAD
231 HA_SPIN_LOCK(OTHER_LOCK, &dadwsch_lock);
232#endif
233 strlcpy2(atlasp, base, sizeof(atlasp));
234 if (da_atlas_read_mapped(atlasp, NULL, &cnew, &atlassz) == DA_OK) {
235 if (da_atlas_open(&inst, extraprops, cnew, atlassz) == DA_OK) {
236 char jsonbuf[26];
237 time_t jsond;
238
239 da_atlas_close(&global_deviceatlas.atlas);
240 free(global_deviceatlas.atlasimgptr);
241 global_deviceatlas.atlasimgptr = cnew;
242 global_deviceatlas.atlas = inst;
243 memset(base, 0, ATLASTOKSZ);
244 jsond = da_getdatacreation(&global_deviceatlas.atlas);
245 ctime_r(&jsond, jsonbuf);
246 jsonbuf[24] = 0;
247 printf("deviceatlas: new instance, data file date `%s`.\n", jsonbuf);
248 } else {
249 ha_warning("deviceatlas: instance update failed.\n");
250 memset(base, 0, ATLASTOKSZ);
251 free(cnew);
252 }
253 }
254#ifdef USE_THREAD
255 HA_SPIN_UNLOCK(OTHER_LOCK, &dadwsch_lock);
256#endif
257 }
258 }
259}
260
David Carlier608c65a2015-09-25 14:16:30 +0100261static int da_haproxy(const struct arg *args, struct sample *smp, da_deviceinfo_t *devinfo)
David Carlier8167f302015-06-01 13:50:06 +0200262{
Willy Tarreau83061a82018-07-13 11:56:34 +0200263 struct buffer *tmp;
David Carlier8167f302015-06-01 13:50:06 +0200264 da_propid_t prop, *pprop;
David Carlier8167f302015-06-01 13:50:06 +0200265 da_status_t status;
David Carlier608c65a2015-09-25 14:16:30 +0100266 da_type_t proptype;
267 const char *propname;
David Carlier8167f302015-06-01 13:50:06 +0200268 int i;
269
David Carlier8167f302015-06-01 13:50:06 +0200270 tmp = get_trash_chunk();
271 chunk_reset(tmp);
272
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200273 propname = (const char *) args[0].data.str.area;
David Carlier8167f302015-06-01 13:50:06 +0200274 i = 0;
275
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200276 for (; propname != 0; i ++,
277 propname = (const char *) args[i].data.str.area) {
Willy Tarreaubee9dde2016-12-21 21:25:06 +0100278 status = da_atlas_getpropid(&global_deviceatlas.atlas,
David Carlier8167f302015-06-01 13:50:06 +0200279 propname, &prop);
280 if (status != DA_OK) {
Willy Tarreaubee9dde2016-12-21 21:25:06 +0100281 chunk_appendf(tmp, "%c", global_deviceatlas.separator);
David Carlier8167f302015-06-01 13:50:06 +0200282 continue;
283 }
284 pprop = &prop;
Willy Tarreaubee9dde2016-12-21 21:25:06 +0100285 da_atlas_getproptype(&global_deviceatlas.atlas, *pprop, &proptype);
David Carlier8167f302015-06-01 13:50:06 +0200286
287 switch (proptype) {
288 case DA_TYPE_BOOLEAN: {
289 bool val;
David Carlier608c65a2015-09-25 14:16:30 +0100290 status = da_getpropboolean(devinfo, *pprop, &val);
David Carlier8167f302015-06-01 13:50:06 +0200291 if (status == DA_OK) {
292 chunk_appendf(tmp, "%d", val);
293 }
294 break;
295 }
296 case DA_TYPE_INTEGER:
297 case DA_TYPE_NUMBER: {
298 long val;
David Carlier608c65a2015-09-25 14:16:30 +0100299 status = da_getpropinteger(devinfo, *pprop, &val);
David Carlier8167f302015-06-01 13:50:06 +0200300 if (status == DA_OK) {
301 chunk_appendf(tmp, "%ld", val);
302 }
303 break;
304 }
305 case DA_TYPE_STRING: {
306 const char *val;
David Carlier608c65a2015-09-25 14:16:30 +0100307 status = da_getpropstring(devinfo, *pprop, &val);
David Carlier8167f302015-06-01 13:50:06 +0200308 if (status == DA_OK) {
309 chunk_appendf(tmp, "%s", val);
310 }
311 break;
David Carlier608c65a2015-09-25 14:16:30 +0100312 }
David Carlier8167f302015-06-01 13:50:06 +0200313 default:
314 break;
315 }
316
Willy Tarreaubee9dde2016-12-21 21:25:06 +0100317 chunk_appendf(tmp, "%c", global_deviceatlas.separator);
David Carlier8167f302015-06-01 13:50:06 +0200318 }
319
David Carlier608c65a2015-09-25 14:16:30 +0100320 da_close(devinfo);
David Carlier8167f302015-06-01 13:50:06 +0200321
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200322 if (tmp->data) {
323 --tmp->data;
324 tmp->area[tmp->data] = 0;
David Carlier8167f302015-06-01 13:50:06 +0200325 }
326
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200327 smp->data.u.str.area = tmp->area;
328 smp->data.u.str.data = tmp->data;
David Carlier7df41852019-07-10 21:19:24 +0100329 smp->data.type = SMP_T_STR;
David Carlier8167f302015-06-01 13:50:06 +0200330
331 return 1;
332}
333
David Carlier608c65a2015-09-25 14:16:30 +0100334static int da_haproxy_conv(const struct arg *args, struct sample *smp, void *private)
335{
336 da_deviceinfo_t devinfo;
337 da_status_t status;
338 const char *useragent;
339 char useragentbuf[1024] = { 0 };
340 int i;
341
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200342 if (global_deviceatlas.daset == 0 || smp->data.u.str.data == 0) {
David Carlier608c65a2015-09-25 14:16:30 +0100343 return 1;
344 }
345
David Carlier629cbdf2022-01-21 20:51:20 +0000346 da_haproxy_checkinst();
347
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200348 i = smp->data.u.str.data > sizeof(useragentbuf) ? sizeof(useragentbuf) : smp->data.u.str.data;
349 memcpy(useragentbuf, smp->data.u.str.area, i - 1);
David Carlier608c65a2015-09-25 14:16:30 +0100350 useragentbuf[i - 1] = 0;
351
352 useragent = (const char *)useragentbuf;
353
Willy Tarreaubee9dde2016-12-21 21:25:06 +0100354 status = da_search(&global_deviceatlas.atlas, &devinfo,
355 global_deviceatlas.useragentid, useragent, 0);
David Carlier608c65a2015-09-25 14:16:30 +0100356
357 return status != DA_OK ? 0 : da_haproxy(args, smp, &devinfo);
358}
359
360#define DA_MAX_HEADERS 24
361
362static int da_haproxy_fetch(const struct arg *args, struct sample *smp, const char *kw, void *private)
363{
David Carlier608c65a2015-09-25 14:16:30 +0100364 da_evidence_t ev[DA_MAX_HEADERS];
365 da_deviceinfo_t devinfo;
366 da_status_t status;
David CARLIER4de0eba2019-04-24 20:41:53 +0100367 struct channel *chn;
Christopher Faulet6d1dd462019-07-15 14:36:03 +0200368 struct htx *htx;
369 struct htx_blk *blk;
David Carlier608c65a2015-09-25 14:16:30 +0100370 char vbuf[DA_MAX_HEADERS][1024] = {{ 0 }};
371 int i, nbh = 0;
372
Willy Tarreaubee9dde2016-12-21 21:25:06 +0100373 if (global_deviceatlas.daset == 0) {
David CARLIER4de0eba2019-04-24 20:41:53 +0100374 return 0;
David Carlier608c65a2015-09-25 14:16:30 +0100375 }
376
David Carlier629cbdf2022-01-21 20:51:20 +0000377 da_haproxy_checkinst();
378
David CARLIER4de0eba2019-04-24 20:41:53 +0100379 chn = (smp->strm ? &smp->strm->req : NULL);
Christopher Fauletd1185cc2020-05-05 11:49:57 +0200380 htx = smp_prefetch_htx(smp, chn, NULL, 1);
Christopher Faulet6d1dd462019-07-15 14:36:03 +0200381 if (!htx)
382 return 0;
David Carlier608c65a2015-09-25 14:16:30 +0100383
Christopher Faulet6d1dd462019-07-15 14:36:03 +0200384 i = 0;
385 for (blk = htx_get_first_blk(htx); nbh < DA_MAX_HEADERS && blk; blk = htx_get_next_blk(htx, blk)) {
386 size_t vlen;
387 char *pval;
388 da_evidence_id_t evid;
389 enum htx_blk_type type;
390 struct ist n, v;
391 char hbuf[24] = { 0 };
392 char tval[1024] = { 0 };
David Carlier608c65a2015-09-25 14:16:30 +0100393
Christopher Faulet6d1dd462019-07-15 14:36:03 +0200394 type = htx_get_blk_type(blk);
David Carlier608c65a2015-09-25 14:16:30 +0100395
Christopher Faulet6d1dd462019-07-15 14:36:03 +0200396 if (type == HTX_BLK_HDR) {
397 n = htx_get_blk_name(htx, blk);
398 v = htx_get_blk_value(htx, blk);
399 } else if (type == HTX_BLK_EOH) {
400 break;
401 } else {
402 continue;
403 }
David Carlier608c65a2015-09-25 14:16:30 +0100404
Christopher Faulet6d1dd462019-07-15 14:36:03 +0200405 /* The HTTP headers used by the DeviceAtlas API are not longer */
406 if (n.len >= sizeof(hbuf)) {
407 continue;
David Carlier608c65a2015-09-25 14:16:30 +0100408 }
409
Christopher Faulet6d1dd462019-07-15 14:36:03 +0200410 memcpy(hbuf, n.ptr, n.len);
411 hbuf[n.len] = 0;
412 pval = v.ptr;
413 vlen = v.len;
414 evid = -1;
415 i = v.len > sizeof(tval) - 1 ? sizeof(tval) - 1 : v.len;
416 memcpy(tval, v.ptr, i);
417 tval[i] = 0;
418 pval = tval;
David CARLIER4de0eba2019-04-24 20:41:53 +0100419
Christopher Faulet6d1dd462019-07-15 14:36:03 +0200420 if (strcasecmp(hbuf, "Accept-Language") == 0) {
421 evid = da_atlas_accept_language_evidence_id(&global_deviceatlas.atlas);
422 } else if (strcasecmp(hbuf, "Cookie") == 0) {
423 char *p, *eval;
424 size_t pl;
David CARLIER4de0eba2019-04-24 20:41:53 +0100425
Christopher Faulet6d1dd462019-07-15 14:36:03 +0200426 eval = pval + vlen;
427 /**
428 * The cookie value, if it exists, is located between the current header's
429 * value position and the next one
430 */
431 if (http_extract_cookie_value(pval, eval, global_deviceatlas.cookiename,
432 global_deviceatlas.cookienamelen, 1, &p, &pl) == NULL) {
David CARLIER4de0eba2019-04-24 20:41:53 +0100433 continue;
434 }
435
Christopher Faulet6d1dd462019-07-15 14:36:03 +0200436 vlen -= global_deviceatlas.cookienamelen - 1;
437 pval = p;
438 evid = da_atlas_clientprop_evidence_id(&global_deviceatlas.atlas);
439 } else {
440 evid = da_atlas_header_evidence_id(&global_deviceatlas.atlas, hbuf);
441 }
David CARLIER4de0eba2019-04-24 20:41:53 +0100442
Christopher Faulet6d1dd462019-07-15 14:36:03 +0200443 if (evid == -1) {
444 continue;
David CARLIER4de0eba2019-04-24 20:41:53 +0100445 }
Christopher Faulet6d1dd462019-07-15 14:36:03 +0200446
447 i = vlen > sizeof(vbuf[nbh]) - 1 ? sizeof(vbuf[nbh]) - 1 : vlen;
448 memcpy(vbuf[nbh], pval, i);
449 vbuf[nbh][i] = 0;
450 ev[nbh].key = evid;
451 ev[nbh].value = vbuf[nbh];
452 ++ nbh;
David Carlier608c65a2015-09-25 14:16:30 +0100453 }
454
Willy Tarreaubee9dde2016-12-21 21:25:06 +0100455 status = da_searchv(&global_deviceatlas.atlas, &devinfo,
David Carlier608c65a2015-09-25 14:16:30 +0100456 ev, nbh);
457
458 return status != DA_OK ? 0 : da_haproxy(args, smp, &devinfo);
459}
460
Willy Tarreau0d74f772015-06-01 15:42:29 +0200461static struct cfg_kw_list dacfg_kws = {{ }, {
462 { CFG_GLOBAL, "deviceatlas-json-file", da_json_file },
David CARLIER4de0eba2019-04-24 20:41:53 +0100463 { CFG_GLOBAL, "deviceatlas-log-level", da_log_level },
464 { CFG_GLOBAL, "deviceatlas-property-separator", da_property_separator },
465 { CFG_GLOBAL, "deviceatlas-properties-cookie", da_properties_cookie },
466 { 0, NULL, NULL },
Willy Tarreau0d74f772015-06-01 15:42:29 +0200467}};
468
Willy Tarreau0108d902018-11-25 19:14:37 +0100469INITCALL1(STG_REGISTER, cfg_register_keywords, &dacfg_kws);
470
Willy Tarreauf63386a2015-06-01 15:39:50 +0200471/* Note: must not be declared <const> as its list will be overwritten */
David Carlier608c65a2015-09-25 14:16:30 +0100472static struct sample_fetch_kw_list fetch_kws = {ILH, {
David Carlier840b0242016-03-16 10:09:55 +0000473 { "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 },
David CARLIER4de0eba2019-04-24 20:41:53 +0100474 { NULL, NULL, 0, 0, 0 },
David Carlier608c65a2015-09-25 14:16:30 +0100475}};
476
Willy Tarreau0108d902018-11-25 19:14:37 +0100477INITCALL1(STG_REGISTER, sample_register_fetches, &fetch_kws);
478
David Carlier608c65a2015-09-25 14:16:30 +0100479/* Note: must not be declared <const> as its list will be overwritten */
Willy Tarreauf63386a2015-06-01 15:39:50 +0200480static struct sample_conv_kw_list conv_kws = {ILH, {
David Carlier840b0242016-03-16 10:09:55 +0000481 { "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 },
David CARLIER4de0eba2019-04-24 20:41:53 +0100482 { NULL, NULL, 0, 0, 0 },
Willy Tarreauf63386a2015-06-01 15:39:50 +0200483}};
484
David Carlier0470d702019-04-26 12:02:28 +0000485static void da_haproxy_register_build_options()
486{
487 char *ptr = NULL;
488
489#ifdef MOBI_DA_DUMMY_LIBRARY
490 memprintf(&ptr, "Built with DeviceAtlas support (dummy library only).");
491#else
492 memprintf(&ptr, "Built with DeviceAtlas support (library version %u.%u).", MOBI_DA_MAJOR, MOBI_DA_MINOR);
493#endif
494 hap_register_build_opts(ptr, 1);
495}
496
Willy Tarreau0108d902018-11-25 19:14:37 +0100497INITCALL1(STG_REGISTER, sample_register_convs, &conv_kws);
498
Willy Tarreau172f5ce2018-11-26 11:21:50 +0100499REGISTER_POST_CHECK(init_deviceatlas);
500REGISTER_POST_DEINIT(deinit_deviceatlas);
David Carlier0470d702019-04-26 12:02:28 +0000501INITCALL0(STG_REGISTER, da_haproxy_register_build_options);