blob: 325cba6496a84f02ea4cfdd871e5af2b432530f4 [file] [log] [blame]
Willy Tarreaub3cc9f22019-04-19 16:03:32 +02001#include <stdio.h>
2#include <stdarg.h>
3
4#include <common/cfgparse.h>
5#include <common/chunk.h>
6#include <common/buffer.h>
7#include <common/errors.h>
8#include <common/initcall.h>
9#include <types/global.h>
10#include <proto/arg.h>
11#include <proto/log.h>
12#include <proto/proto_http.h>
13#include <proto/sample.h>
14#include <ebsttree.h>
15#include <ebmbtree.h>
16
17#include <wurfl/wurfl.h>
18
19static struct {
20 char *data_file; /* the WURFL data file */
21 char *cache_size; /* the WURFL cache parameters */
Willy Tarreaub3cc9f22019-04-19 16:03:32 +020022 struct list patch_file_list; /* the list of WURFL patch file to use */
23 char information_list_separator; /* the separator used in request to separate values */
24 struct list information_list; /* the list of WURFL data to return into request */
25 void *handle; /* the handle to WURFL engine */
26 struct eb_root btree; /* btree containing info (name/type) on WURFL data to return */
27} global_wurfl = {
28 .data_file = NULL,
29 .cache_size = NULL,
Willy Tarreaub3cc9f22019-04-19 16:03:32 +020030 .information_list_separator = ',',
31 .information_list = LIST_HEAD_INIT(global_wurfl.information_list),
32 .patch_file_list = LIST_HEAD_INIT(global_wurfl.patch_file_list),
33 .handle = NULL,
34};
35
36#ifdef WURFL_DEBUG
37inline static void ha_wurfl_log(char * message, ...)
38{
39 char logbuf[256];
40 va_list argp;
41
42 va_start(argp, message);
43 vsnprintf(logbuf, sizeof(logbuf), message, argp);
44 va_end(argp);
45 send_log(NULL, LOG_NOTICE, logbuf, NULL);
46}
47#else
48inline static void ha_wurfl_log(char * message, ...)
49{
50}
51#endif
52
53#define HA_WURFL_MAX_HEADER_LENGTH 1024
54
55typedef char *(*PROP_CALLBACK_FUNC)(wurfl_handle wHandle, wurfl_device_handle dHandle);
56
57enum wurfl_data_type {
58 HA_WURFL_DATA_TYPE_UNKNOWN = 0,
59 HA_WURFL_DATA_TYPE_CAP = 100,
60 HA_WURFL_DATA_TYPE_VCAP = 200,
61 HA_WURFL_DATA_TYPE_PROPERTY = 300
62};
63
64typedef struct {
65 char *name;
66 enum wurfl_data_type type;
67 PROP_CALLBACK_FUNC func_callback;
68 struct ebmb_node nd;
69} wurfl_data_t;
70
71static const char HA_WURFL_MODULE_VERSION[] = "1.0";
72static const char HA_WURFL_ISDEVROOT_FALSE[] = "FALSE";
73static const char HA_WURFL_ISDEVROOT_TRUE[] = "TRUE";
Willy Tarreaub3cc9f22019-04-19 16:03:32 +020074
75static const char HA_WURFL_DATA_TYPE_UNKNOWN_STRING[] = "unknown";
76static const char HA_WURFL_DATA_TYPE_CAP_STRING[] = "capability";
77static const char HA_WURFL_DATA_TYPE_VCAP_STRING[] = "virtual_capability";
78static const char HA_WURFL_DATA_TYPE_PROPERTY_STRING[] = "property";
79
80static const char *ha_wurfl_retrieve_header(const char *header_name, const void *wh);
81static const char *ha_wurfl_get_wurfl_root_id (wurfl_handle wHandle, wurfl_device_handle dHandle);
82static const char *ha_wurfl_get_wurfl_id (wurfl_handle wHandle, wurfl_device_handle dHandle);
83static const char *ha_wurfl_get_wurfl_isdevroot (wurfl_handle wHandle, wurfl_device_handle dHandle);
84static const char *ha_wurfl_get_wurfl_useragent (wurfl_handle wHandle, wurfl_device_handle dHandle);
85static const char *ha_wurfl_get_wurfl_api_version (wurfl_handle wHandle, wurfl_device_handle dHandle);
86static const char *ha_wurfl_get_wurfl_engine_target (wurfl_handle wHandle, wurfl_device_handle dHandle);
87static const char *ha_wurfl_get_wurfl_info (wurfl_handle wHandle, wurfl_device_handle dHandle);
88static const char *ha_wurfl_get_wurfl_last_load_time (wurfl_handle wHandle, wurfl_device_handle dHandle);
89static const char *ha_wurfl_get_wurfl_normalized_useragent (wurfl_handle wHandle, wurfl_device_handle dHandle);
90static const char *ha_wurfl_get_wurfl_useragent_priority (wurfl_handle wHandle, wurfl_device_handle dHandle);
91static const char *(*ha_wurfl_get_property_callback(char *name)) (wurfl_handle wHandle, wurfl_device_handle dHandle);
92
93// ordered property=>function map, suitable for binary search
94static const struct {
95 const char *name;
96 const char *(*func)(wurfl_handle wHandle, wurfl_device_handle dHandle);
97} wurfl_properties_function_map [] = {
98 {"wurfl_api_version", ha_wurfl_get_wurfl_api_version},
paulborilebad132c2019-04-18 11:57:04 +020099 {"wurfl_engine_target", ha_wurfl_get_wurfl_engine_target}, // kept for backward conf file compat
Willy Tarreaub3cc9f22019-04-19 16:03:32 +0200100 {"wurfl_id", ha_wurfl_get_wurfl_id },
101 {"wurfl_info", ha_wurfl_get_wurfl_info },
102 {"wurfl_isdevroot", ha_wurfl_get_wurfl_isdevroot},
103 {"wurfl_last_load_time", ha_wurfl_get_wurfl_last_load_time},
104 {"wurfl_normalized_useragent", ha_wurfl_get_wurfl_normalized_useragent},
105 {"wurfl_useragent", ha_wurfl_get_wurfl_useragent},
paulborilebad132c2019-04-18 11:57:04 +0200106 {"wurfl_useragent_priority", ha_wurfl_get_wurfl_useragent_priority }, // kept for backward conf file compat
Willy Tarreaub3cc9f22019-04-19 16:03:32 +0200107 {"wurfl_root_id", ha_wurfl_get_wurfl_root_id},
108};
109static const int HA_WURFL_PROPERTIES_NBR = 10;
110
111typedef struct {
112 struct list list;
113 wurfl_data_t data;
114} wurfl_information_t;
115
116typedef struct {
117 struct list list;
118 char *patch_file_path;
119} wurfl_patches_t;
120
121typedef struct {
122 struct sample *wsmp;
123 char header_value[HA_WURFL_MAX_HEADER_LENGTH + 1];
124} ha_wurfl_header_t;
125
126/*
127 * configuration parameters parsing functions
128 */
129static int ha_wurfl_cfg_data_file(char **args, int section_type, struct proxy *curpx,
130 struct proxy *defpx, const char *file, int line,
131 char **err)
132{
133
134 if (*(args[1]) == 0) {
135 memprintf(err, "WURFL: %s expects a value.\n", args[0]);
136 return -1;
137 }
138
139 global_wurfl.data_file = strdup(args[1]);
140 return 0;
141}
142
143static int ha_wurfl_cfg_cache(char **args, int section_type, struct proxy *curpx,
144 struct proxy *defpx, const char *file, int line,
145 char **err)
146{
147 if (*(args[1]) == 0) {
148 memprintf(err, "WURFL: %s expects a value.\n", args[0]);
149 return -1;
150 }
151
152 global_wurfl.cache_size = strdup(args[1]);
153 return 0;
154}
155
156static int ha_wurfl_cfg_engine_mode(char **args, int section_type, struct proxy *curpx,
157 struct proxy *defpx, const char *file, int line,
158 char **err)
159{
paulborilebad132c2019-04-18 11:57:04 +0200160 // kept for backward conf file compat
161 return 0;
Willy Tarreaub3cc9f22019-04-19 16:03:32 +0200162}
163
164static int ha_wurfl_cfg_information_list_separator(char **args, int section_type, struct proxy *curpx,
165 struct proxy *defpx, const char *file, int line,
166 char **err)
167{
168 if (*(args[1]) == 0) {
169 memprintf(err, "WURFL: %s expects a single character.\n", args[0]);
170 return -1;
171 }
172
173 if (strlen(args[1]) > 1) {
174 memprintf(err, "WURFL: %s expects a single character, got %s.\n", args[0], args[1]);
175 return -1;
176 }
177
178 global_wurfl.information_list_separator = *args[1];
179 return 0;
180}
181
182static int ha_wurfl_cfg_information_list(char **args, int section_type, struct proxy *curpx,
183 struct proxy *defpx, const char *file, int line,
184 char **err)
185{
186 int argIdx = 1;
187 wurfl_information_t *wi;
188
189 if (*(args[argIdx]) == 0) {
190 memprintf(err, "WURFL: %s expects a value.\n", args[0]);
191 return -1;
192 }
193
194 while (*(args[argIdx])) {
195 wi = calloc(1, sizeof(*wi));
196
197 if (wi == NULL) {
198 memprintf(err, "WURFL: Error allocating memory for %s element.\n", args[0]);
199 return -1;
200 }
201
202 wi->data.name = strdup(args[argIdx]);
203 wi->data.type = HA_WURFL_DATA_TYPE_UNKNOWN;
204 wi->data.func_callback = NULL;
205 LIST_ADDQ(&global_wurfl.information_list, &wi->list);
206 ++argIdx;
207 }
208
209 return 0;
210}
211
212static int ha_wurfl_cfg_patch_file_list(char **args, int section_type, struct proxy *curpx,
213 struct proxy *defpx, const char *file, int line,
214 char **err)
215{
216 int argIdx = 1;
217 wurfl_patches_t *wp;
218
219 if (*(args[argIdx]) == 0) {
220 memprintf(err, "WURFL: %s expects a value.\n", args[0]);
221 return -1;
222 }
223
224 while (*(args[argIdx])) {
225 wp = calloc(1, sizeof(*wp));
226
227 if (wp == NULL) {
228 memprintf(err, "WURFL: Error allocating memory for %s element.\n", args[0]);
229 return -1;
230 }
231
232 wp->patch_file_path = strdup(args[argIdx]);
233 LIST_ADDQ(&global_wurfl.patch_file_list, &wp->list);
234 ++argIdx;
235 }
236
237 return 0;
238}
239
240static int ha_wurfl_cfg_useragent_priority(char **args, int section_type, struct proxy *curpx,
241 struct proxy *defpx, const char *file, int line,
242 char **err)
243{
paulborilebad132c2019-04-18 11:57:04 +0200244 // this feature is deprecated, keeping only not to break compatibility
245 // with old configuration files.
246 return 0;
Willy Tarreaub3cc9f22019-04-19 16:03:32 +0200247}
248
249/*
250 * module init / deinit functions. Returns 0 if OK, or a combination of ERR_*.
251 */
252
253static int ha_wurfl_init(void)
254{
255 wurfl_information_t *wi;
256 wurfl_patches_t *wp;
257 wurfl_data_t * wn;
258 int wurfl_result_code = WURFL_OK;
259 int len;
260
261 send_log(NULL, LOG_NOTICE, "WURFL: Loading module v.%s\n", HA_WURFL_MODULE_VERSION);
262 // creating WURFL handler
263 global_wurfl.handle = wurfl_create();
264
265 if (global_wurfl.handle == NULL) {
266 ha_warning("WURFL: Engine handler creation failed");
267 send_log(NULL, LOG_WARNING, "WURFL: Engine handler creation failed\n");
268 return ERR_WARN;
269 }
270
271 send_log(NULL, LOG_NOTICE, "WURFL: Engine handler created - API version %s\n", wurfl_get_api_version() );
272
273 // set wurfl data file
274 if (global_wurfl.data_file == NULL) {
275 ha_warning("WURFL: missing wurfl-data-file parameter in global configuration\n");
276 send_log(NULL, LOG_WARNING, "WURFL: missing wurfl-data-file parameter in global configuration\n");
277 return ERR_WARN;
278 }
279
Willy Tarreaub3cc9f22019-04-19 16:03:32 +0200280 if (wurfl_set_root(global_wurfl.handle, global_wurfl.data_file) != WURFL_OK) {
281 ha_warning("WURFL: Engine setting root file failed - %s\n", wurfl_get_error_message(global_wurfl.handle));
282 send_log(NULL, LOG_WARNING, "WURFL: Engine setting root file failed - %s\n", wurfl_get_error_message(global_wurfl.handle));
283 return ERR_WARN;
284 }
285
286 send_log(NULL, LOG_NOTICE, "WURFL: Engine root file set to %s\n", global_wurfl.data_file);
287 // just a log to inform which separator char has to be used
288 send_log(NULL, LOG_NOTICE, "WURFL: Information list separator set to '%c'\n", global_wurfl.information_list_separator);
289
290 // load wurfl data needed ( and filter whose are supposed to be capabilities )
291 if (LIST_ISEMPTY(&global_wurfl.information_list)) {
292 ha_warning("WURFL: missing wurfl-information-list parameter in global configuration\n");
293 send_log(NULL, LOG_WARNING, "WURFL: missing wurfl-information-list parameter in global configuration\n");
294 return ERR_WARN;
295 } else {
296 // ebtree initialization
297 global_wurfl.btree = EB_ROOT;
298
299 // checking if informations are valid WURFL data ( cap, vcaps, properties )
300 list_for_each_entry(wi, &global_wurfl.information_list, list) {
301 // check if information is already loaded looking into btree
302 if (ebst_lookup(&global_wurfl.btree, wi->data.name) == NULL) {
303 if ((wi->data.func_callback = (PROP_CALLBACK_FUNC) ha_wurfl_get_property_callback(wi->data.name)) != NULL) {
304 wi->data.type = HA_WURFL_DATA_TYPE_PROPERTY;
305 ha_wurfl_log("WURFL: [%s] is a valid wurfl data [property]\n",wi->data.name);
306 } else if (wurfl_has_virtual_capability(global_wurfl.handle, wi->data.name)) {
307 wi->data.type = HA_WURFL_DATA_TYPE_VCAP;
308 ha_wurfl_log("WURFL: [%s] is a valid wurfl data [virtual capability]\n",wi->data.name);
309 } else {
310 // by default a cap type is assumed to be and we control it on engine load
311 wi->data.type = HA_WURFL_DATA_TYPE_CAP;
312
313 if (wurfl_add_requested_capability(global_wurfl.handle, wi->data.name) != WURFL_OK) {
314 ha_warning("WURFL: capability filtering failed - %s\n", wurfl_get_error_message(global_wurfl.handle));
315 send_log(NULL, LOG_WARNING, "WURFL: capability filtering failed - %s\n", wurfl_get_error_message(global_wurfl.handle));
316 return ERR_WARN;
317 }
318
319 ha_wurfl_log("WURFL: [%s] treated as wurfl capability. Will check its validity later, on engine load\n",wi->data.name);
320 }
321
322 // ebtree insert here
323 len = strlen(wi->data.name);
324
325 wn = malloc(sizeof(wurfl_data_t) + len + 1);
326
327 if (wn == NULL) {
328 ha_warning("WURFL: Error allocating memory for information tree element.\n");
329 send_log(NULL, LOG_WARNING, "WURFL: Error allocating memory for information tree element.\n");
330 return ERR_WARN;
331 }
332
333 wn->name = wi->data.name;
334 wn->type = wi->data.type;
335 wn->func_callback = wi->data.func_callback;
336 memcpy(wn->nd.key, wi->data.name, len);
337 wn->nd.key[len] = 0;
338
339 if (!ebst_insert(&global_wurfl.btree, &wn->nd)) {
340 ha_warning("WURFL: [%s] not inserted in btree\n",wn->name);
341 send_log(NULL, LOG_WARNING, "WURFL: [%s] not inserted in btree\n",wn->name);
342 return ERR_WARN;
343 }
344
345 } else {
346 ha_wurfl_log("WURFL: [%s] already loaded\n",wi->data.name);
347 }
348
349 }
350
351 }
352
Willy Tarreaub3cc9f22019-04-19 16:03:32 +0200353
354 // adding WURFL patches if needed
355 if (!LIST_ISEMPTY(&global_wurfl.patch_file_list)) {
356
357 list_for_each_entry(wp, &global_wurfl.patch_file_list, list) {
358 if (wurfl_add_patch(global_wurfl.handle, wp->patch_file_path) != WURFL_OK) {
359 ha_warning("WURFL: Engine adding patch file failed - %s\n", wurfl_get_error_message(global_wurfl.handle));
360 send_log(NULL, LOG_WARNING, "WURFL: Adding engine patch file failed - %s\n", wurfl_get_error_message(global_wurfl.handle));
361 return ERR_WARN;
362 }
363 send_log(NULL, LOG_NOTICE, "WURFL: Engine patch file added %s\n", wp->patch_file_path);
364
365 }
366
367 }
368
369 // setting cache provider if specified in cfg, otherwise let engine choose
370 if (global_wurfl.cache_size != NULL) {
371 if (strpbrk(global_wurfl.cache_size, ",") != NULL) {
372 wurfl_result_code = wurfl_set_cache_provider(global_wurfl.handle, WURFL_CACHE_PROVIDER_DOUBLE_LRU, global_wurfl.cache_size) ;
373 } else {
374 if (strcmp(global_wurfl.cache_size, "0")) {
375 wurfl_result_code = wurfl_set_cache_provider(global_wurfl.handle, WURFL_CACHE_PROVIDER_LRU, global_wurfl.cache_size) ;
376 } else {
377 wurfl_result_code = wurfl_set_cache_provider(global_wurfl.handle, WURFL_CACHE_PROVIDER_NONE, 0);
378 }
379
380 }
381
382 if (wurfl_result_code != WURFL_OK) {
383 ha_warning("WURFL: Setting cache to [%s] failed - %s\n", global_wurfl.cache_size, wurfl_get_error_message(global_wurfl.handle));
384 send_log(NULL, LOG_WARNING, "WURFL: Setting cache to [%s] failed - %s\n", global_wurfl.cache_size, wurfl_get_error_message(global_wurfl.handle));
385 return ERR_WARN;
386 }
387
388 send_log(NULL, LOG_NOTICE, "WURFL: Cache set to [%s]\n", global_wurfl.cache_size);
389 }
390
Willy Tarreaub3cc9f22019-04-19 16:03:32 +0200391 // loading WURFL engine
392 if (wurfl_load(global_wurfl.handle) != WURFL_OK) {
393 ha_warning("WURFL: Engine load failed - %s\n", wurfl_get_error_message(global_wurfl.handle));
394 send_log(NULL, LOG_WARNING, "WURFL: Engine load failed - %s\n", wurfl_get_error_message(global_wurfl.handle));
395 return ERR_WARN;
396 }
397
398 send_log(NULL, LOG_NOTICE, "WURFL: Engine loaded\n");
399 send_log(NULL, LOG_NOTICE, "WURFL: Module load completed\n");
400 return 0;
401}
402
403static void ha_wurfl_deinit(void)
404{
405 wurfl_information_t *wi, *wi2;
406 wurfl_patches_t *wp, *wp2;
407
408 send_log(NULL, LOG_NOTICE, "WURFL: Unloading module v.%s\n", HA_WURFL_MODULE_VERSION);
409 wurfl_destroy(global_wurfl.handle);
410 global_wurfl.handle = NULL;
411 free(global_wurfl.data_file);
412 global_wurfl.data_file = NULL;
413 free(global_wurfl.cache_size);
414 global_wurfl.cache_size = NULL;
415
416 list_for_each_entry_safe(wi, wi2, &global_wurfl.information_list, list) {
417 LIST_DEL(&wi->list);
418 free(wi);
419 }
420
421 list_for_each_entry_safe(wp, wp2, &global_wurfl.patch_file_list, list) {
422 LIST_DEL(&wp->list);
423 free(wp);
424 }
425
426 send_log(NULL, LOG_NOTICE, "WURFL: Module unloaded\n");
427}
428
429static int ha_wurfl_get_all(const struct arg *args, struct sample *smp, const char *kw, void *private)
430{
431 wurfl_device_handle dHandle;
432 struct buffer *temp;
433 wurfl_information_t *wi;
434 ha_wurfl_header_t wh;
435
436 ha_wurfl_log("WURFL: starting ha_wurfl_get_all\n");
437 wh.wsmp = smp;
438 dHandle = wurfl_lookup(global_wurfl.handle, &ha_wurfl_retrieve_header, &wh);
439
440 if (!dHandle) {
441 ha_wurfl_log("WURFL: unable to retrieve device from request %s\n", wurfl_get_error_message(global_wurfl.handle));
442 return 1;
443 }
444
445 temp = get_trash_chunk();
446 chunk_reset(temp);
447
448 list_for_each_entry(wi, &global_wurfl.information_list, list) {
449 chunk_appendf(temp, "%c", global_wurfl.information_list_separator);
450
451 switch(wi->data.type) {
452 case HA_WURFL_DATA_TYPE_UNKNOWN :
453 ha_wurfl_log("WURFL: %s is of an %s type\n", wi->data.name, HA_WURFL_DATA_TYPE_UNKNOWN_STRING);
454#ifdef WURFL_HEADER_WITH_DETAILS
455 // write WURFL property type and name before its value...
456 chunk_appendf(temp, "%s=%s", HA_WURFL_DATA_TYPE_UNKNOWN_STRING, wi->data.name);
457#endif
458 break;
459 case HA_WURFL_DATA_TYPE_CAP :
460 ha_wurfl_log("WURFL: %s is a %s\n", wi->data.name, HA_WURFL_DATA_TYPE_CAP_STRING);
461#ifdef WURFL_HEADER_WITH_DETAILS
462 // write WURFL property type and name before its value...
463 chunk_appendf(temp, "%s=%s=", HA_WURFL_DATA_TYPE_CAP_STRING, wi->data.name);
464#endif
465 chunk_appendf(temp, "%s", wurfl_device_get_capability(dHandle, wi->data.name));
466 break;
467 case HA_WURFL_DATA_TYPE_VCAP :
468 ha_wurfl_log("WURFL: %s is a %s\n", wi->data.name, HA_WURFL_DATA_TYPE_VCAP_STRING);
469#ifdef WURFL_HEADER_WITH_DETAILS
470 // write WURFL property type and name before its value...
471 chunk_appendf(temp, "%s=%s=", HA_WURFL_DATA_TYPE_VCAP_STRING, wi->data.name);
472#endif
473 chunk_appendf(temp, "%s", wurfl_device_get_virtual_capability(dHandle, wi->data.name));
474 break;
475 case HA_WURFL_DATA_TYPE_PROPERTY :
476 ha_wurfl_log("WURFL: %s is a %s\n", wi->data.name, HA_WURFL_DATA_TYPE_PROPERTY_STRING);
477#ifdef WURFL_HEADER_WITH_DETAILS
478 // write WURFL property type and name before its value...
479 chunk_appendf(temp, "%s=%s=", HA_WURFL_DATA_TYPE_PROPERTY_STRING, wi->data.name);
480#endif
481 chunk_appendf(temp, "%s", wi->data.func_callback(global_wurfl.handle, dHandle));
482 break;
483 }
484
485 }
486
487 wurfl_device_destroy(dHandle);
488 smp->data.u.str.area = temp->area;
489 smp->data.u.str.data = temp->data;
490 return 1;
491}
492
493static int ha_wurfl_get(const struct arg *args, struct sample *smp, const char *kw, void *private)
494{
495 wurfl_device_handle dHandle;
496 struct buffer *temp;
497 wurfl_data_t *wn = NULL;
498 struct ebmb_node *node;
499 ha_wurfl_header_t wh;
500 int i = 0;
501
502 ha_wurfl_log("WURFL: starting ha_wurfl_get\n");
503 wh.wsmp = smp;
504 dHandle = wurfl_lookup(global_wurfl.handle, &ha_wurfl_retrieve_header, &wh);
505
506 if (!dHandle) {
507 ha_wurfl_log("WURFL: unable to retrieve device from request %s\n", wurfl_get_error_message(global_wurfl.handle));
508 return 1;
509 }
510
511 temp = get_trash_chunk();
512 chunk_reset(temp);
513
514 while (args[i].data.str.area) {
515 chunk_appendf(temp, "%c", global_wurfl.information_list_separator);
516 node = ebst_lookup(&global_wurfl.btree, args[i].data.str.area);
517 wn = container_of(node, wurfl_data_t, nd);
518
519 if (wn) {
520
521 switch(wn->type) {
522 case HA_WURFL_DATA_TYPE_UNKNOWN :
523 ha_wurfl_log("WURFL: %s is of an %s type\n", wn->name, HA_WURFL_DATA_TYPE_UNKNOWN_STRING);
524#ifdef WURFL_HEADER_WITH_DETAILS
525 // write WURFL property type and name before its value...
526 chunk_appendf(temp, "%s=%s", HA_WURFL_DATA_TYPE_UNKNOWN_STRING, wn->name);
527#endif
528 break;
529 case HA_WURFL_DATA_TYPE_CAP :
530 ha_wurfl_log("WURFL: %s is a %s\n", wn->name, HA_WURFL_DATA_TYPE_CAP_STRING);
531#ifdef WURFL_HEADER_WITH_DETAILS
532 // write WURFL property type and name before its value...
533 chunk_appendf(temp, "%s=%s=", HA_WURFL_DATA_TYPE_CAP_STRING, wn->name);
534#endif
535 chunk_appendf(temp, "%s", wurfl_device_get_capability(dHandle, wn->name));
536 break;
537 case HA_WURFL_DATA_TYPE_VCAP :
538 ha_wurfl_log("WURFL: %s is a %s\n", wn->name, HA_WURFL_DATA_TYPE_VCAP_STRING);
539#ifdef WURFL_HEADER_WITH_DETAILS
540 // write WURFL property type and name before its value...
541 chunk_appendf(temp, "%s=%s=", HA_WURFL_DATA_TYPE_VCAP_STRING, wn->name);
542#endif
543 chunk_appendf(temp, "%s", wurfl_device_get_virtual_capability(dHandle, wn->name));
544 break;
545 case HA_WURFL_DATA_TYPE_PROPERTY :
546 ha_wurfl_log("WURFL: %s is a %s\n", wn->name, HA_WURFL_DATA_TYPE_PROPERTY_STRING);
547#ifdef WURFL_HEADER_WITH_DETAILS
548 // write WURFL property type and name before its value...
549 chunk_appendf(temp, "%s=%s=", HA_WURFL_DATA_TYPE_PROPERTY_STRING, wn->name);
550#endif
551 chunk_appendf(temp, "%s", wn->func_callback(global_wurfl.handle, dHandle));
552 break;
553 }
554
555 } else {
556 ha_wurfl_log("WURFL: %s not in wurfl-information-list \n",
557 args[i].data.str.area);
558 }
559
560 i++;
561 }
562
563 wurfl_device_destroy(dHandle);
564 smp->data.u.str.area = temp->area;
565 smp->data.u.str.data = temp->data;
566 return 1;
567}
568
569static struct cfg_kw_list wurflcfg_kws = {{ }, {
570 { CFG_GLOBAL, "wurfl-data-file", ha_wurfl_cfg_data_file },
571 { CFG_GLOBAL, "wurfl-information-list-separator", ha_wurfl_cfg_information_list_separator },
572 { CFG_GLOBAL, "wurfl-information-list", ha_wurfl_cfg_information_list },
573 { CFG_GLOBAL, "wurfl-patch-file", ha_wurfl_cfg_patch_file_list },
574 { CFG_GLOBAL, "wurfl-cache-size", ha_wurfl_cfg_cache },
575 { CFG_GLOBAL, "wurfl-engine-mode", ha_wurfl_cfg_engine_mode },
576 { CFG_GLOBAL, "wurfl-useragent-priority", ha_wurfl_cfg_useragent_priority },
577 { 0, NULL, NULL },
578 }
579};
580
581INITCALL1(STG_REGISTER, cfg_register_keywords, &wurflcfg_kws);
582
583/* Note: must not be declared <const> as its list will be overwritten */
584static struct sample_fetch_kw_list fetch_kws = {ILH, {
585 { "wurfl-get-all", ha_wurfl_get_all, 0, NULL, SMP_T_STR, SMP_USE_HRQHV },
586 { "wurfl-get", ha_wurfl_get, ARG12(1,STR,STR,STR,STR,STR,STR,STR,STR,STR,STR,STR,STR), NULL, SMP_T_STR, SMP_USE_HRQHV },
587 { NULL, NULL, 0, 0, 0 },
588 }
589};
590
591INITCALL1(STG_REGISTER, sample_register_fetches, &fetch_kws);
592
593/* Note: must not be declared <const> as its list will be overwritten */
594static struct sample_conv_kw_list conv_kws = {ILH, {
595 { NULL, NULL, 0, 0, 0 },
596 }
597};
598
599INITCALL1(STG_REGISTER, sample_register_convs, &conv_kws);
600
601// WURFL properties wrapper functions
602static const char *ha_wurfl_get_wurfl_root_id (wurfl_handle wHandle, wurfl_device_handle dHandle)
603{
604 return wurfl_device_get_root_id(dHandle);
605}
606
607static const char *ha_wurfl_get_wurfl_id (wurfl_handle wHandle, wurfl_device_handle dHandle)
608{
609 return wurfl_device_get_id(dHandle);
610}
611
612static const char *ha_wurfl_get_wurfl_isdevroot (wurfl_handle wHandle, wurfl_device_handle dHandle)
613{
614 if (wurfl_device_is_actual_device_root(dHandle))
615 return HA_WURFL_ISDEVROOT_TRUE;
616 else
617 return HA_WURFL_ISDEVROOT_FALSE;
618}
619
620static const char *ha_wurfl_get_wurfl_useragent (wurfl_handle wHandle, wurfl_device_handle dHandle)
621{
622 return wurfl_device_get_original_useragent(dHandle);
623}
624
625static const char *ha_wurfl_get_wurfl_api_version (wurfl_handle wHandle, wurfl_device_handle dHandle)
626{
627 return wurfl_get_api_version();
628}
629
630static const char *ha_wurfl_get_wurfl_engine_target (wurfl_handle wHandle, wurfl_device_handle dHandle)
631{
paulborilebad132c2019-04-18 11:57:04 +0200632 return "default";
Willy Tarreaub3cc9f22019-04-19 16:03:32 +0200633}
634
635static const char *ha_wurfl_get_wurfl_info (wurfl_handle wHandle, wurfl_device_handle dHandle)
636{
637 return wurfl_get_wurfl_info(wHandle);
638}
639
640static const char *ha_wurfl_get_wurfl_last_load_time (wurfl_handle wHandle, wurfl_device_handle dHandle)
641{
642 return wurfl_get_last_load_time_as_string(wHandle);
643}
644
645static const char *ha_wurfl_get_wurfl_normalized_useragent (wurfl_handle wHandle, wurfl_device_handle dHandle)
646{
647 return wurfl_device_get_normalized_useragent(dHandle);
648}
649
650static const char *ha_wurfl_get_wurfl_useragent_priority (wurfl_handle wHandle, wurfl_device_handle dHandle)
651{
paulborilebad132c2019-04-18 11:57:04 +0200652 return "default";
Willy Tarreaub3cc9f22019-04-19 16:03:32 +0200653}
654
655// call function for WURFL properties
656static const char *(*ha_wurfl_get_property_callback(char *name)) (wurfl_handle wHandle, wurfl_device_handle dHandle)
657{
658 int position;
659 int begin = 0;
660 int end = HA_WURFL_PROPERTIES_NBR - 1;
661 int cond = 0;
662
663 while(begin <= end) {
664 position = (begin + end) / 2;
665
666 if((cond = strcmp(wurfl_properties_function_map[position].name, name)) == 0) {
667 ha_wurfl_log("WURFL: ha_wurfl_get_property_callback match %s\n", wurfl_properties_function_map[position].name );
668 return wurfl_properties_function_map[position].func;
669 } else if(cond < 0)
670 begin = position + 1;
671 else
672 end = position - 1;
673
674 }
675
676 return NULL;
677}
678
679static const char *ha_wurfl_retrieve_header(const char *header_name, const void *wh)
680{
681 struct sample *smp;
682 struct hdr_idx *idx;
683 struct hdr_ctx ctx;
684 const struct http_msg *msg;
685 int header_len = HA_WURFL_MAX_HEADER_LENGTH;
686
687 ha_wurfl_log("WURFL: retrieve header request [%s]\n", header_name);
688 smp = ((ha_wurfl_header_t *)wh)->wsmp;
689 idx = &smp->strm->txn->hdr_idx;
690 msg = &smp->strm->txn->req;
691 ctx.idx = 0;
692
paulborile59d50142019-04-17 12:20:42 +0200693 if (http_find_full_header2(header_name, strlen(header_name), ci_head(msg->chn), idx, &ctx) == 0)
Willy Tarreaub3cc9f22019-04-19 16:03:32 +0200694 return 0;
695
696 if (header_len > ctx.vlen)
697 header_len = ctx.vlen;
698
699 strncpy(((ha_wurfl_header_t *)wh)->header_value, ctx.line + ctx.val, header_len);
700 ((ha_wurfl_header_t *)wh)->header_value[header_len] = '\0';
701 ha_wurfl_log("WURFL: retrieve header request returns [%s]\n", ((ha_wurfl_header_t *)wh)->header_value);
702 return ((ha_wurfl_header_t *)wh)->header_value;
703}
704
Willy Tarreaub5188232019-04-19 16:28:53 +0200705static void ha_wurfl_register_build_options()
706{
707 const char *ver = wurfl_get_api_version();
708 char *ptr = NULL;
709
710 memprintf(&ptr, "Built with WURFL support (%sversion %s)",
711 strcmp(ver, "1.11.2.100") ? "" : "dummy library ",
712 ver);
713 hap_register_build_opts(ptr, 1);
714}
715
Willy Tarreaub3cc9f22019-04-19 16:03:32 +0200716REGISTER_POST_CHECK(ha_wurfl_init);
717REGISTER_POST_DEINIT(ha_wurfl_deinit);
Willy Tarreaub5188232019-04-19 16:28:53 +0200718INITCALL0(STG_REGISTER, ha_wurfl_register_build_options);