diff --git a/INSTALL b/INSTALL index 8086d1548..cf3f1dfbb 100644 --- a/INSTALL +++ b/INSTALL @@ -320,7 +320,6 @@ following files : doc/DeviceAtlas-device-detection.txt for DeviceAtlas doc/51Degrees-device-detection.txt for 51Degrees - doc/WURFL-device-detection.txt for Scientiamobile WURFL 4.9) Miscellaneous diff --git a/Makefile b/Makefile index 6c19d3dfe..0ab190295 100644 --- a/Makefile +++ b/Makefile @@ -46,7 +46,6 @@ # USE_RT : enable it if your system requires -lrt. Automatic on Linux. # USE_DEVICEATLAS : enable DeviceAtlas api. # USE_51DEGREES : enable third party device detection library from 51Degrees -# USE_WURFL : enable WURFL detection library from Scientiamobile # USE_SYSTEMD : enable sd_notify() support. # # Options can be forced by specifying "USE_xxx=1" or can be disabled by using @@ -753,24 +752,6 @@ BUILD_OPTIONS += $(call ignore_implicit,USE_51DEGREES) OPTIONS_LDFLAGS += $(if $(51DEGREES_LIB),-L$(51DEGREES_LIB)) -lm endif -ifneq ($(USE_WURFL),) -# Use WURFL_SRC and possibly WURFL_INC and WURFL_LIB to force path -# to WURFL headers and libraries if needed. -WURFL_SRC = -WURFL_INC = $(WURFL_SRC) -WURFL_LIB = $(WURFL_SRC) -OPTIONS_OBJS += src/wurfl.o -OPTIONS_CFLAGS += -DUSE_WURFL $(if $(WURFL_INC),-I$(WURFL_INC)) -ifneq ($(WURFL_DEBUG),) -OPTIONS_CFLAGS += -DWURFL_DEBUG -endif -ifneq ($(WURFL_HEADER_WITH_DETAILS),) -OPTIONS_CFLAGS += -DWURFL_HEADER_WITH_DETAILS -endif -BUILD_OPTIONS += $(call ignore_implicit,USE_WURFL) -OPTIONS_LDFLAGS += $(if $(WURFL_LIB),-L$(WURFL_LIB)) -lwurfl -endif - ifneq ($(USE_SYSTEMD),) BUILD_OPTIONS += $(call ignore_implicit,USE_SYSTEMD) OPTIONS_CFLAGS += -DUSE_SYSTEMD diff --git a/doc/WURFL-device-detection.txt b/doc/WURFL-device-detection.txt deleted file mode 100644 index c96861513..000000000 --- a/doc/WURFL-device-detection.txt +++ /dev/null @@ -1,68 +0,0 @@ -Scientiamobile WURFL Device Detection -------------------------------------- - -You can also include WURFL for inbuilt device detection enabling attributes. - -WURFL is a high-performance and low-memory footprint mobile device detection -software component that can quickly and accurately detect over 500 capabilities -of visiting devices. It can differentiate between portable mobile devices, desktop devices, -SmartTVs and any other types of devices on which a web browser can be installed. - -In order to add WURFL device detection support, you would need to download Scientiamobile -InFuze C API and install it on your system. Refer to www.scientiamobile.com to obtain a valid -InFuze license. -Compile haproxy as shown : - - $ make TARGET=<target> USE_WURFL=1 - -Optionally WURFL_DEBUG=1 may be set to increase logs verbosity - -These are the supported WURFL directives (see doc/configuration.txt) : -- wurfl-data-file <path to WURFL data file> -- wurfl-information-list [<string>] (list of WURFL capabilities, - virtual capabilities, property names we plan to use in injected headers) -- wurfl-information-list-separator <char> (character that will be - used to separate values in a response header, ',' by default). -- wurfl-engine-mode <string> (Sets the WURFL engine target. You can choose - between "accuracy" and "performance","performance" by default) -- wurfl-cache-size <string> (Sets the WURFL caching strategy) -- wurfl-patch-file [<file path>] (Sets the paths to custom WURFL patch files) - -Sample configuration : - - global - wurfl-data-file /usr/share/wurfl/wurfl-eval.xml - - wurfl-information-list wurfl_id model_name - - #wurfl-information-list-separator | - - wurfl-engine-mode performance - #wurfl-engine-mode accuracy - - ## double LRU cache - wurfl-cache-size 100000,30000 - ## single LRU cache - #wurfl-cache-size 100000 - ## no cache - #wurfl-cache-size 0 - - #wurfl-patch-file <paths to custom patch files> - - ... - frontend - bind *:8888 - default_backend servers - -There are two distinct methods available to transmit the WURFL data downstream -to the target application: - -All data listed in wurfl-information-list - - http-request set-header X-WURFL-All %[wurfl-get-all()] - -A subset of data listed in wurfl-information-list - - http-request set-header X-WURFL-Properties %[wurfl-get(wurfl_id,is_tablet)] - -Please find more information about WURFL and the detection methods at https://www.scientiamobile.com diff --git a/doc/configuration.txt b/doc/configuration.txt index ab09e8367..4a671e479 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -596,12 +596,6 @@ The following keywords are supported in the "global" section : - 51degrees-property-name-list - 51degrees-property-separator - 51degrees-cache-size - - wurfl-data-file - - wurfl-information-list - - wurfl-information-list-separator - - wurfl-engine-mode - - wurfl-cache-size - - wurfl-useragent-priority * Performance tuning - max-spread-checks @@ -1217,95 +1211,6 @@ description <text> Please note that this option is only available when haproxy has been compiled with USE_51DEGREES. -wurfl-data-file <file path> - The path of the WURFL data file to provide device detection services. The - file should be accessible by HAProxy with relevant permissions. - - Please note that this option is only available when haproxy has been compiled - with USE_WURFL=1. - -wurfl-information-list [<capability>]* - A space-delimited list of WURFL capabilities, virtual capabilities, property - names we plan to use in injected headers. A full list of capability and - virtual capability names is available on the Scientiamobile website : - - https://www.scientiamobile.com/wurflCapability - - Valid WURFL properties are: - - wurfl_id Contains the device ID of the matched device. - - - wurfl_root_id Contains the device root ID of the matched - device. - - - wurfl_isdevroot Tells if the matched device is a root device. - Possible values are "TRUE" or "FALSE". - - - wurfl_useragent The original useragent coming with this - particular web request. - - - wurfl_api_version Contains a string representing the currently - used Libwurfl API version. - - - wurfl_engine_target Contains a string representing the currently - set WURFL Engine Target. Possible values are - "HIGH_ACCURACY", "HIGH_PERFORMANCE", "INVALID". - - - wurfl_info A string containing information on the parsed - wurfl.xml and its full path. - - - wurfl_last_load_time Contains the UNIX timestamp of the last time - WURFL has been loaded successfully. - - - wurfl_normalized_useragent The normalized useragent. - - - wurfl_useragent_priority The user agent priority used by WURFL. - - Please note that this option is only available when haproxy has been compiled - with USE_WURFL=1. - -wurfl-information-list-separator <char> - A char that will be used to separate values in a response header containing - WURFL results. If not set that a comma (',') will be used by default. - - Please note that this option is only available when haproxy has been compiled - with USE_WURFL=1. - -wurfl-patch-file [<file path>] - A list of WURFL patch file paths. Note that patches are loaded during startup - thus before the chroot. - - Please note that this option is only available when haproxy has been compiled - with USE_WURFL=1. - -wurfl-engine-mode { accuracy | performance } - Sets the WURFL engine target. You can choose between 'accuracy' or - 'performance' targets. In performance mode, desktop web browser detection is - done programmatically without referencing the WURFL data. As a result, most - desktop web browsers are returned as generic_web_browser WURFL ID for - performance. If either performance or accuracy are not defined, performance - mode is enabled by default. - - Please note that this option is only available when haproxy has been compiled - with USE_WURFL=1. - -wurfl-cache-size <U>[,<D>] - Sets the WURFL caching strategy. Here <U> is the Useragent cache size, and - <D> is the internal device cache size. There are three possibilities here : - - "0" : no cache is used. - - <U> : the Single LRU cache is used, the size is expressed in elements. - - <U>,<D> : the Double LRU cache is used, both sizes are in elements. This is - the highest performing option. - - Please note that this option is only available when haproxy has been compiled - with USE_WURFL=1. - -wurfl-useragent-priority { plain | sideloaded_browser } - Tells WURFL if it should prioritize use of the plain user agent ('plain') - over the default sideloaded browser user agent ('sideloaded_browser'). - - Please note that this option is only available when haproxy has been compiled - with USE_WURFL=1. - 3.2. Performance tuning ----------------------- diff --git a/examples/wurfl-example.cfg b/examples/wurfl-example.cfg deleted file mode 100644 index ad651a8cd..000000000 --- a/examples/wurfl-example.cfg +++ /dev/null @@ -1,49 +0,0 @@ -# -# This is an example of how to configure HAProxy to be used with WURFL Device Detection module. -# -# HAProxy needs to be compiled with support for this. See README section 1.3 -# - -global - - # The WURFL data file - wurfl-data-file /usr/share/wurfl/wurfl-eval.xml - - # WURFL patches definition (as much as needed, patches will be applied in the same order as specified in this conf file) - #wurfl-patch-file /path/to/patch1.xml; - - # WURFL engine target: one of the following (default is performance) - wurfl-engine-mode performance - #wurfl-engine-mode accuracy - - # WURFL cache: one of the following - ## double LRU cache - wurfl-cache-size 100000,30000 - ## single LRU cache - #wurfl-cache-size 100000 - ## no cache - #wurfl-cache-size 0 - - wurfl-information-list-separator | - - # list of WURFL capabilities, virtual capabilities, property names planned to be used in injected headers - wurfl-information-list wurfl_id model_name - -defaults - mode http - timeout connect 30s - timeout client 30s - timeout server 30s - -frontend TheFrontend - bind 192.168.1.22:80 - default_backend TheBackend - - # inject a header called X-Wurfl-All with all the WURFL informations listed in wurfl-information-list - http-request set-header X-Wurfl-All %[wurfl-get-all()] - - # inject a header called X-WURFL-PROPERTIES with the "wurfl_id" information (should be listed in wurfl-information-list) - #http-request set-header X-WURFL-PROPERTIES %[wurfl-get(wurfl_id)] - -backend TheBackend - server TheWebServer 192.168.0.40:80 diff --git a/src/wurfl.c b/src/wurfl.c deleted file mode 100644 index 75dcf0045..000000000 --- a/src/wurfl.c +++ /dev/null @@ -1,800 +0,0 @@ -#include <stdio.h> -#include <stdarg.h> - -#include <common/cfgparse.h> -#include <common/chunk.h> -#include <common/buffer.h> -#include <common/errors.h> -#include <common/initcall.h> -#include <types/global.h> -#include <proto/arg.h> -#include <proto/log.h> -#include <proto/proto_http.h> -#include <proto/sample.h> -#include <ebsttree.h> -#include <ebmbtree.h> - -#include <wurfl/wurfl.h> - -static struct { - char *data_file; /* the WURFL data file */ - char *cache_size; /* the WURFL cache parameters */ - int engine_mode; /* the WURFL engine mode */ - int useragent_priority; /* the WURFL ua priority */ - struct list patch_file_list; /* the list of WURFL patch file to use */ - char information_list_separator; /* the separator used in request to separate values */ - struct list information_list; /* the list of WURFL data to return into request */ - void *handle; /* the handle to WURFL engine */ - struct eb_root btree; /* btree containing info (name/type) on WURFL data to return */ -} global_wurfl = { - .data_file = NULL, - .cache_size = NULL, - .engine_mode = -1, - .useragent_priority = -1, - .information_list_separator = ',', - .information_list = LIST_HEAD_INIT(global_wurfl.information_list), - .patch_file_list = LIST_HEAD_INIT(global_wurfl.patch_file_list), - .handle = NULL, -}; - -#ifdef WURFL_DEBUG -inline static void ha_wurfl_log(char * message, ...) -{ - char logbuf[256]; - va_list argp; - - va_start(argp, message); - vsnprintf(logbuf, sizeof(logbuf), message, argp); - va_end(argp); - send_log(NULL, LOG_NOTICE, logbuf, NULL); -} -#else -inline static void ha_wurfl_log(char * message, ...) -{ -} -#endif - -#define HA_WURFL_MAX_HEADER_LENGTH 1024 - -typedef char *(*PROP_CALLBACK_FUNC)(wurfl_handle wHandle, wurfl_device_handle dHandle); - -enum wurfl_data_type { - HA_WURFL_DATA_TYPE_UNKNOWN = 0, - HA_WURFL_DATA_TYPE_CAP = 100, - HA_WURFL_DATA_TYPE_VCAP = 200, - HA_WURFL_DATA_TYPE_PROPERTY = 300 -}; - -typedef struct { - char *name; - enum wurfl_data_type type; - PROP_CALLBACK_FUNC func_callback; - struct ebmb_node nd; -} wurfl_data_t; - -static const char HA_WURFL_MODULE_VERSION[] = "1.0"; -static const char HA_WURFL_ISDEVROOT_FALSE[] = "FALSE"; -static const char HA_WURFL_ISDEVROOT_TRUE[] = "TRUE"; -static const char HA_WURFL_TARGET_ACCURACY[] = "accuracy"; -static const char HA_WURFL_TARGET_PERFORMANCE[] = "performance"; -static const char HA_WURFL_PRIORITY_PLAIN[] = "plain"; -static const char HA_WURFL_PRIORITY_SIDELOADED_BROWSER[] = "sideloaded_browser"; -static const char HA_WURFL_MIN_ENGINE_VERSION_MANDATORY[] = "1.8.0.0"; - -static const char HA_WURFL_DATA_TYPE_UNKNOWN_STRING[] = "unknown"; -static const char HA_WURFL_DATA_TYPE_CAP_STRING[] = "capability"; -static const char HA_WURFL_DATA_TYPE_VCAP_STRING[] = "virtual_capability"; -static const char HA_WURFL_DATA_TYPE_PROPERTY_STRING[] = "property"; - -static const char *ha_wurfl_retrieve_header(const char *header_name, const void *wh); -static const char *ha_wurfl_get_wurfl_root_id (wurfl_handle wHandle, wurfl_device_handle dHandle); -static const char *ha_wurfl_get_wurfl_id (wurfl_handle wHandle, wurfl_device_handle dHandle); -static const char *ha_wurfl_get_wurfl_isdevroot (wurfl_handle wHandle, wurfl_device_handle dHandle); -static const char *ha_wurfl_get_wurfl_useragent (wurfl_handle wHandle, wurfl_device_handle dHandle); -static const char *ha_wurfl_get_wurfl_api_version (wurfl_handle wHandle, wurfl_device_handle dHandle); -static const char *ha_wurfl_get_wurfl_engine_target (wurfl_handle wHandle, wurfl_device_handle dHandle); -static const char *ha_wurfl_get_wurfl_info (wurfl_handle wHandle, wurfl_device_handle dHandle); -static const char *ha_wurfl_get_wurfl_last_load_time (wurfl_handle wHandle, wurfl_device_handle dHandle); -static const char *ha_wurfl_get_wurfl_normalized_useragent (wurfl_handle wHandle, wurfl_device_handle dHandle); -static const char *ha_wurfl_get_wurfl_useragent_priority (wurfl_handle wHandle, wurfl_device_handle dHandle); -static const char *(*ha_wurfl_get_property_callback(char *name)) (wurfl_handle wHandle, wurfl_device_handle dHandle); - -// ordered property=>function map, suitable for binary search -static const struct { - const char *name; - const char *(*func)(wurfl_handle wHandle, wurfl_device_handle dHandle); -} wurfl_properties_function_map [] = { - {"wurfl_api_version", ha_wurfl_get_wurfl_api_version}, - {"wurfl_engine_target", ha_wurfl_get_wurfl_engine_target}, - {"wurfl_id", ha_wurfl_get_wurfl_id }, - {"wurfl_info", ha_wurfl_get_wurfl_info }, - {"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_useragent", ha_wurfl_get_wurfl_useragent}, - {"wurfl_useragent_priority", ha_wurfl_get_wurfl_useragent_priority }, - {"wurfl_root_id", ha_wurfl_get_wurfl_root_id}, -}; -static const int HA_WURFL_PROPERTIES_NBR = 10; - -typedef struct { - struct list list; - wurfl_data_t data; -} wurfl_information_t; - -typedef struct { - struct list list; - char *patch_file_path; -} wurfl_patches_t; - -typedef struct { - struct sample *wsmp; - char header_value[HA_WURFL_MAX_HEADER_LENGTH + 1]; -} ha_wurfl_header_t; - -/* - * configuration parameters parsing functions - */ -static int ha_wurfl_cfg_data_file(char **args, int section_type, struct proxy *curpx, - struct proxy *defpx, const char *file, int line, - char **err) -{ - - if (*(args[1]) == 0) { - memprintf(err, "WURFL: %s expects a value.\n", args[0]); - return -1; - } - - global_wurfl.data_file = strdup(args[1]); - return 0; -} - -static int ha_wurfl_cfg_cache(char **args, int section_type, struct proxy *curpx, - struct proxy *defpx, const char *file, int line, - char **err) -{ - if (*(args[1]) == 0) { - memprintf(err, "WURFL: %s expects a value.\n", args[0]); - return -1; - } - - global_wurfl.cache_size = strdup(args[1]); - return 0; -} - -static int ha_wurfl_cfg_engine_mode(char **args, int section_type, struct proxy *curpx, - struct proxy *defpx, const char *file, int line, - char **err) -{ - if (*(args[1]) == 0) { - memprintf(err, "WURFL: %s expects a value.\n", args[0]); - return -1; - } - - if (!strcmp(args[1],HA_WURFL_TARGET_ACCURACY)) { - global_wurfl.engine_mode = WURFL_ENGINE_TARGET_HIGH_ACCURACY; - return 0; - } - - if (!strcmp(args[1],HA_WURFL_TARGET_PERFORMANCE)) { - global_wurfl.engine_mode = WURFL_ENGINE_TARGET_HIGH_PERFORMANCE; - return 0; - } - - memprintf(err, "WURFL: %s valid values are %s or %s.\n", args[0], HA_WURFL_TARGET_PERFORMANCE, HA_WURFL_TARGET_ACCURACY); - return -1; -} - -static int ha_wurfl_cfg_information_list_separator(char **args, int section_type, struct proxy *curpx, - struct proxy *defpx, const char *file, int line, - char **err) -{ - if (*(args[1]) == 0) { - memprintf(err, "WURFL: %s expects a single character.\n", args[0]); - return -1; - } - - if (strlen(args[1]) > 1) { - memprintf(err, "WURFL: %s expects a single character, got %s.\n", args[0], args[1]); - return -1; - } - - global_wurfl.information_list_separator = *args[1]; - return 0; -} - -static int ha_wurfl_cfg_information_list(char **args, int section_type, struct proxy *curpx, - struct proxy *defpx, const char *file, int line, - char **err) -{ - int argIdx = 1; - wurfl_information_t *wi; - - if (*(args[argIdx]) == 0) { - memprintf(err, "WURFL: %s expects a value.\n", args[0]); - return -1; - } - - while (*(args[argIdx])) { - wi = calloc(1, sizeof(*wi)); - - if (wi == NULL) { - memprintf(err, "WURFL: Error allocating memory for %s element.\n", args[0]); - return -1; - } - - wi->data.name = strdup(args[argIdx]); - wi->data.type = HA_WURFL_DATA_TYPE_UNKNOWN; - wi->data.func_callback = NULL; - LIST_ADDQ(&global_wurfl.information_list, &wi->list); - ++argIdx; - } - - return 0; -} - -static int ha_wurfl_cfg_patch_file_list(char **args, int section_type, struct proxy *curpx, - struct proxy *defpx, const char *file, int line, - char **err) -{ - int argIdx = 1; - wurfl_patches_t *wp; - - if (*(args[argIdx]) == 0) { - memprintf(err, "WURFL: %s expects a value.\n", args[0]); - return -1; - } - - while (*(args[argIdx])) { - wp = calloc(1, sizeof(*wp)); - - if (wp == NULL) { - memprintf(err, "WURFL: Error allocating memory for %s element.\n", args[0]); - return -1; - } - - wp->patch_file_path = strdup(args[argIdx]); - LIST_ADDQ(&global_wurfl.patch_file_list, &wp->list); - ++argIdx; - } - - return 0; -} - -static int ha_wurfl_cfg_useragent_priority(char **args, int section_type, struct proxy *curpx, - struct proxy *defpx, const char *file, int line, - char **err) -{ - if (*(args[1]) == 0) { - memprintf(err, "WURFL: %s expects a value.\n", args[0]); - return -1; - } - - if (!strcmp(args[1],HA_WURFL_PRIORITY_PLAIN)) { - global_wurfl.useragent_priority = WURFL_USERAGENT_PRIORITY_USE_PLAIN_USERAGENT; - return 0; - } - - if (!strcmp(args[1],HA_WURFL_PRIORITY_SIDELOADED_BROWSER)) { - global_wurfl.useragent_priority = WURFL_USERAGENT_PRIORITY_OVERRIDE_SIDELOADED_BROWSER_USERAGENT; - return 0; - } - - memprintf(err, "WURFL: %s valid values are %s or %s.\n", args[0], HA_WURFL_PRIORITY_PLAIN, HA_WURFL_PRIORITY_SIDELOADED_BROWSER); - return -1; -} - -/* - * module init / deinit functions. Returns 0 if OK, or a combination of ERR_*. - */ - -static int ha_wurfl_init(void) -{ - wurfl_information_t *wi; - wurfl_patches_t *wp; - wurfl_data_t * wn; - int wurfl_result_code = WURFL_OK; - int len; - - send_log(NULL, LOG_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"); - return ERR_WARN; - } - - send_log(NULL, LOG_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 (global.nbthread > 1) { - ha_alert("WURFL: multithreading is not supported for now.\n"); - return (ERR_FATAL | ERR_ALERT); - } - - 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); - // 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); - - // 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 - global_wurfl.btree = EB_ROOT; - - // checking if informations are valid WURFL data ( cap, vcaps, properties ) - list_for_each_entry(wi, &global_wurfl.information_list, list) { - // check if information is already loaded looking into btree - 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); - } 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); - } 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); - } - - // ebtree insert here - len = strlen(wi->data.name); - - wn = malloc(sizeof(wurfl_data_t) + len + 1); - - 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; - } - - wn->name = wi->data.name; - wn->type = wi->data.type; - wn->func_callback = wi->data.func_callback; - memcpy(wn->nd.key, wi->data.name, len); - wn->nd.key[len] = 0; - - 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); - } - - } - - } - - // filtering mandatory capabilities if engine version < 1.8.0.0 - if (strcmp(wurfl_get_api_version(), HA_WURFL_MIN_ENGINE_VERSION_MANDATORY) < 0) { - wurfl_capability_enumerator_handle hmandatorycapabilityenumerator; - ha_wurfl_log("WURFL: Engine version %s < %s - Filtering mandatory capabilities\n", wurfl_get_api_version(), HA_WURFL_MIN_ENGINE_VERSION_MANDATORY); - hmandatorycapabilityenumerator = wurfl_get_mandatory_capability_enumerator(global_wurfl.handle); - - while (wurfl_capability_enumerator_is_valid(hmandatorycapabilityenumerator)) { - char *name = (char *)wurfl_capability_enumerator_get_name(hmandatorycapabilityenumerator); - - if (ebst_lookup(&global_wurfl.btree, name) == NULL) { - if (wurfl_add_requested_capability(global_wurfl.handle, name) != WURFL_OK) { - ha_warning("WURFL: Engine adding mandatory capability [%s] failed - %s\n", name, wurfl_get_error_message(global_wurfl.handle)); - send_log(NULL, LOG_WARNING, "WURFL: Adding mandatory capability [%s] failed - %s\n", name, wurfl_get_error_message(global_wurfl.handle)); - return ERR_WARN; - } - - ha_wurfl_log("WURFL: Mandatory capability [%s] added\n", name); - } else { - ha_wurfl_log("WURFL: Mandatory capability [%s] already filtered\n", name); - } - - wurfl_capability_enumerator_move_next(hmandatorycapabilityenumerator); - } - - wurfl_capability_enumerator_destroy(hmandatorycapabilityenumerator); - } - - // adding WURFL patches if needed - if (!LIST_ISEMPTY(&global_wurfl.patch_file_list)) { - - 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); - - } - - } - - // setting cache provider if specified in cfg, otherwise let engine choose - if (global_wurfl.cache_size != NULL) { - if (strpbrk(global_wurfl.cache_size, ",") != NULL) { - wurfl_result_code = wurfl_set_cache_provider(global_wurfl.handle, WURFL_CACHE_PROVIDER_DOUBLE_LRU, global_wurfl.cache_size) ; - } else { - if (strcmp(global_wurfl.cache_size, "0")) { - wurfl_result_code = wurfl_set_cache_provider(global_wurfl.handle, WURFL_CACHE_PROVIDER_LRU, global_wurfl.cache_size) ; - } else { - wurfl_result_code = wurfl_set_cache_provider(global_wurfl.handle, WURFL_CACHE_PROVIDER_NONE, 0); - } - - } - - 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); - } - - // setting engine mode if specified in cfg, otherwise let engine choose - if (global_wurfl.engine_mode != -1) { - if (wurfl_set_engine_target(global_wurfl.handle, global_wurfl.engine_mode) != WURFL_OK ) { - ha_warning("WURFL: Setting engine target failed - %s\n", wurfl_get_error_message(global_wurfl.handle)); - send_log(NULL, LOG_WARNING, "WURFL: Setting engine target failed - %s\n", wurfl_get_error_message(global_wurfl.handle)); - return ERR_WARN; - } - - } - - send_log(NULL, LOG_NOTICE, "WURFL: Engine target set to [%s]\n", (global_wurfl.engine_mode == WURFL_ENGINE_TARGET_HIGH_PERFORMANCE) ? (HA_WURFL_TARGET_PERFORMANCE) : (HA_WURFL_TARGET_ACCURACY) ); - - // setting ua priority if specified in cfg, otherwise let engine choose - if (global_wurfl.useragent_priority != -1) { - if (wurfl_set_useragent_priority(global_wurfl.handle, global_wurfl.useragent_priority) != WURFL_OK ) { - ha_warning("WURFL: Setting engine useragent priority failed - %s\n", wurfl_get_error_message(global_wurfl.handle)); - send_log(NULL, LOG_WARNING, "WURFL: Setting engine useragent priority failed - %s\n", wurfl_get_error_message(global_wurfl.handle)); - return ERR_WARN; - } - - } - - send_log(NULL, LOG_NOTICE, "WURFL: Engine useragent priority set to [%s]\n", (global_wurfl.useragent_priority == WURFL_USERAGENT_PRIORITY_USE_PLAIN_USERAGENT) ? (HA_WURFL_PRIORITY_PLAIN) : (HA_WURFL_PRIORITY_SIDELOADED_BROWSER) ); - - // 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"); - return 0; -} - -static void ha_wurfl_deinit(void) -{ - wurfl_information_t *wi, *wi2; - wurfl_patches_t *wp, *wp2; - - send_log(NULL, LOG_NOTICE, "WURFL: Unloading module v.%s\n", HA_WURFL_MODULE_VERSION); - wurfl_destroy(global_wurfl.handle); - global_wurfl.handle = NULL; - free(global_wurfl.data_file); - global_wurfl.data_file = NULL; - free(global_wurfl.cache_size); - global_wurfl.cache_size = NULL; - - list_for_each_entry_safe(wi, wi2, &global_wurfl.information_list, list) { - LIST_DEL(&wi->list); - free(wi); - } - - list_for_each_entry_safe(wp, wp2, &global_wurfl.patch_file_list, list) { - LIST_DEL(&wp->list); - free(wp); - } - - send_log(NULL, LOG_NOTICE, "WURFL: Module unloaded\n"); -} - -static int ha_wurfl_get_all(const struct arg *args, struct sample *smp, const char *kw, void *private) -{ - wurfl_device_handle dHandle; - struct buffer *temp; - wurfl_information_t *wi; - ha_wurfl_header_t wh; - - ha_wurfl_log("WURFL: starting ha_wurfl_get_all\n"); - wh.wsmp = smp; - 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; - } - - temp = get_trash_chunk(); - 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 : - ha_wurfl_log("WURFL: %s is of an %s type\n", wi->data.name, HA_WURFL_DATA_TYPE_UNKNOWN_STRING); -#ifdef WURFL_HEADER_WITH_DETAILS - // write WURFL property type and name before its value... - chunk_appendf(temp, "%s=%s", HA_WURFL_DATA_TYPE_UNKNOWN_STRING, wi->data.name); -#endif - break; - case HA_WURFL_DATA_TYPE_CAP : - ha_wurfl_log("WURFL: %s is a %s\n", wi->data.name, HA_WURFL_DATA_TYPE_CAP_STRING); -#ifdef WURFL_HEADER_WITH_DETAILS - // write WURFL property type and name before its value... - chunk_appendf(temp, "%s=%s=", HA_WURFL_DATA_TYPE_CAP_STRING, wi->data.name); -#endif - chunk_appendf(temp, "%s", wurfl_device_get_capability(dHandle, wi->data.name)); - break; - case HA_WURFL_DATA_TYPE_VCAP : - ha_wurfl_log("WURFL: %s is a %s\n", wi->data.name, HA_WURFL_DATA_TYPE_VCAP_STRING); -#ifdef WURFL_HEADER_WITH_DETAILS - // write WURFL property type and name before its value... - chunk_appendf(temp, "%s=%s=", HA_WURFL_DATA_TYPE_VCAP_STRING, wi->data.name); -#endif - chunk_appendf(temp, "%s", wurfl_device_get_virtual_capability(dHandle, wi->data.name)); - break; - case HA_WURFL_DATA_TYPE_PROPERTY : - ha_wurfl_log("WURFL: %s is a %s\n", wi->data.name, HA_WURFL_DATA_TYPE_PROPERTY_STRING); -#ifdef WURFL_HEADER_WITH_DETAILS - // write WURFL property type and name before its value... - chunk_appendf(temp, "%s=%s=", HA_WURFL_DATA_TYPE_PROPERTY_STRING, wi->data.name); -#endif - chunk_appendf(temp, "%s", wi->data.func_callback(global_wurfl.handle, dHandle)); - break; - } - - } - - wurfl_device_destroy(dHandle); - smp->data.u.str.area = temp->area; - smp->data.u.str.data = temp->data; - return 1; -} - -static int ha_wurfl_get(const struct arg *args, struct sample *smp, const char *kw, void *private) -{ - wurfl_device_handle dHandle; - struct buffer *temp; - wurfl_data_t *wn = NULL; - struct ebmb_node *node; - ha_wurfl_header_t wh; - int i = 0; - - ha_wurfl_log("WURFL: starting ha_wurfl_get\n"); - wh.wsmp = smp; - 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; - } - - temp = get_trash_chunk(); - 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); - wn = container_of(node, wurfl_data_t, nd); - - if (wn) { - - switch(wn->type) { - case HA_WURFL_DATA_TYPE_UNKNOWN : - ha_wurfl_log("WURFL: %s is of an %s type\n", wn->name, HA_WURFL_DATA_TYPE_UNKNOWN_STRING); -#ifdef WURFL_HEADER_WITH_DETAILS - // write WURFL property type and name before its value... - chunk_appendf(temp, "%s=%s", HA_WURFL_DATA_TYPE_UNKNOWN_STRING, wn->name); -#endif - break; - case HA_WURFL_DATA_TYPE_CAP : - ha_wurfl_log("WURFL: %s is a %s\n", wn->name, HA_WURFL_DATA_TYPE_CAP_STRING); -#ifdef WURFL_HEADER_WITH_DETAILS - // write WURFL property type and name before its value... - chunk_appendf(temp, "%s=%s=", HA_WURFL_DATA_TYPE_CAP_STRING, wn->name); -#endif - chunk_appendf(temp, "%s", wurfl_device_get_capability(dHandle, wn->name)); - break; - case HA_WURFL_DATA_TYPE_VCAP : - ha_wurfl_log("WURFL: %s is a %s\n", wn->name, HA_WURFL_DATA_TYPE_VCAP_STRING); -#ifdef WURFL_HEADER_WITH_DETAILS - // write WURFL property type and name before its value... - chunk_appendf(temp, "%s=%s=", HA_WURFL_DATA_TYPE_VCAP_STRING, wn->name); -#endif - chunk_appendf(temp, "%s", wurfl_device_get_virtual_capability(dHandle, wn->name)); - break; - case HA_WURFL_DATA_TYPE_PROPERTY : - ha_wurfl_log("WURFL: %s is a %s\n", wn->name, HA_WURFL_DATA_TYPE_PROPERTY_STRING); -#ifdef WURFL_HEADER_WITH_DETAILS - // write WURFL property type and name before its value... - chunk_appendf(temp, "%s=%s=", HA_WURFL_DATA_TYPE_PROPERTY_STRING, wn->name); -#endif - chunk_appendf(temp, "%s", wn->func_callback(global_wurfl.handle, dHandle)); - break; - } - - } else { - ha_wurfl_log("WURFL: %s not in wurfl-information-list \n", - args[i].data.str.area); - } - - i++; - } - - wurfl_device_destroy(dHandle); - smp->data.u.str.area = temp->area; - smp->data.u.str.data = temp->data; - return 1; -} - -static struct cfg_kw_list wurflcfg_kws = {{ }, { - { CFG_GLOBAL, "wurfl-data-file", ha_wurfl_cfg_data_file }, - { CFG_GLOBAL, "wurfl-information-list-separator", ha_wurfl_cfg_information_list_separator }, - { CFG_GLOBAL, "wurfl-information-list", ha_wurfl_cfg_information_list }, - { CFG_GLOBAL, "wurfl-patch-file", ha_wurfl_cfg_patch_file_list }, - { CFG_GLOBAL, "wurfl-cache-size", ha_wurfl_cfg_cache }, - { CFG_GLOBAL, "wurfl-engine-mode", ha_wurfl_cfg_engine_mode }, - { CFG_GLOBAL, "wurfl-useragent-priority", ha_wurfl_cfg_useragent_priority }, - { 0, NULL, NULL }, - } -}; - -INITCALL1(STG_REGISTER, cfg_register_keywords, &wurflcfg_kws); - -/* Note: must not be declared <const> as its list will be overwritten */ -static struct sample_fetch_kw_list fetch_kws = {ILH, { - { "wurfl-get-all", ha_wurfl_get_all, 0, NULL, SMP_T_STR, SMP_USE_HRQHV }, - { "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 }, - { NULL, NULL, 0, 0, 0 }, - } -}; - -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, { - { NULL, NULL, 0, 0, 0 }, - } -}; - -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); -} - -static const char *ha_wurfl_get_wurfl_id (wurfl_handle wHandle, wurfl_device_handle dHandle) -{ - return wurfl_device_get_id(dHandle); -} - -static const char *ha_wurfl_get_wurfl_isdevroot (wurfl_handle wHandle, wurfl_device_handle dHandle) -{ - if (wurfl_device_is_actual_device_root(dHandle)) - return HA_WURFL_ISDEVROOT_TRUE; - else - return HA_WURFL_ISDEVROOT_FALSE; -} - -static const char *ha_wurfl_get_wurfl_useragent (wurfl_handle wHandle, wurfl_device_handle dHandle) -{ - return wurfl_device_get_original_useragent(dHandle); -} - -static const char *ha_wurfl_get_wurfl_api_version (wurfl_handle wHandle, wurfl_device_handle dHandle) -{ - return wurfl_get_api_version(); -} - -static const char *ha_wurfl_get_wurfl_engine_target (wurfl_handle wHandle, wurfl_device_handle dHandle) -{ - return wurfl_get_engine_target_as_string(wHandle); -} - -static const char *ha_wurfl_get_wurfl_info (wurfl_handle wHandle, wurfl_device_handle dHandle) -{ - return wurfl_get_wurfl_info(wHandle); -} - -static const char *ha_wurfl_get_wurfl_last_load_time (wurfl_handle wHandle, wurfl_device_handle dHandle) -{ - return wurfl_get_last_load_time_as_string(wHandle); -} - -static const char *ha_wurfl_get_wurfl_normalized_useragent (wurfl_handle wHandle, wurfl_device_handle dHandle) -{ - return wurfl_device_get_normalized_useragent(dHandle); -} - -static const char *ha_wurfl_get_wurfl_useragent_priority (wurfl_handle wHandle, wurfl_device_handle dHandle) -{ - return wurfl_get_useragent_priority_as_string(wHandle); -} - -// call function for WURFL properties -static const char *(*ha_wurfl_get_property_callback(char *name)) (wurfl_handle wHandle, wurfl_device_handle dHandle) -{ - int position; - int begin = 0; - int end = HA_WURFL_PROPERTIES_NBR - 1; - int cond = 0; - - while(begin <= end) { - position = (begin + end) / 2; - - if((cond = strcmp(wurfl_properties_function_map[position].name, name)) == 0) { - ha_wurfl_log("WURFL: ha_wurfl_get_property_callback match %s\n", wurfl_properties_function_map[position].name ); - return wurfl_properties_function_map[position].func; - } else if(cond < 0) - begin = position + 1; - else - end = position - 1; - - } - - return NULL; -} - -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; - 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; - - if (http_find_full_header2(header_name, strlen(header_name), msg->chn->buf->p, 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); - ((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; -} - -REGISTER_POST_CHECK(ha_wurfl_init); -REGISTER_POST_DEINIT(ha_wurfl_deinit); -REGISTER_BUILD_OPTS("Built with WURFL support.");