mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2024-12-18 01:14:38 +00:00
CLEANUP: wurfl: remove dead, broken and unmaintained code
Since the "wurfl" device detection engine was merged slightly more than two years ago (2016-11-04), it never received a single fix nor update. For almost two years it didn't receive even the minimal review or changes needed to be compatible with threads, and it's remained build-broken for about the last 9 months, consecutive to the last buffer API changes, without anyone ever noticing! When asked on the list, nobody confirmed using it : https://www.mail-archive.com/haproxy@formilux.org/msg32516.html And obviously nobody even cared to verify that it did still build. So we are left with this broken code with no user and no maintainer. It might even suffer from remotely exploitable vulnerabilities without anyone being able to check if it presents any risk. It's a pain to update each time there is an API change because it doesn't build as it depends on external libraries that are not publicly accessible, leading to careful blind changes. It slows down the whole project. This situation is not acceptable at all. It's time to cure the problem where it is. This patch removes all this dead, non-buildable, non-working code. If anyone ever decides to use it, which I seriously doubt based on history, it could be reintegrated, but this time the following guarantees will be required : - someone has to step up as a maintainer and have his name listed in the MAINTAINERS file (I should have been more careful last time). This person will take the sole blame for all issues and will be responsible for fixing the bugs and incompatibilities affecting this code, and for making it evolve to follow regular internal API updates. - support building on a standard distro with automated tools (i.e. no more "click on this site, register your e-mail and download an archive then figure how to place this into your build system"). Dummy libs are OK though as long as they allow the mainline code to build and start. - multi-threaded support must be fixed. I mean seriously, not worked around with a check saying "please disable threads, we've been busy fishing for the last two years". This may be backported to 1.9 given that the code has never worked there either, thus at least we're certain nobody will miss it.
This commit is contained in:
parent
756d97f205
commit
8e5e1e7bf0
1
INSTALL
1
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
|
||||
|
19
Makefile
19
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
|
||||
|
@ -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
|
@ -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
|
||||
-----------------------
|
||||
|
@ -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
|
800
src/wurfl.c
800
src/wurfl.c
@ -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.");
|
Loading…
Reference in New Issue
Block a user