Hi All. Here attached you may find a set of patches related to WURFL module.
Patches from 0001 to 0004 should implements Christopher's last suggestions/issues. - segfault when I try to retrieve an unknown data (I mean not listed in wurfl-information-list). - the channel validity must be checked calling the macro CHECK_HTTP_MESSAGE_FIRST(). - the function ha_wurfl_retrieve_header() is not HTX aware - It could be cool to call ha_wurfl_retrieve_header() from the dummy library, in wurfl_lookup(). Patches from 0005 to 0008 corrects some small issues found during this activity. Thank you in advance for your feedback. ( ...and thank you Willy for your clarifications on send_log() ) Regards -Max -- Massimiliano Bellomi Senior Software Engineer Scientiamobile Italy - massimili...@scientiamobile.com +39 338 6990288 Milano Office : +39 02 620227260 skype: massimiliano.bellomi
From fab346cee058d443c32d010a3f6ad0a864ebf82d Mon Sep 17 00:00:00 2001 From: mbellomi <massimili...@scientiamobile.com> Date: Thu, 9 May 2019 16:36:12 +0200 Subject: [PATCH 1/8] BUG/MEDIUM WURFL fixed segfault in reference to information not present in wurfl-information-list --- src/wurfl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wurfl.c b/src/wurfl.c index 325cba64..a53209c8 100644 --- a/src/wurfl.c +++ b/src/wurfl.c @@ -514,9 +514,9 @@ static int ha_wurfl_get(const struct arg *args, struct sample *smp, const char * while (args[i].data.str.area) { chunk_appendf(temp, "%c", global_wurfl.information_list_separator); node = ebst_lookup(&global_wurfl.btree, args[i].data.str.area); - wn = container_of(node, wurfl_data_t, nd); - if (wn) { + if (node) { + wn = container_of(node, wurfl_data_t, nd); switch(wn->type) { case HA_WURFL_DATA_TYPE_UNKNOWN : -- 2.17.1
From 028b5e4bf5ae4f179e87be5734f319abf6715181 Mon Sep 17 00:00:00 2001 From: mbellomi <massimili...@scientiamobile.com> Date: Mon, 13 May 2019 15:33:44 +0200 Subject: [PATCH 2/8] MINOR WURFL checks channel validity in fetch functions --- src/wurfl.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/wurfl.c b/src/wurfl.c index a53209c8..40ea1b53 100644 --- a/src/wurfl.c +++ b/src/wurfl.c @@ -10,6 +10,7 @@ #include <proto/arg.h> #include <proto/log.h> #include <proto/proto_http.h> +#include <proto/http_fetch.h> #include <proto/sample.h> #include <ebsttree.h> #include <ebmbtree.h> @@ -433,6 +434,9 @@ static int ha_wurfl_get_all(const struct arg *args, struct sample *smp, const ch wurfl_information_t *wi; ha_wurfl_header_t wh; + struct channel *chn = (smp->strm ? &smp->strm->req : NULL); + CHECK_HTTP_MESSAGE_FIRST(chn); + ha_wurfl_log("WURFL: starting ha_wurfl_get_all\n"); wh.wsmp = smp; dHandle = wurfl_lookup(global_wurfl.handle, &ha_wurfl_retrieve_header, &wh); @@ -487,6 +491,7 @@ static int ha_wurfl_get_all(const struct arg *args, struct sample *smp, const ch wurfl_device_destroy(dHandle); smp->data.u.str.area = temp->area; smp->data.u.str.data = temp->data; + smp->data.type = SMP_T_STR; return 1; } @@ -499,6 +504,9 @@ static int ha_wurfl_get(const struct arg *args, struct sample *smp, const char * ha_wurfl_header_t wh; int i = 0; + struct channel *chn = (smp->strm ? &smp->strm->req : NULL); + CHECK_HTTP_MESSAGE_FIRST(chn); + ha_wurfl_log("WURFL: starting ha_wurfl_get\n"); wh.wsmp = smp; dHandle = wurfl_lookup(global_wurfl.handle, &ha_wurfl_retrieve_header, &wh); @@ -563,6 +571,7 @@ static int ha_wurfl_get(const struct arg *args, struct sample *smp, const char * wurfl_device_destroy(dHandle); smp->data.u.str.area = temp->area; smp->data.u.str.data = temp->data; + smp->data.type = SMP_T_STR; return 1; } -- 2.17.1
From 08295dec46f256332bb6f49d5ab28f4e9f77e41f Mon Sep 17 00:00:00 2001 From: mbellomi <massimili...@scientiamobile.com> Date: Mon, 13 May 2019 15:40:53 +0200 Subject: [PATCH 3/8] MINOR WURFL makes ha_wurfl_retrieve_header() HTX aware --- src/wurfl.c | 67 +++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 55 insertions(+), 12 deletions(-) diff --git a/src/wurfl.c b/src/wurfl.c index 40ea1b53..c6fb26eb 100644 --- a/src/wurfl.c +++ b/src/wurfl.c @@ -11,6 +11,7 @@ #include <proto/log.h> #include <proto/proto_http.h> #include <proto/http_fetch.h> +#include <proto/http_htx.h> #include <proto/sample.h> #include <ebsttree.h> #include <ebmbtree.h> @@ -688,25 +689,67 @@ static const char *(*ha_wurfl_get_property_callback(char *name)) (wurfl_handle w static const char *ha_wurfl_retrieve_header(const char *header_name, const void *wh) { struct sample *smp; - struct hdr_idx *idx; - struct hdr_ctx ctx; - const struct http_msg *msg; + struct channel *chn; int header_len = HA_WURFL_MAX_HEADER_LENGTH; - ha_wurfl_log("WURFL: retrieve header request [%s]\n", header_name); smp = ((ha_wurfl_header_t *)wh)->wsmp; - idx = &smp->strm->txn->hdr_idx; - msg = &smp->strm->txn->req; - ctx.idx = 0; + chn = (smp->strm ? &smp->strm->req : NULL); - if (http_find_full_header2(header_name, strlen(header_name), ci_head(msg->chn), idx, &ctx) == 0) - return 0; + if (smp->px->options2 & PR_O2_USE_HTX) { + /* HTX version */ + struct htx *htx; + struct http_hdr_ctx ctx; + struct ist name; - if (header_len > ctx.vlen) - header_len = ctx.vlen; + ha_wurfl_log("WURFL: retrieve header (HTX) request [%s]\n", header_name); + + //the header is searched from the beginning + ctx.blk = NULL; + + htx = smp_prefetch_htx(smp, chn, 1); + if (!htx) { + return 0; + } + + name.ptr = (char *)header_name; + name.len = strlen(header_name); + + // If 4th param is set, it works on full-line headers in whose comma is not a delimiter but is + // part of the syntax + if (!http_find_header(htx, name, &ctx, 1)) { + return 0; + } + + if (header_len > ctx.value.len) + header_len = ctx.value.len; + + strncpy(((ha_wurfl_header_t *)wh)->header_value, ctx.value.ptr, header_len); + + } else { + /* Legacy version */ + struct http_txn *txn; + struct hdr_idx *idx; + struct hdr_ctx ctx; + + ha_wurfl_log("WURFL: retrieve header (legacy) request [%s]\n", header_name); + + txn = smp->strm->txn; + idx = &txn->hdr_idx; + + ctx.idx = 0; + + if (http_find_full_header2(header_name, strlen(header_name), ci_head(chn), idx, &ctx) == 0) + return 0; + + if (header_len > ctx.vlen) + header_len = ctx.vlen; + + strncpy(((ha_wurfl_header_t *)wh)->header_value, ctx.line + ctx.val, header_len); + + } - strncpy(((ha_wurfl_header_t *)wh)->header_value, ctx.line + ctx.val, header_len); ((ha_wurfl_header_t *)wh)->header_value[header_len] = '\0'; + ha_wurfl_log("WURFL: retrieve header request returns [%s]\n", ((ha_wurfl_header_t *)wh)->header_value); return ((ha_wurfl_header_t *)wh)->header_value; } -- 2.17.1
From f15462a92a7ebf964381bc9f8f1594291bf1eccb Mon Sep 17 00:00:00 2001 From: mbellomi <massimili...@scientiamobile.com> Date: Mon, 13 May 2019 15:51:49 +0200 Subject: [PATCH 4/8] MINOR WURFL calls header_retrieve_callback from within dummy library --- contrib/wurfl/dummy-wurfl.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/contrib/wurfl/dummy-wurfl.c b/contrib/wurfl/dummy-wurfl.c index c87d9b95..8de59d09 100644 --- a/contrib/wurfl/dummy-wurfl.c +++ b/contrib/wurfl/dummy-wurfl.c @@ -67,6 +67,10 @@ wurfl_error wurfl_load(wurfl_handle hwurfl) wurfl_device_handle wurfl_lookup(wurfl_handle hwurfl, wurfl_header_retrieve_callback header_retrieve_callback, const void *header_retrieve_callback_data) { + // call callback, on a probably existing header + const char *hvalue = header_retrieve_callback("User-Agent", header_retrieve_callback_data); + // and on a non existing one + hvalue = header_retrieve_callback("Non-Existing-Header", header_retrieve_callback_data); return (void *) 0xdeffa; } -- 2.17.1
From c59108126c54d0fcb486a2a7e4ecb791156dbc76 Mon Sep 17 00:00:00 2001 From: mbellomi <massimili...@scientiamobile.com> Date: Mon, 13 May 2019 16:56:53 +0200 Subject: [PATCH 5/8] MINOR WURFL fixed engine load failed error when wurfl-information-list contains wurfl_root_id --- src/wurfl.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/wurfl.c b/src/wurfl.c index c6fb26eb..38008fde 100644 --- a/src/wurfl.c +++ b/src/wurfl.c @@ -104,9 +104,9 @@ static const struct { {"wurfl_isdevroot", ha_wurfl_get_wurfl_isdevroot}, {"wurfl_last_load_time", ha_wurfl_get_wurfl_last_load_time}, {"wurfl_normalized_useragent", ha_wurfl_get_wurfl_normalized_useragent}, + {"wurfl_root_id", ha_wurfl_get_wurfl_root_id}, {"wurfl_useragent", ha_wurfl_get_wurfl_useragent}, {"wurfl_useragent_priority", ha_wurfl_get_wurfl_useragent_priority }, // kept for backward conf file compat - {"wurfl_root_id", ha_wurfl_get_wurfl_root_id}, }; static const int HA_WURFL_PROPERTIES_NBR = 10; @@ -611,7 +611,10 @@ INITCALL1(STG_REGISTER, sample_register_convs, &conv_kws); // WURFL properties wrapper functions static const char *ha_wurfl_get_wurfl_root_id (wurfl_handle wHandle, wurfl_device_handle dHandle) { - return wurfl_device_get_root_id(dHandle); + if (wurfl_device_get_root_id(dHandle)) + return wurfl_device_get_root_id(dHandle); + else + return ""; } static const char *ha_wurfl_get_wurfl_id (wurfl_handle wHandle, wurfl_device_handle dHandle) -- 2.17.1
From 4c96e1e30aa8086ffa6f3cb12ae13d0a537e22fe Mon Sep 17 00:00:00 2001 From: mbellomi <massimili...@scientiamobile.com> Date: Mon, 13 May 2019 17:21:18 +0200 Subject: [PATCH 6/8] MINOR WURFL shows log messages during module initialization --- src/wurfl.c | 44 ++++++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/src/wurfl.c b/src/wurfl.c index 38008fde..fad05120 100644 --- a/src/wurfl.c +++ b/src/wurfl.c @@ -70,7 +70,7 @@ typedef struct { struct ebmb_node nd; } wurfl_data_t; -static const char HA_WURFL_MODULE_VERSION[] = "1.0"; +static const char HA_WURFL_MODULE_VERSION[] = "1.1"; static const char HA_WURFL_ISDEVROOT_FALSE[] = "FALSE"; static const char HA_WURFL_ISDEVROOT_TRUE[] = "TRUE"; @@ -260,39 +260,35 @@ static int ha_wurfl_init(void) int wurfl_result_code = WURFL_OK; int len; - send_log(NULL, LOG_NOTICE, "WURFL: Loading module v.%s\n", HA_WURFL_MODULE_VERSION); + ha_notice("WURFL: Loading module v.%s\n", HA_WURFL_MODULE_VERSION); // creating WURFL handler global_wurfl.handle = wurfl_create(); if (global_wurfl.handle == NULL) { - ha_warning("WURFL: Engine handler creation failed"); - send_log(NULL, LOG_WARNING, "WURFL: Engine handler creation failed\n"); + ha_warning("WURFL: Engine handler creation failed\n"); return ERR_WARN; } - send_log(NULL, LOG_NOTICE, "WURFL: Engine handler created - API version %s\n", wurfl_get_api_version() ); + ha_notice("WURFL: Engine handler created - API version %s\n", wurfl_get_api_version() ); // set wurfl data file if (global_wurfl.data_file == NULL) { ha_warning("WURFL: missing wurfl-data-file parameter in global configuration\n"); - send_log(NULL, LOG_WARNING, "WURFL: missing wurfl-data-file parameter in global configuration\n"); return ERR_WARN; } if (wurfl_set_root(global_wurfl.handle, global_wurfl.data_file) != WURFL_OK) { ha_warning("WURFL: Engine setting root file failed - %s\n", wurfl_get_error_message(global_wurfl.handle)); - send_log(NULL, LOG_WARNING, "WURFL: Engine setting root file failed - %s\n", wurfl_get_error_message(global_wurfl.handle)); return ERR_WARN; } - send_log(NULL, LOG_NOTICE, "WURFL: Engine root file set to %s\n", global_wurfl.data_file); + ha_notice("WURFL: Engine root file set to %s\n", global_wurfl.data_file); // just a log to inform which separator char has to be used - send_log(NULL, LOG_NOTICE, "WURFL: Information list separator set to '%c'\n", global_wurfl.information_list_separator); + ha_notice("WURFL: Information list separator set to '%c'\n", global_wurfl.information_list_separator); // load wurfl data needed ( and filter whose are supposed to be capabilities ) if (LIST_ISEMPTY(&global_wurfl.information_list)) { ha_warning("WURFL: missing wurfl-information-list parameter in global configuration\n"); - send_log(NULL, LOG_WARNING, "WURFL: missing wurfl-information-list parameter in global configuration\n"); return ERR_WARN; } else { // ebtree initialization @@ -304,21 +300,24 @@ static int ha_wurfl_init(void) if (ebst_lookup(&global_wurfl.btree, wi->data.name) == NULL) { if ((wi->data.func_callback = (PROP_CALLBACK_FUNC) ha_wurfl_get_property_callback(wi->data.name)) != NULL) { wi->data.type = HA_WURFL_DATA_TYPE_PROPERTY; - ha_wurfl_log("WURFL: [%s] is a valid wurfl data [property]\n",wi->data.name); +#ifdef WURFL_DEBUG + ha_notice("WURFL: [%s] is a valid wurfl data [property]\n",wi->data.name); +#endif } else if (wurfl_has_virtual_capability(global_wurfl.handle, wi->data.name)) { wi->data.type = HA_WURFL_DATA_TYPE_VCAP; - ha_wurfl_log("WURFL: [%s] is a valid wurfl data [virtual capability]\n",wi->data.name); +#ifdef WURFL_DEBUG + ha_notice("WURFL: [%s] is a valid wurfl data [virtual capability]\n",wi->data.name); +#endif } else { // by default a cap type is assumed to be and we control it on engine load wi->data.type = HA_WURFL_DATA_TYPE_CAP; if (wurfl_add_requested_capability(global_wurfl.handle, wi->data.name) != WURFL_OK) { ha_warning("WURFL: capability filtering failed - %s\n", wurfl_get_error_message(global_wurfl.handle)); - send_log(NULL, LOG_WARNING, "WURFL: capability filtering failed - %s\n", wurfl_get_error_message(global_wurfl.handle)); return ERR_WARN; } - ha_wurfl_log("WURFL: [%s] treated as wurfl capability. Will check its validity later, on engine load\n",wi->data.name); + ha_notice("WURFL: [%s] treated as wurfl capability. Will check its validity later, on engine load\n",wi->data.name); } // ebtree insert here @@ -328,7 +327,6 @@ static int ha_wurfl_init(void) if (wn == NULL) { ha_warning("WURFL: Error allocating memory for information tree element.\n"); - send_log(NULL, LOG_WARNING, "WURFL: Error allocating memory for information tree element.\n"); return ERR_WARN; } @@ -340,12 +338,13 @@ static int ha_wurfl_init(void) if (!ebst_insert(&global_wurfl.btree, &wn->nd)) { ha_warning("WURFL: [%s] not inserted in btree\n",wn->name); - send_log(NULL, LOG_WARNING, "WURFL: [%s] not inserted in btree\n",wn->name); return ERR_WARN; } } else { - ha_wurfl_log("WURFL: [%s] already loaded\n",wi->data.name); +#ifdef WURFL_DEBUG + ha_notice("WURFL: [%s] already loaded\n",wi->data.name); +#endif } } @@ -359,10 +358,9 @@ static int ha_wurfl_init(void) list_for_each_entry(wp, &global_wurfl.patch_file_list, list) { if (wurfl_add_patch(global_wurfl.handle, wp->patch_file_path) != WURFL_OK) { ha_warning("WURFL: Engine adding patch file failed - %s\n", wurfl_get_error_message(global_wurfl.handle)); - send_log(NULL, LOG_WARNING, "WURFL: Adding engine patch file failed - %s\n", wurfl_get_error_message(global_wurfl.handle)); return ERR_WARN; } - send_log(NULL, LOG_NOTICE, "WURFL: Engine patch file added %s\n", wp->patch_file_path); + ha_notice("WURFL: Engine patch file added %s\n", wp->patch_file_path); } @@ -383,22 +381,20 @@ static int ha_wurfl_init(void) if (wurfl_result_code != WURFL_OK) { ha_warning("WURFL: Setting cache to [%s] failed - %s\n", global_wurfl.cache_size, wurfl_get_error_message(global_wurfl.handle)); - send_log(NULL, LOG_WARNING, "WURFL: Setting cache to [%s] failed - %s\n", global_wurfl.cache_size, wurfl_get_error_message(global_wurfl.handle)); return ERR_WARN; } - send_log(NULL, LOG_NOTICE, "WURFL: Cache set to [%s]\n", global_wurfl.cache_size); + ha_notice("WURFL: Cache set to [%s]\n", global_wurfl.cache_size); } // loading WURFL engine if (wurfl_load(global_wurfl.handle) != WURFL_OK) { ha_warning("WURFL: Engine load failed - %s\n", wurfl_get_error_message(global_wurfl.handle)); - send_log(NULL, LOG_WARNING, "WURFL: Engine load failed - %s\n", wurfl_get_error_message(global_wurfl.handle)); return ERR_WARN; } - send_log(NULL, LOG_NOTICE, "WURFL: Engine loaded\n"); - send_log(NULL, LOG_NOTICE, "WURFL: Module load completed\n"); + ha_notice("WURFL: Engine loaded\n"); + ha_notice("WURFL: Module load completed\n"); return 0; } -- 2.17.1
From 84f96a37e65c064da202cda354ce35cd3938d2b5 Mon Sep 17 00:00:00 2001 From: mbellomi <massimili...@scientiamobile.com> Date: Mon, 13 May 2019 17:56:23 +0200 Subject: [PATCH 7/8] MINOR WURFL removes heading separator from resulting headers --- src/wurfl.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/wurfl.c b/src/wurfl.c index fad05120..ea2ac928 100644 --- a/src/wurfl.c +++ b/src/wurfl.c @@ -447,7 +447,6 @@ static int ha_wurfl_get_all(const struct arg *args, struct sample *smp, const ch chunk_reset(temp); list_for_each_entry(wi, &global_wurfl.information_list, list) { - chunk_appendf(temp, "%c", global_wurfl.information_list_separator); switch(wi->data.type) { case HA_WURFL_DATA_TYPE_UNKNOWN : @@ -483,11 +482,21 @@ static int ha_wurfl_get_all(const struct arg *args, struct sample *smp, const ch break; } + // append separator + chunk_appendf(temp, "%c", global_wurfl.information_list_separator); + } wurfl_device_destroy(dHandle); smp->data.u.str.area = temp->area; smp->data.u.str.data = temp->data; + + // remove trailing separator + if (temp->data) { + temp->area[temp->data] = '\0'; + --smp->data.u.str.data; + } + smp->data.type = SMP_T_STR; return 1; } @@ -517,7 +526,6 @@ static int ha_wurfl_get(const struct arg *args, struct sample *smp, const char * chunk_reset(temp); while (args[i].data.str.area) { - chunk_appendf(temp, "%c", global_wurfl.information_list_separator); node = ebst_lookup(&global_wurfl.btree, args[i].data.str.area); if (node) { @@ -557,6 +565,9 @@ static int ha_wurfl_get(const struct arg *args, struct sample *smp, const char * break; } + // append separator + chunk_appendf(temp, "%c", global_wurfl.information_list_separator); + } else { ha_wurfl_log("WURFL: %s not in wurfl-information-list \n", args[i].data.str.area); @@ -568,6 +579,13 @@ static int ha_wurfl_get(const struct arg *args, struct sample *smp, const char * wurfl_device_destroy(dHandle); smp->data.u.str.area = temp->area; smp->data.u.str.data = temp->data; + + // remove trailing separator + if (temp->data) { + temp->area[temp->data] = '\0'; + --smp->data.u.str.data; + } + smp->data.type = SMP_T_STR; return 1; } -- 2.17.1
From 486b11f5d9fe7ad89b1699471cd6ba297fea295d Mon Sep 17 00:00:00 2001 From: mbellomi <massimili...@scientiamobile.com> Date: Mon, 13 May 2019 18:02:19 +0200 Subject: [PATCH 8/8] MINOR WURFL returns empty header if unable to obtain wurfl device descriptor --- src/wurfl.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/wurfl.c b/src/wurfl.c index ea2ac928..43239f50 100644 --- a/src/wurfl.c +++ b/src/wurfl.c @@ -435,17 +435,18 @@ static int ha_wurfl_get_all(const struct arg *args, struct sample *smp, const ch CHECK_HTTP_MESSAGE_FIRST(chn); ha_wurfl_log("WURFL: starting ha_wurfl_get_all\n"); + wh.wsmp = smp; + temp = get_trash_chunk(); + chunk_reset(temp); + dHandle = wurfl_lookup(global_wurfl.handle, &ha_wurfl_retrieve_header, &wh); if (!dHandle) { ha_wurfl_log("WURFL: unable to retrieve device from request %s\n", wurfl_get_error_message(global_wurfl.handle)); - return 1; + goto wurfl_get_all_completed; } - temp = get_trash_chunk(); - chunk_reset(temp); - list_for_each_entry(wi, &global_wurfl.information_list, list) { switch(wi->data.type) { @@ -487,6 +488,8 @@ static int ha_wurfl_get_all(const struct arg *args, struct sample *smp, const ch } +wurfl_get_all_completed: + wurfl_device_destroy(dHandle); smp->data.u.str.area = temp->area; smp->data.u.str.data = temp->data; @@ -514,17 +517,18 @@ static int ha_wurfl_get(const struct arg *args, struct sample *smp, const char * CHECK_HTTP_MESSAGE_FIRST(chn); ha_wurfl_log("WURFL: starting ha_wurfl_get\n"); + wh.wsmp = smp; + temp = get_trash_chunk(); + chunk_reset(temp); + dHandle = wurfl_lookup(global_wurfl.handle, &ha_wurfl_retrieve_header, &wh); if (!dHandle) { ha_wurfl_log("WURFL: unable to retrieve device from request %s\n", wurfl_get_error_message(global_wurfl.handle)); - return 1; + goto wurfl_get_completed; } - temp = get_trash_chunk(); - chunk_reset(temp); - while (args[i].data.str.area) { node = ebst_lookup(&global_wurfl.btree, args[i].data.str.area); @@ -576,6 +580,8 @@ static int ha_wurfl_get(const struct arg *args, struct sample *smp, const char * i++; } +wurfl_get_completed: + wurfl_device_destroy(dHandle); smp->data.u.str.area = temp->area; smp->data.u.str.data = temp->data; -- 2.17.1