Browse code

Adding the curl module with status "Development"

Anyone that wants to help is welcome to help. I've listed a few
todo's in the TODO.txt file. We will have to decide which of these
that we need for release and which that can be done in the future.

Olle E. Johansson authored on 19/09/2015 09:29:52
Showing 14 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,42 @@
1
+#
2
+# curl module makefile
3
+#
4
+# 
5
+# WARNING: do not run this directly, it should be run by the master Makefile
6
+
7
+include ../../Makefile.defs
8
+auto_gen=
9
+NAME=curl.so
10
+
11
+ifeq ($(CROSS_COMPILE),)
12
+XML2CFG=$(shell which xml2-config)
13
+CURL_BUILDER=$(shell \
14
+	if pkg-config --exists libcurl; then \
15
+		echo 'pkg-config libcurl'; \
16
+	else \
17
+		which curl-config; \
18
+	fi)
19
+endif
20
+
21
+ifneq ($(XML2CFG),)
22
+	DEFS += $(shell $(XML2CFG) --cflags )
23
+	LIBS += $(shell $(XML2CFG) --libs)
24
+else
25
+	DEFS+=-I$(LOCALBASE)/include/libxml2 \
26
+      -I$(LOCALBASE)/include
27
+	LIBS+=-L$(LOCALBASE)/lib -lxml2
28
+endif
29
+
30
+ifneq ($(CURL_BUILDER),)
31
+	DEFS += $(shell $(CURL_BUILDER) --cflags )
32
+	LIBS += $(shell $(CURL_BUILDER) --libs)
33
+else
34
+	DEFS+=-I$(LOCALBASE)/include
35
+	LIBS+=-L$(LOCALBASE)/lib -lcurl
36
+endif
37
+
38
+DEFS+=-DKAMAILIO_MOD_INTERFACE
39
+
40
+SERLIBPATH=../../lib
41
+#SER_LIBS+=$(SERLIBPATH)/kmi/kmi
42
+include ../../Makefile.modules
0 43
new file mode 100644
... ...
@@ -0,0 +1,342 @@
1
+curl
2
+
3
+Olle E. Johansson
4
+
5
+   Edvina AB
6
+
7
+Juha Heinanen
8
+
9
+   TutPro Inc.
10
+
11
+Carsten Bock
12
+
13
+   ng-voice GmbH
14
+
15
+   Copyright � 2008-2009 Juha Heinanen
16
+
17
+   Copyright � 2013 Carsten Bock, ng-voice GmbH
18
+
19
+   Copyright � 2015 Olle E. Johansson, Edvina AB
20
+     __________________________________________________________________
21
+
22
+   Table of Contents
23
+
24
+   1. Admin Guide
25
+
26
+        1. Overview
27
+        2. Dependencies
28
+
29
+              2.1. Kamailio Modules
30
+              2.2. External Libraries or Applications
31
+
32
+        3. Parameters
33
+
34
+              3.1. httpredirect (int)
35
+              3.2. useragent (string)
36
+              3.3. connection_timeout (int)
37
+              3.4. tlsclientcert (string)
38
+              3.5. tlsclientkey (string)
39
+              3.6. tlscacert (string)
40
+              3.7. tlsverifyserver (int)
41
+              3.8. curlcon (string)
42
+
43
+        4. Functions
44
+
45
+              4.1. curl_http_query(url, [post-data], result)
46
+
47
+        5. Pseudovariables
48
+
49
+              5.1. $curlerror(error)
50
+
51
+        6. Counters
52
+
53
+              6.1. curl.connections
54
+              6.2. curl.connok
55
+              6.3. curl.connfail
56
+
57
+   List of Examples
58
+
59
+   1.1. Set httpredirect parameter
60
+   1.2. Set useragent parameter
61
+   1.3. Set connection_timeout parameter
62
+   1.4. Set tlsclientcert parameter
63
+   1.5. Set tlsclientkey parameter
64
+   1.6. Set tlscacert parameter
65
+   1.7. Set tlsverifyserver parameter
66
+   1.8. Set curlcon parameter
67
+   1.9. curl_http_query() usage
68
+
69
+Chapter 1. Admin Guide
70
+
71
+   Table of Contents
72
+
73
+   1. Overview
74
+   2. Dependencies
75
+
76
+        2.1. Kamailio Modules
77
+        2.2. External Libraries or Applications
78
+
79
+   3. Parameters
80
+
81
+        3.1. httpredirect (int)
82
+        3.2. useragent (string)
83
+        3.3. connection_timeout (int)
84
+        3.4. tlsclientcert (string)
85
+        3.5. tlsclientkey (string)
86
+        3.6. tlscacert (string)
87
+        3.7. tlsverifyserver (int)
88
+        3.8. curlcon (string)
89
+
90
+   4. Functions
91
+
92
+        4.1. curl_http_query(url, [post-data], result)
93
+
94
+   5. Pseudovariables
95
+
96
+        5.1. $curlerror(error)
97
+
98
+   6. Counters
99
+
100
+        6.1. curl.connections
101
+        6.2. curl.connok
102
+        6.3. curl.connfail
103
+
104
+1. Overview
105
+
106
+   This module implements protocol functions that use the libcurl library
107
+   to fetch data from external HTTP servers or post data to HTTP servers.
108
+   The module is using a concept of "connections" to define properties of
109
+   sessions in a simple way.
110
+
111
+   Function http_query allows Kamailio to issue an HTTP GET request and
112
+   get access to parts of the reply. This function has been ported from
113
+   the utils module and now use the same libcurl functions.
114
+
115
+2. Dependencies
116
+
117
+   2.1. Kamailio Modules
118
+   2.2. External Libraries or Applications
119
+
120
+2.1. Kamailio Modules
121
+
122
+   The following modules must be loaded before this module:
123
+     * None.
124
+
125
+2.2. External Libraries or Applications
126
+
127
+   The following libraries or applications must be installed before
128
+   running Kamailio with this module loaded:
129
+     * libcurl.
130
+
131
+3. Parameters
132
+
133
+   3.1. httpredirect (int)
134
+   3.2. useragent (string)
135
+   3.3. connection_timeout (int)
136
+   3.4. tlsclientcert (string)
137
+   3.5. tlsclientkey (string)
138
+   3.6. tlscacert (string)
139
+   3.7. tlsverifyserver (int)
140
+   3.8. curlcon (string)
141
+
142
+3.1. httpredirect (int)
143
+
144
+   If set to 1, enabled, CURL will follow HTTP 302 Redirects. If set to 0,
145
+   CURL will not follow redirects. Default is 1, enabled.
146
+
147
+   The latest redirect URL will be stored in the $curlredirect
148
+   pseudovariable.
149
+
150
+   Example 1.1. Set httpredirect parameter
151
+...
152
+modparam("curl", "httpredirect", 0)
153
+...
154
+
155
+3.2. useragent (string)
156
+
157
+   Useragent to use in the HTTP protocol for requests. Defaults to the
158
+   Kamailio SIP useragent string - including software version and
159
+   platform.
160
+
161
+   Example 1.2. Set useragent parameter
162
+...
163
+modparam("curl", "useragent", "Secret HTTP REST grabber 0.42")
164
+...
165
+
166
+3.3. connection_timeout (int)
167
+
168
+   Defines in seconds how long Kamailio waits for response from servers.
169
+
170
+   Default value is zero, i.e., the timeout function is disabled.
171
+
172
+   Example 1.3. Set connection_timeout parameter
173
+...
174
+modparam("curl", "connection_timeout", 2)
175
+...
176
+
177
+3.4. tlsclientcert (string)
178
+
179
+   File name for a TLS client certificate. The certificate needs to be
180
+   encoded in PEM format.
181
+
182
+   Default value is empty string, i.e. no client certificate used. Note
183
+   that if you specify a client cert, you also need to specify the
184
+   tlsclientkey.
185
+
186
+   Example 1.4. Set tlsclientcert parameter
187
+...
188
+modparam("curl", "tlsclientcert", "/var/certs/sollentuna.example.com.cert")
189
+...
190
+
191
+3.5. tlsclientkey (string)
192
+
193
+   File name for a TLS client key. The key needs to be encoded in PEM
194
+   format.
195
+
196
+   Default value is empty string, i.e. no client certificate or key is
197
+   used. Note that if you specify a client key, you also need to specify
198
+   the tlsclientcert.
199
+
200
+   Example 1.5. Set tlsclientkey parameter
201
+...
202
+modparam("curl", "tlsclientkey", "/var/certs/sollentuna.example.com.key")
203
+...
204
+
205
+3.6. tlscacert (string)
206
+
207
+   File name for the trusted TLS CA cert used to verify servers. The
208
+   certificates need to be encoded in PEM format.
209
+
210
+   Default value is empty string, i.e. no CA certificate is used to verify
211
+   the host. If tlsverifyhost is on, all TLS connections will fail without
212
+   any CA certificate to validate with.
213
+
214
+   Example 1.6. Set tlscacert parameter
215
+...
216
+modparam("curl", "tlscacert", "/var/certs/ca/edvina-sip-ca.pem")
217
+...
218
+
219
+3.7. tlsverifyserver (int)
220
+
221
+   If set to 0, TLS verification of the server certificate is disabled.
222
+   This means that the connection will get encrypted, but there's no
223
+   authentication. There's no proof that the transmission of data is to
224
+   the host that is meant to receive data.
225
+
226
+   IF set to 1, default setting, and one or more CA certificates is
227
+   configured, the server TLS certificate will be validated. If validation
228
+   fails, the connection fails.
229
+
230
+   Example 1.7. Set tlsverifyserver parameter
231
+...
232
+modparam("curl", "tlsverifyserver", 1)
233
+...
234
+
235
+3.8. curlcon (string)
236
+
237
+   Defines a connection and credentials for the connection for use in a
238
+   connection-oriented function call in this module.
239
+
240
+   Syntax:
241
+   <connection-name>=><schema>://[<username>:<password>@]<hostname/address
242
+   >[;param=value]
243
+
244
+   The address in the URL is the base for the URL in the curlcon_query()
245
+   call. The address given in the function call will be appended to the
246
+   base URL in the connection definition.
247
+
248
+   By default, no connections are defined.
249
+
250
+   Parameters
251
+     * httpredirect Set to 1 for following HTTP 302 redirect. 0 to
252
+       disable. Default is the setting for the httpredirect modparam.
253
+     * timeout Timeout used for this connection. Overrides the default
254
+       timeout for the module.
255
+     * useragent Useragent used for HTTP requests. Overrides useragent
256
+       modparam.
257
+
258
+   Example 1.8. Set curlcon parameter
259
+...
260
+modparam("curl", "curlcon", "apione=>http://atlanta.example.com")
261
+modparam("curl", "curlcon", "apitwo=>http://atlanta.example.com/api/12")
262
+modparam("curl", "curlcon", "apithree=>http://annabella:mysecret@atlanta.example
263
+.com/api/12")
264
+modparam("curl", "curlcon", "apifour=>http://stockholm.example.com/api/getstuff;
265
+timeout=12")
266
+...
267
+
268
+4. Functions
269
+
270
+   4.1. curl_http_query(url, [post-data], result)
271
+
272
+4.1. curl_http_query(url, [post-data], result)
273
+
274
+   Sends HTTP GET or POST request according to URL given in "url"
275
+   parameter, which is a string that may contain pseudo variables.
276
+
277
+   If you want to make a POST-Request, you have to define the "post"-data,
278
+   that should be submitted in that request as the second parameter.
279
+
280
+   If HTTP server returns a class 2xx, 3xx or 4xx reply, the first line of
281
+   the reply's body (if any) is stored in "result" parameter, which must
282
+   be a writable pseudo variable.
283
+
284
+   Function returns reply code of HTTP reply or -1 if something went
285
+   wrong.
286
+
287
+   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
288
+   FAILURE_ROUTE, and BRANCH_ROUTE.
289
+
290
+   Note that this function is based on the http_query function in the
291
+   utils module. It is changed to use the same base library and settings
292
+   as the rest of the functions in this module.
293
+
294
+   Example 1.9. curl_http_query() usage
295
+...
296
+# GET-Request
297
+curl_http_query("http://tutpro.com/index.php?r_uri=$(ru{s.escape.param})&f_uri=$
298
+(fu{s.escape.param})",
299
+           "$var(result)")
300
+switch ($retcode) {
301
+       ...
302
+}
303
+...
304
+...
305
+# POST-Request
306
+curl_http_query("http://tutpro.com/index.php", "r_uri=$(ru{s.escape.param})&f_ur
307
+i=$(fu{s.escape.param})",
308
+           "$var(result)")
309
+switch ($retcode) {
310
+       ...
311
+}
312
+...
313
+
314
+5. Pseudovariables
315
+
316
+   5.1. $curlerror(error)
317
+
318
+5.1. $curlerror(error)
319
+
320
+   cURL returns error codes from the protocol used. If an error happens, a
321
+   cURL specific error code below 100 is returned. The $curlerror pv
322
+   returns a text string representing the error. For more information on
323
+   cURL error codes, please visit
324
+   http://curl.haxx.se/libcurl/c/libcurl-errors.html
325
+
326
+6. Counters
327
+
328
+   6.1. curl.connections
329
+   6.2. curl.connok
330
+   6.3. curl.connfail
331
+
332
+6.1. curl.connections
333
+
334
+   The number of connection definitions that are in-memory.
335
+
336
+6.2. curl.connok
337
+
338
+   The number of successful connections since Kamailio start
339
+
340
+6.3. curl.connfail
341
+
342
+   The number of failed connections since Kamailio start
0 343
new file mode 100644
... ...
@@ -0,0 +1,49 @@
1
+The curl module - todo
2
+======================
3
+
4
+- connection parameters
5
+	timeout=x		- DONE
6
+	read=line/all
7
+	tlsverify=on/off
8
+	failover=curlcon	Other curlcon that can be used for failover in case of 5xx response or timeout
9
+	httpredirect		- DONE
10
+	useragent		- DONE
11
+
12
+- Make sure modparams work
13
+	httpproxy		- Not working with curl
14
+	tls cert, key, ca	- Not working with curl yet
15
+	httpredirect		- done
16
+	timeout			- done
17
+	
18
+- save fingerprint of cert for trust-on-first-use procedure
19
+
20
+- status for curlcon-object, needs to be object in process memory, so child_init
21
+	- if 5xx response or timeout set flag
22
+	- function in dialplan - curlcon_exist(object)
23
+	- pv $curlstatus(object) ??
24
+
25
+- pv for curl error codes (result < 100)
26
+	$curlerror(code)	Result string - DONE
27
+
28
+- rpc
29
+	curl.listcon	list all connection objects with properties
30
+			-- Done, but not documented
31
+	curl.modcon     modify connection object
32
+			url
33
+			username
34
+			password
35
+			scheme
36
+			timeout
37
+			read
38
+			tlsverify
39
+			failover
40
+	curl.addcon	add connection object
41
+	curl.rmcon	remove connection object
42
+
43
+
44
+- Async - event_route when done
45
+	Need background task process to run curl request
46
+	event_route[curl:connectioncomplete]
47
+	$curlcon == connection
48
+	$curl == URL
49
+	$curlres == result
0 50
new file mode 100644
... ...
@@ -0,0 +1,606 @@
1
+/*
2
+ * curl Module
3
+ * Copyright (C) 2015 Edvina AB, Olle E. Johansson
4
+ *
5
+ * Based on part of the utils module and part
6
+ * of the json-rpc-c module
7
+ *
8
+ * Copyright (C) 2008 Juha Heinanen
9
+ * Copyright (C) 2009 1&1 Internet AG
10
+ * Copyright (C) 2013 Carsten Bock, ng-voice GmbH
11
+ *
12
+ * This file is part of Kamailio, a free SIP server.
13
+ *
14
+ * Kamailio is free software; you can redistribute it and/or modify
15
+ * it under the terms of the GNU General Public License as published by
16
+ * the Free Software Foundation; either version 2 of the License, or
17
+ * (at your option) any later version
18
+ *
19
+ * Kamailio is distributed in the hope that it will be useful,
20
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22
+ * GNU General Public License for more details.
23
+ *
24
+ * You should have received a copy of the GNU General Public License 
25
+ * along with this program; if not, write to the Free Software 
26
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
27
+ *
28
+ */
29
+
30
+/*! \file
31
+ * \brief  Kamailio curl :: The module interface file
32
+ * \ingroup curl
33
+ */
34
+
35
+/*! \defgroup curl Kamailio :: Module interface to Curl
36
+ *
37
+ * http://curl.haxx.se
38
+ * A generic library for many protocols
39
+ *
40
+ *  curl_connect(connection, url, $avp)
41
+ *  curl_connect(connection, url, content-type, data, $avp)
42
+ *
43
+ * 	$var(res) = curl_connect("anders", "/postlåda", "application/json", "{ ok, {200, ok}}", "$avp(gurka)");
44
+ *
45
+ */
46
+
47
+
48
+#include <curl/curl.h>
49
+
50
+#include "../../mod_fix.h"
51
+#include "../../sr_module.h"
52
+#include "../../ut.h"
53
+#include "../../resolve.h"
54
+#include "../../locking.h"
55
+#include "../../script_cb.h"
56
+#include "../../mem/shm_mem.h"
57
+#include "../../lib/srdb1/db.h"
58
+#include "../../rpc.h"
59
+#include "../../rpc_lookup.h"
60
+#include "../../config.h"
61
+
62
+#include "functions.h"
63
+#include "curlcon.h"
64
+#include "curlrpc.h"
65
+
66
+MODULE_VERSION
67
+
68
+#define CURL_USER_AGENT  NAME  " (" VERSION " (" ARCH "/" OS_QUOTED "))"
69
+#define CURL_USER_AGENT_LEN (sizeof(CURL_USER_AGENT)-1)
70
+
71
+/* Module parameter variables */
72
+unsigned int	default_connection_timeout = 4;
73
+char		*default_tls_cacert = NULL;		/*!< File name: Default CA cert to use for curl TLS connection */
74
+char		*default_tls_clientcert = NULL;		/*!< File name: Default client certificate to use for curl TLS connection */
75
+char		*default_tls_clientkey = NULL;		/*!< File name: Key in PEM format that belongs to client cert */
76
+unsigned int	default_tls_verifyserver = 1;		/*!< 0 = Do not verify TLS server cert. 1 = Verify TLS cert (default) */
77
+char 		*default_http_proxy = NULL;		/*!< Default HTTP proxy to use */
78
+unsigned int	default_http_proxy_port = 0;		/*!< Default HTTP proxy port to use */
79
+unsigned int	default_http_follow_redirect = 0;	/*!< Follow HTTP redirects CURLOPT_FOLLOWLOCATION */
80
+char 		*default_useragent = CURL_USER_AGENT;	/*!< Default CURL useragent. Default "Kamailio Curl " */
81
+
82
+static curl_version_info_data *curl_info;
83
+
84
+/* lock for configuration access */
85
+static gen_lock_t *conf_lock = NULL;
86
+
87
+
88
+/* Module management function prototypes */
89
+static int mod_init(void);
90
+static int child_init(int);
91
+static void destroy(void);
92
+
93
+/* Fixup functions to be defined later */
94
+static int fixup_http_query_get(void** param, int param_no);
95
+static int fixup_free_http_query_get(void** param, int param_no);
96
+static int fixup_http_query_post(void** param, int param_no);
97
+static int fixup_free_http_query_post(void** param, int param_no);
98
+
99
+static int fixup_curl_connect(void** param, int param_no);
100
+static int fixup_free_curl_connect(void** param, int param_no);
101
+static int fixup_curl_connect_post(void** param, int param_no);
102
+static int fixup_free_curl_connect_post(void** param, int param_no);
103
+
104
+/* Wrappers for http_query to be defined later */
105
+static int w_http_query(struct sip_msg* _m, char* _url, char* _result);
106
+static int w_http_query_post(struct sip_msg* _m, char* _url, char* _post, char* _result);
107
+static int w_curl_connect(struct sip_msg* _m, char* _con, char * _url, char* _result);
108
+static int w_curl_connect_post(struct sip_msg* _m, char* _con, char * _url, char* _result, char* _ctype, char* _data);
109
+
110
+/* forward function */
111
+static int curl_con_param(modparam_t type, void* val);
112
+static int pv_parse_curlerror(pv_spec_p sp, str *in);
113
+static int pv_get_curlerror(struct sip_msg *msg, pv_param_t *param, pv_value_t *res);
114
+static int pv_parse_curlredirect(pv_spec_p sp, str *in);
115
+static int pv_get_curlredirect(struct sip_msg *msg, pv_param_t *param, pv_value_t *res);
116
+
117
+/* Exported functions */
118
+static cmd_export_t cmds[] = {
119
+    {"curl_http_query", (cmd_function)w_http_query, 2, fixup_http_query_get,
120
+     fixup_free_http_query_get,
121
+     REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
122
+    {"curl_http_query", (cmd_function)w_http_query_post, 3, fixup_http_query_post,
123
+     fixup_free_http_query_post,
124
+     REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
125
+    {"curl_connect", (cmd_function)w_curl_connect, 3, fixup_curl_connect,
126
+     fixup_free_curl_connect,
127
+     REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
128
+    {"curl_connect", (cmd_function)w_curl_connect_post, 5, fixup_curl_connect_post,
129
+     fixup_free_curl_connect_post,
130
+     REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
131
+};
132
+
133
+
134
+/* Exported parameters */
135
+static param_export_t params[] = {
136
+    	{"connection_timeout", INT_PARAM, &default_connection_timeout},
137
+	{"curlcon",  PARAM_STRING|USE_FUNC_PARAM, (void*)curl_con_param},
138
+	{"tlscacert", PARAM_STRING,  &default_tls_cacert },
139
+	{"tlsclientcert", PARAM_STRING, &default_tls_clientcert },
140
+	{"tlsclientkey", PARAM_STRING, &default_tls_clientkey },
141
+	{"tlsverifyserver", INT_PARAM, &default_tls_verifyserver },
142
+	{"httpproxyport", INT_PARAM, &default_http_proxy_port },
143
+	{"httpproxy", PARAM_STRING, &default_http_proxy},
144
+	{"httpredirect", INT_PARAM, &default_http_follow_redirect },
145
+	{"useragent", PARAM_STRING,  &default_useragent },
146
+    	{0, 0, 0}
147
+};
148
+
149
+//		str	default_tls_clientcert;			/*!< File name: Default client certificate to use for curl TLS connection */
150
+//		str	default_tls_clientkey;			/*!< File name: Key in PEM format that belongs to client cert */
151
+//		int	default_tls_verifyserver = 1;		/*!< 0 = Do not verify TLS server cert. 1 = Verify TLS cert (default) */
152
+//		str	default_http_proxy;			/*!< Default HTTP proxy to use */
153
+//		int	default_http_proxy_port;		/*!< Default HTTP proxy port to use */
154
+//		int	default_http_follow_redirect = 0;	/*!< Follow HTTP redirects CURLOPT_FOLLOWLOCATION */
155
+//		str	default_useragent;			/*!< Default CURL useragent. Default "Kamailio Curl " */
156
+
157
+/*!
158
+ * \brief Exported Pseudo variables
159
+ */
160
+static pv_export_t mod_pvs[] = {
161
+    {{"curlerror", (sizeof("curlerror")-1)}, /* Curl error codes */
162
+     PVT_OTHER, pv_get_curlerror, 0,
163
+	pv_parse_curlerror, 0, 0, 0},
164
+    {{"curlredirect", (sizeof("redirect")-1)}, /* Curl error codes */
165
+     PVT_OTHER, pv_get_curlredirect, 0,
166
+	pv_parse_curlredirect, 0, 0, 0},
167
+    {{0, 0}, 0, 0, 0, 0, 0, 0, 0}
168
+};
169
+
170
+/* Module interface */
171
+struct module_exports exports = {
172
+    "curl",
173
+    DEFAULT_DLFLAGS, /* dlopen flags */
174
+    cmds,      /* Exported functions */
175
+    params,    /* Exported parameters */
176
+    0,         /* exported statistics */
177
+    0,   	/* exported MI functions */
178
+    mod_pvs,         /* exported pseudo-variables */
179
+    0,         /* extra processes */
180
+    mod_init,  /* module initialization function */
181
+    0,         /* response function*/
182
+    destroy,   /* destroy function */
183
+    child_init /* per-child init function */
184
+};
185
+
186
+counter_handle_t connections;	/* Number of connection definitions */
187
+counter_handle_t connok;	/* Successful Connection attempts */
188
+counter_handle_t connfail;	/* Failed Connection attempts */
189
+
190
+
191
+
192
+static int init_shmlock(void)
193
+{
194
+	return 0;
195
+}
196
+
197
+
198
+static void destroy_shmlock(void)
199
+{
200
+	;
201
+}
202
+
203
+/* Init counters */
204
+static void curl_counter_init()
205
+{
206
+        counter_register(&connections, "curl", "connections", 0, 0, 0, "Counter of connection definitions (curlcon)", 0);
207
+        counter_register(&connok, "curl", "connok", 0, 0, 0, "Counter of successful connections (200 OK)", 0);
208
+        counter_register(&connfail, "curl", "connfail", 0, 0, 0, "Counter of failed connections (not 200 OK)", 0);
209
+}
210
+
211
+
212
+/* Module initialization function */
213
+static int mod_init(void)
214
+{
215
+	
216
+	LM_DBG("init curl module\n");
217
+
218
+	/* Initialize curl */
219
+	if (curl_global_init(CURL_GLOBAL_ALL)) {
220
+		LM_ERR("curl_global_init failed\n");
221
+		return -1;
222
+	}
223
+	curl_info = curl_version_info(CURLVERSION_NOW);
224
+
225
+	if(curl_init_rpc() < 0)
226
+        {
227
+                LM_ERR("failed to register RPC commands\n");
228
+                return -1;
229
+        }
230
+
231
+	if (init_shmlock() != 0) {
232
+		LM_CRIT("cannot initialize shmlock.\n");
233
+		return -1;
234
+	}
235
+
236
+	curl_counter_init();
237
+	counter_add(connections, curl_connection_count());
238
+
239
+	if (default_connection_timeout == 0) {
240
+		LM_ERR("CURL connection timeout set to zero. Using default 4 secs\n");
241
+		default_connection_timeout = 4;
242
+	}
243
+	if (default_http_proxy_port == 0) {
244
+		LM_INFO("HTTP proxy port set to 0. Disabling HTTP proxy\n");
245
+	}
246
+
247
+
248
+	LM_DBG("**** init curl module done. Curl version: %s SSL %s\n", curl_info->version, curl_info->ssl_version);
249
+	LM_DBG("**** init curl: Number of connection objects: %d \n", curl_connection_count());
250
+	LM_DBG("**** init curl: User Agent: %s \n", default_useragent);
251
+	LM_DBG("**** init curl: HTTPredirect: %d \n", default_http_follow_redirect);
252
+	LM_DBG("**** init curl: Client Cert: %s Key %s\n", default_tls_clientcert, default_tls_clientkey);
253
+	LM_DBG("**** init curl: CA Cert: %s \n", default_tls_cacert);
254
+	LM_DBG("**** init curl: HTTP Proxy: %s Port %d\n", default_http_proxy, default_http_proxy_port);
255
+
256
+	LM_DBG("Extra: Curl supports %s %s %s \n",
257
+			(curl_info->features & CURL_VERSION_SSL ? "SSL" : ""),
258
+			(curl_info->features & CURL_VERSION_IPV6 ? "IPv6" : ""),
259
+			(curl_info->features & CURL_VERSION_IDN ? "IDN" : "")
260
+		 );
261
+	return 0;
262
+}
263
+
264
+/*! Returns TRUE if curl supports TLS */
265
+int curl_support_tls()
266
+{
267
+	return (curl_info->features & CURL_VERSION_SSL);
268
+}
269
+
270
+/*! Returns TRUE if curl supports IPv6 */
271
+int curl_support_ipv6()
272
+{
273
+	return (curl_info->features & CURL_VERSION_IPV6);
274
+}
275
+
276
+
277
+/* Child initialization function */
278
+static int child_init(int rank)
279
+{	
280
+	if (rank==PROC_INIT || rank==PROC_MAIN || rank==PROC_TCP_MAIN) {
281
+		return 0; /* do nothing for the main process */
282
+	}
283
+
284
+    	return 0;
285
+}
286
+
287
+
288
+static void destroy(void)
289
+{
290
+	/* Cleanup curl */
291
+	curl_global_cleanup();
292
+	destroy_shmlock();
293
+}
294
+
295
+
296
+
297
+/**
298
+ * parse curlcon module parameter
299
+ */
300
+int curl_con_param(modparam_t type, void *val)
301
+{
302
+	if(val == NULL) {
303
+		goto error;
304
+	}
305
+
306
+	LM_DBG("**** CURL got modparam curlcon \n");
307
+	return curl_parse_param((char*)val);
308
+error:
309
+	return -1;
310
+
311
+}
312
+
313
+/* Fixup functions */
314
+
315
+/*
316
+ * Fix http_query params: url (string that may contain pvars) and
317
+ * result (writable pvar).
318
+ */
319
+static int fixup_http_query_get(void** param, int param_no)
320
+{
321
+    if (param_no == 1) {
322
+	return fixup_spve_null(param, 1);
323
+    }
324
+
325
+    if (param_no == 2) {
326
+	if (fixup_pvar_null(param, 1) != 0) {
327
+	    LM_ERR("failed to fixup result pvar\n");
328
+	    return -1;
329
+	}
330
+	if (((pv_spec_t *)(*param))->setf == NULL) {
331
+	    LM_ERR("result pvar is not writeble\n");
332
+	    return -1;
333
+	}
334
+	return 0;
335
+    }
336
+
337
+    LM_ERR("invalid parameter number <%d>\n", param_no);
338
+    return -1;
339
+}
340
+
341
+/*
342
+ * Free http_query params.
343
+ */
344
+static int fixup_free_http_query_get(void** param, int param_no)
345
+{
346
+    if (param_no == 1) {
347
+	LM_WARN("free function has not been defined for spve\n");
348
+	return 0;
349
+    }
350
+
351
+    if (param_no == 2) {
352
+	return fixup_free_pvar_null(param, 1);
353
+    }
354
+    
355
+    LM_ERR("invalid parameter number <%d>\n", param_no);
356
+    return -1;
357
+}
358
+
359
+
360
+/*
361
+ * Fix curl_connect params: connection(string/pvar) url (string that may contain pvars) and
362
+ * result (writable pvar).
363
+ */
364
+static int fixup_curl_connect(void** param, int param_no)
365
+{
366
+
367
+    if ((param_no == 1) || (param_no == 2)) {
368
+	/* We want char * strings */
369
+	return 0;
370
+	}
371
+    if (param_no == 3) {
372
+	if (fixup_pvar_null(param, 1) != 0) {
373
+	    LM_ERR("failed to fixup result pvar\n");
374
+	    return -1;
375
+	}
376
+	if (((pv_spec_t *)(*param))->setf == NULL) {
377
+	    LM_ERR("result pvar is not writeble\n");
378
+	    return -1;
379
+	}
380
+	return 0;
381
+    }
382
+
383
+    LM_ERR("invalid parameter number <%d>\n", param_no);
384
+    return -1;
385
+}
386
+
387
+/*
388
+ * Fix curl_connect params when posting (5 parameters): 
389
+ *	connection, url, content-type, data, pvar
390
+ */
391
+static int fixup_curl_connect_post(void** param, int param_no)
392
+{
393
+
394
+    if (param_no == 1 || param_no == 2 || param_no == 3 || param_no == 4) {
395
+	/* We want char * strings */
396
+	/* At some point we need to allow pvars in the string. */
397
+	return 0;
398
+	}
399
+    if (param_no == 5) {
400
+	if (fixup_pvar_null(param, 1) != 0) {
401
+	    LM_ERR("failed to fixup result pvar\n");
402
+	    return -1;
403
+	}
404
+	if (((pv_spec_t *)(*param))->setf == NULL) {
405
+	    LM_ERR("result pvar is not writeble\n");
406
+	    return -1;
407
+	}
408
+	return 0;
409
+    }
410
+
411
+    LM_ERR("invalid parameter number <%d>\n", param_no);
412
+    return -1;
413
+}
414
+
415
+
416
+/*
417
+ * Free curl_connect params.
418
+ */
419
+static int fixup_free_curl_connect_post(void** param, int param_no)
420
+{
421
+    if (param_no == 1 || param_no == 2 || param_no == 3 || param_no == 4) {
422
+	LM_WARN("free function has not been defined for spve\n");
423
+	return 0;
424
+    }
425
+
426
+    if (param_no == 5) {
427
+	return fixup_free_pvar_null(param, 5);
428
+    }
429
+    
430
+    LM_ERR("invalid parameter number <%d>\n", param_no);
431
+    return -1;
432
+}
433
+
434
+/*
435
+ * Free curl_connect params.
436
+ */
437
+static int fixup_free_curl_connect(void** param, int param_no)
438
+{
439
+    if ((param_no == 1) || (param_no == 2)) {
440
+	LM_WARN("free function has not been defined for spve\n");
441
+	return 0;
442
+    }
443
+
444
+    if (param_no == 5) {
445
+	return fixup_free_pvar_null(param, 5);
446
+    }
447
+    
448
+    LM_ERR("invalid parameter number <%d>\n", param_no);
449
+    return -1;
450
+}
451
+
452
+/*
453
+ * Wrapper for Curl_connect (GET)
454
+ */
455
+static int w_curl_connect(struct sip_msg* _m, char* _con, char * _url, char* _result) {
456
+//	curl_con_query_url(struct sip_msg* _m, char *connection, char* _url, char* _result, const char *contenttype, char* _post)
457
+	LM_DBG("**** Curl Connection %s URL %s Result var %s\n", _con, _url, _result);
458
+
459
+	return curl_con_query_url(_m, _con, _url, _result, NULL, NULL);
460
+}
461
+
462
+/*
463
+ * Wrapper for Curl_connect (POST)
464
+ */
465
+static int w_curl_connect_post(struct sip_msg* _m, char* _con, char * _url, char* _ctype, char* _data, char *_result) {
466
+	return curl_con_query_url(_m, _con, _url, _result, _ctype, _data);
467
+}
468
+
469
+
470
+/*!
471
+ * Fix http_query params: url (string that may contain pvars) and
472
+ * result (writable pvar).
473
+ */
474
+static int fixup_http_query_post(void** param, int param_no)
475
+{
476
+    if ((param_no == 1) || (param_no == 2)) {
477
+	return fixup_spve_null(param, 1);
478
+    }
479
+
480
+    if (param_no == 3) {
481
+	if (fixup_pvar_null(param, 1) != 0) {
482
+	    LM_ERR("failed to fixup result pvar\n");
483
+	    return -1;
484
+	}
485
+	if (((pv_spec_t *)(*param))->setf == NULL) {
486
+	    LM_ERR("result pvar is not writeble\n");
487
+	    return -1;
488
+	}
489
+	return 0;
490
+    }
491
+
492
+    LM_ERR("invalid parameter number <%d>\n", param_no);
493
+    return -1;
494
+}
495
+
496
+/*!
497
+ * Free http_query params.
498
+ */
499
+static int fixup_free_http_query_post(void** param, int param_no)
500
+{
501
+    if ((param_no == 1) || (param_no == 2)) {
502
+	LM_WARN("free function has not been defined for spve\n");
503
+	return 0;
504
+    }
505
+
506
+    if (param_no == 3) {
507
+	return fixup_free_pvar_null(param, 1);
508
+    }
509
+    
510
+    LM_ERR("invalid parameter number <%d>\n", param_no);
511
+    return -1;
512
+}
513
+
514
+/*!
515
+ * Wrapper for HTTP-Query (GET)
516
+ */
517
+static int w_http_query(struct sip_msg* _m, char* _url, char* _result) {
518
+	return http_query(_m, _url, _result, NULL);
519
+}
520
+
521
+
522
+/*!
523
+ * Wrapper for HTTP-Query (POST-Variant)
524
+ */
525
+static int w_http_query_post(struct sip_msg* _m, char* _url, char* _post, char* _result) {
526
+	return http_query(_m, _url, _result, _post);
527
+}
528
+
529
+/*!
530
+ * Parse arguments to  pv $curlerror
531
+ */
532
+static int pv_parse_curlerror(pv_spec_p sp, str *in)
533
+{
534
+	int cerr  = 0;
535
+	if(sp==NULL || in==NULL || in->len<=0)
536
+		return -1;
537
+
538
+	
539
+	cerr = atoi(in->s);
540
+	LM_DBG(" =====> CURL ERROR %d \n", cerr);
541
+	sp->pvp.pvn.u.isname.name.n = cerr;
542
+
543
+	sp->pvp.pvn.type = PV_NAME_INTSTR;
544
+	sp->pvp.pvn.u.isname.type = 0;
545
+
546
+	return 0;
547
+}
548
+
549
+/*
550
+ * PV - return curl error explanation as string
551
+ */
552
+static int pv_get_curlerror(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
553
+{
554
+	str curlerr;
555
+	char *err = NULL;
556
+	CURLcode codeerr;
557
+
558
+	if(param==NULL) {
559
+		return -1;
560
+	}
561
+
562
+	/* cURL error codes does not collide with HTTP codes */
563
+	if (param->pvn.u.isname.name.n < 0 || param->pvn.u.isname.name.n > 999 ) {
564
+		err = "Bad CURL error code";
565
+	}
566
+	if (param->pvn.u.isname.name.n > 99) {
567
+		err = "HTTP result code";
568
+	}
569
+	if (err == NULL) {
570
+		err = (char *) curl_easy_strerror(param->pvn.u.isname.name.n);
571
+	}
572
+	curlerr.s = err;
573
+	curlerr.len = strlen(err);
574
+
575
+	return pv_get_strval(msg, param, res, &curlerr);
576
+}
577
+
578
+/*!
579
+ * Parse arguments to  pv $curlredirect
580
+ */
581
+static int pv_parse_curlredirect(pv_spec_p sp, str *in)
582
+{
583
+	int cerr  = 0;
584
+	if(sp==NULL || in==NULL || in->len<=0) {
585
+		return -1;
586
+	}
587
+
588
+	// DO SOMETHING HERE
589
+	return 0;
590
+}
591
+
592
+/*
593
+ * PV - return curl redirect URL for curlcon
594
+ *	$curlredirect("curlcon");
595
+ */
596
+static int pv_get_curlredirect(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
597
+{
598
+	str redirecturl;
599
+
600
+	if(param==NULL) {
601
+		return -1;
602
+	}
603
+
604
+	// DO SOMETHING HERE
605
+	return pv_get_strval(msg, param, res, &redirecturl);
606
+}
0 607
new file mode 100644
... ...
@@ -0,0 +1,89 @@
1
+/*
2
+ * header file of curl.c
3
+ *
4
+ * Copyright (C) 2008 Juha Heinanen
5
+ *
6
+ * This file is part of Kamailio, a free SIP server.
7
+ *
8
+ * Kamailio is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version
12
+ *
13
+ * Kamailio is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
+ * GNU General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU General Public License 
19
+ * along with this program; if not, write to the Free Software 
20
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21
+ *
22
+ */
23
+
24
+/*!
25
+ * \file
26
+ * \brief Kamailio curl :: Core include file
27
+ * \ingroup curl
28
+ * Module: \ref curl
29
+ */
30
+
31
+#ifndef CURL_H
32
+#define CURL_H
33
+
34
+#include "../../str.h"
35
+#include "../../counters.h"
36
+#include "../../lib/srdb1/db.h"
37
+
38
+extern unsigned int	default_connection_timeout;
39
+extern char	*default_tls_cacert;			/*!< File name: Default CA cert to use for curl TLS connection */
40
+extern char	*default_tls_clientcert;		/*!< File name: Default client certificate to use for curl TLS connection */
41
+extern char	*default_tls_clientkey;			/*!< File name: Key in PEM format that belongs to client cert */
42
+extern unsigned int	default_tls_verifyserver;		/*!< 0 = Do not verify TLS server cert. 1 = Verify TLS cert (default) */
43
+extern char 	*default_http_proxy;			/*!< Default HTTP proxy to use */
44
+extern unsigned int	default_http_proxy_port;		/*!< Default HTTP proxy port to use */
45
+extern unsigned int	default_http_follow_redirect;	/*!< Follow HTTP redirects CURLOPT_FOLLOWLOCATION */
46
+extern char 	*default_useragent;			/*!< Default CURL useragent. Default "Kamailio Curl " */
47
+
48
+extern counter_handle_t connections;	/* Number of connection definitions */
49
+extern counter_handle_t connok;	/* Successful Connection attempts */
50
+extern counter_handle_t connfail;	/* Failed Connection attempts */
51
+
52
+/* Curl  stream object  */
53
+typedef struct {
54
+	char		*buf;
55
+	size_t		curr_size;
56
+	size_t		pos;
57
+} http_res_stream_t;
58
+
59
+
60
+/*! Predefined connection objects */
61
+typedef struct _curl_con
62
+{
63
+	str name;			/*!< Connection name */
64
+	unsigned int conid;		/*!< Connection ID */
65
+	str url;			/*!< The URL without schema (host + base URL)*/
66
+	str schema;			/*!< The URL schema */
67
+	str username;			/*!< The username to use for auth */
68
+	str password;			/*!< The password to use for auth */
69
+	str failover;			/*!< Another connection to use if this one fails */
70
+	str cacert;			/*!< File name of CA cert to use */
71
+	str clientcert;			/*!< File name of CA client cert */
72
+	str useragent;			/*!< Useragent to use for this connection */
73
+	int tls_verifyserver;		/*!< TRUE if server cert needs to be verified */
74
+	int http_follow_redirect;	/*!< TRUE if we should follow HTTP 302 redirects */
75
+	unsigned int port;		/*!< The port to connect to */
76
+	int timeout;			/*!< Timeout for this connection */
77
+	http_res_stream_t *stream;	/*!< Curl stream */
78
+	struct _curl_con *next;		/*!< next connection */
79
+	char redirecturl[512];		/*!< Last redirect URL - to use for $curlredirect(curlcon) pv */
80
+} curl_con_t;
81
+
82
+
83
+/*! Returns true if CURL supports TLS */
84
+extern int curl_support_tls();
85
+
86
+/*! Returns TRUE if curl supports IPv6 */
87
+extern int curl_support_ipv6();
88
+
89
+#endif /* CURL_H */
0 90
new file mode 100644
... ...
@@ -0,0 +1,361 @@
1
+/*
2
+ * Copyright (C) 2015 Olle E. Johansson, Edvina AB
3
+ *
4
+ * Based on code from sqlops and htable by Elena-Ramona:
5
+ * Copyright (C) 2008 Elena-Ramona Modroiu (asipto.com)
6
+ *
7
+ * This file is part of kamailio, a free SIP server.
8
+ *
9
+ * Kamailio is free software; you can redistribute it and/or modify
10
+ * it under the terms of the GNU General Public License as published by
11
+ * the Free Software Foundation; either version 2 of the License, or
12
+ * (at your option) any later version
13
+ *
14
+ * Kamailio is distributed in the hope that it will be useful,
15
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
+ * GNU General Public License for more details.
18
+ *
19
+ * You should have received a copy of the GNU General Public License
20
+ * along with this program; if not, write to the Free Software
21
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22
+ */
23
+
24
+/*! \file
25
+ * \brief  Kamailio curl :: Connectoin handling
26
+ * \ingroup curl
27
+ */
28
+
29
+#include "../../hashes.h"
30
+#include "../../dprint.h"
31
+#include "../../parser/parse_param.h"
32
+#include "../../usr_avp.h"
33
+#include "curl.h"
34
+#include "curlcon.h"
35
+
36
+#define KEYVALUE_TYPE_NONE	0
37
+#define KEYVALUE_TYPE_PARAMS	1
38
+
39
+
40
+curl_con_t *_curl_con_root = NULL;
41
+
42
+/* Forward declaration */
43
+curl_con_t *curl_init_con(str *name);
44
+
45
+/*! Count the number of connections 
46
+ */
47
+unsigned int curl_connection_count()
48
+{
49
+	unsigned int i = 0;
50
+	curl_con_t *cc;
51
+	cc = _curl_con_root;
52
+	while(cc)
53
+	{
54
+		i++;
55
+		cc = cc->next;
56
+	}
57
+	return i;
58
+}
59
+
60
+
61
+/*! Find CURL connection by name
62
+ */
63
+curl_con_t* curl_get_connection(str *name)
64
+{
65
+	curl_con_t *cc;
66
+	unsigned int conid;
67
+
68
+	conid = core_case_hash(name, 0, 0);
69
+
70
+	cc = _curl_con_root;
71
+	while(cc)
72
+	{
73
+		if(conid==cc->conid && cc->name.len==name->len
74
+				&& strncmp(cc->name.s, name->s, name->len)==0)
75
+			return cc;
76
+		cc = cc->next;
77
+	}
78
+	return NULL;
79
+}
80
+
81
+
82
+/*! Parse the curlcon module parameter
83
+ *
84
+ *	Syntax:
85
+ *		name => proto://user:password@server/url/url
86
+ *		name => proto://server/url/url
87
+ *		name => proto://server/url/url;param=value;param=value
88
+ *
89
+ *		the url is very much like CURLs syntax
90
+ *		the url is a base url where you can add local address
91
+ */
92
+int curl_parse_param(char *val)
93
+{
94
+	str name	= STR_NULL;;
95
+	str schema	= STR_NULL;
96
+	str url		= STR_NULL;
97
+	str username	= STR_NULL;
98
+	str password	= STR_NULL;
99
+	str params	= STR_NULL;
100
+	str failover	= STR_NULL;
101
+	unsigned int timeout	= default_connection_timeout;
102
+	str useragent   = { default_useragent, strlen(default_useragent) };
103
+	unsigned int http_follow_redirect = default_http_follow_redirect;
104
+
105
+	str in;
106
+	char *p;
107
+	char *u;
108
+	param_t *conparams = NULL;
109
+	curl_con_t *cc;
110
+
111
+	username.len = 0;
112
+	password.len = 0;
113
+	LM_INFO("curl modparam parsing starting\n");
114
+	LM_DBG("modparam curlcon: %s\n", val);
115
+
116
+	/* parse: name=>http_url*/
117
+	in.s = val;
118
+	in.len = strlen(in.s);
119
+	p = in.s;
120
+
121
+	/* Skip white space */
122
+	while(p < in.s+in.len && (*p==' ' || *p=='\t' || *p=='\n' || *p=='\r')) {
123
+		p++;
124
+	}
125
+	if(p > in.s+in.len || *p=='\0') {
126
+		goto error;
127
+	}
128
+
129
+	/* This is the connection name */
130
+	name.s = p;
131
+	/* Skip to whitespace */
132
+	while(p < in.s + in.len)
133
+	{
134
+		if(*p=='=' || *p==' ' || *p=='\t' || *p=='\n' || *p=='\r') {
135
+			break;
136
+		}
137
+		p++;
138
+	}
139
+	if(p > in.s+in.len || *p=='\0') {
140
+		goto error;
141
+	}
142
+	name.len = p - name.s;
143
+	if(*p != '=')
144
+	{
145
+		/* Skip whitespace */
146
+		while(p<in.s+in.len && (*p==' ' || *p=='\t' || *p=='\n' || *p=='\r')) {
147
+			p++;
148
+		}
149
+		if(p>in.s+in.len || *p=='\0' || *p!='=') {
150
+			goto error;
151
+		}
152
+	}
153
+	p++;
154
+	if(*p != '>') {
155
+		goto error;
156
+	}
157
+	p++;
158
+	/* Skip white space again */
159
+	while(p < in.s+in.len && (*p==' ' || *p=='\t' || *p=='\n' || *p=='\r')) {
160
+		p++;
161
+	}
162
+	schema.s = p;
163
+	/* Skip to colon ':' */
164
+	while(p < in.s + in.len)
165
+	{
166
+		if(*p == ':') {
167
+			break;
168
+		}
169
+		p++;
170
+	}
171
+	if(*p != ':') {
172
+		goto error;
173
+	}
174
+	schema.len = p - schema.s;
175
+	p++;	/* Skip the colon */
176
+	/* Skip two slashes */
177
+	if(*p != '/') {
178
+		goto error;
179
+	}
180
+	p++;
181
+	if(*p != '/') {
182
+		goto error;
183
+	}
184
+	p++;
185
+	/* We are now at the first character after :// */
186
+	url.s = p;
187
+	url.len = in.len + (int)(in.s - p);
188
+	u = p;
189
+
190
+	/* Now check if there is a @ character. If so, we need to parse the username
191
+	   and password */
192
+	/* Skip to at-sign '@' */
193
+	while(p < in.s + in.len)
194
+	{
195
+		if(*p == '@') {
196
+			break;
197
+		}
198
+		p++;
199
+	}
200
+	if (*p == '@') {
201
+		/* We have a username and possibly password - parse them out */
202
+		username.s = u;
203
+		while (u < p) {
204
+			if (*u == ':') {
205
+				break;
206
+			}
207
+			u++;
208
+		}
209
+		username.len = u - username.s;
210
+
211
+		/* We either have a : or a @ */
212
+		if (*u == ':') {
213
+			u++;
214
+			/* Go look for password */
215
+			password.s = u;
216
+			while (u < p) {
217
+				u++;
218
+			}
219
+			password.len = u - password.s;
220
+		}
221
+		p++;	/* Skip the at sign */
222
+		url.s = p;
223
+		url.len = in.len + (int)(in.s - p);
224
+	}
225
+	/* Reset P to beginning of URL and look for parameters - starting with ; */
226
+	p = url.s;
227
+	/* Skip to ';' or end of string */
228
+	while(p < url.s + url.len)
229
+	{
230
+		if(*p == ';') {
231
+			/* Cut off URL at the ; */
232
+			url.len = (int)(p - url.s);
233
+			break;
234
+		}
235
+		p++;
236
+	}
237
+	if (*p == ';') {
238
+		/* We have parameters */
239
+		str tok;
240
+		int_str ival;
241
+		int itype;
242
+		param_t *pit = NULL;
243
+
244
+		/* Adjust the URL length */
245
+
246
+		p++;		/* Skip the ; */
247
+		params.s = p;
248
+		params.len = in.len + (int) (in.s - p);
249
+		param_hooks_t phooks;
250
+
251
+		if (parse_params(&params, CLASS_ANY, &phooks, &conparams) < 0)
252
+                {
253
+                        LM_ERR("CURL failed parsing curlcon parameters value\n");
254
+                        goto error;
255
+                }
256
+
257
+		/* Have parameters */
258
+		for (pit = conparams; pit; pit=pit->next)
259
+		{
260
+			tok = pit->body;
261
+			if(pit->name.len==12 && strncmp(pit->name.s, "httpredirect", 12)==0) {
262
+				if(str2int(&tok, &http_follow_redirect) != 0) {
263
+					/* Bad value */
264
+					LM_DBG("curl connection [%.*s]: httpredirect bad value. Using default\n", name.len, name.s);
265
+					http_follow_redirect = default_http_follow_redirect;
266
+				}
267
+				if (http_follow_redirect != 0 && http_follow_redirect != 1) {
268
+					LM_DBG("curl connection [%.*s]: httpredirect bad value. Using default\n", name.len, name.s);
269
+					http_follow_redirect = default_http_follow_redirect;
270
+				}
271
+				LM_DBG("curl [%.*s] - httpredirect [%d]\n", pit->name.len, pit->name.s, http_follow_redirect);
272
+			} else if(pit->name.len==7 && strncmp(pit->name.s, "timeout", 7)==0) {
273
+				if(str2int(&tok, &timeout)!=0) {
274
+					/* Bad timeout */
275