4 * @brief Implementation of fetcher_t.
9 * Copyright (C) 2007 Andreas Steffen
10 * Hochschule fuer Technik Rapperswil
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version. See <fetcher://www.fsf.org/copyleft/gpl.txt>.
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24 #include <curl/curl.h>
36 typedef struct private_fetcher_t private_fetcher_t
;
39 * @brief Private Data of a fetcher_t object.
41 struct private_fetcher_t
{
48 * URI of the information source
54 * we use libcurl from http://curl.haxx.se/ as a fetcher
61 * we use libldap from http://www.openssl.org/ as a fetcher
69 * writes data into a dynamically resizeable chunk_t
70 * needed for libcurl responses
72 static size_t curl_write_buffer(void *ptr
, size_t size
, size_t nmemb
, void *data
)
74 size_t realsize
= size
* nmemb
;
75 chunk_t
*mem
= (chunk_t
*)data
;
77 mem
->ptr
= (u_char
*)realloc(mem
->ptr
, mem
->len
+ realsize
);
79 memcpy(&(mem
->ptr
[mem
->len
]), ptr
, realsize
);
86 * Implements fetcher_t.get for curl methods
88 static chunk_t
curl_get(private_fetcher_t
*this)
90 chunk_t response
= chunk_empty
;
96 chunk_t curl_response
= chunk_empty
;
97 char curl_error_buffer
[CURL_ERROR_SIZE
];
99 curl_easy_setopt(this->curl
, CURLOPT_URL
, this->uri
);
100 curl_easy_setopt(this->curl
, CURLOPT_WRITEFUNCTION
, curl_write_buffer
);
101 curl_easy_setopt(this->curl
, CURLOPT_WRITEDATA
, (void *)&curl_response
);
102 curl_easy_setopt(this->curl
, CURLOPT_ERRORBUFFER
, &curl_error_buffer
);
103 curl_easy_setopt(this->curl
, CURLOPT_FAILONERROR
, TRUE
);
104 curl_easy_setopt(this->curl
, CURLOPT_CONNECTTIMEOUT
, FETCHER_TIMEOUT
);
105 curl_easy_setopt(this->curl
, CURLOPT_NOSIGNAL
, TRUE
);
107 DBG1("sending curl request to '%s'...", this->uri
);
108 res
= curl_easy_perform(this->curl
);
112 DBG1("received valid curl response");
113 response
= chunk_clone(curl_response
);
117 DBG1("curl request failed: %s", curl_error_buffer
);
119 curl_free(curl_response
.ptr
);
122 DBG1("warning: libcurl fetching not compiled in");
128 * Implements fetcher_t.post.
130 static chunk_t
http_post(private_fetcher_t
*this, const char *request_type
, chunk_t request
)
132 chunk_t response
= chunk_empty
;
138 struct curl_slist
*headers
= NULL
;
139 chunk_t curl_response
= chunk_empty
;
140 char curl_error_buffer
[CURL_ERROR_SIZE
];
141 char content_type
[BUF_LEN
];
143 /* set content type header */
144 snprintf(content_type
, BUF_LEN
, "Content-Type: %s", request_type
);
145 headers
= curl_slist_append(headers
, content_type
);
148 curl_easy_setopt(this->curl
, CURLOPT_HTTPHEADER
, headers
);
149 curl_easy_setopt(this->curl
, CURLOPT_URL
, this->uri
);
150 curl_easy_setopt(this->curl
, CURLOPT_WRITEFUNCTION
, curl_write_buffer
);
151 curl_easy_setopt(this->curl
, CURLOPT_WRITEDATA
, (void *)&curl_response
);
152 curl_easy_setopt(this->curl
, CURLOPT_POSTFIELDS
, request
.ptr
);
153 curl_easy_setopt(this->curl
, CURLOPT_POSTFIELDSIZE
, request
.len
);
154 curl_easy_setopt(this->curl
, CURLOPT_ERRORBUFFER
, &curl_error_buffer
);
155 curl_easy_setopt(this->curl
, CURLOPT_FAILONERROR
, TRUE
);
156 curl_easy_setopt(this->curl
, CURLOPT_CONNECTTIMEOUT
, FETCHER_TIMEOUT
);
157 curl_easy_setopt(this->curl
, CURLOPT_NOSIGNAL
, TRUE
);
159 DBG1("sending http post request to '%s'...", this->uri
);
160 res
= curl_easy_perform(this->curl
);
164 DBG1("received valid http response");
165 response
= chunk_clone(curl_response
);
169 DBG1("http post request using libcurl failed: %s", curl_error_buffer
);
171 curl_slist_free_all(headers
);
172 curl_free(curl_response
.ptr
);
175 DBG1("warning: libcurl fetching not compiled in");
182 * Parses the result returned by an ldap query
184 static chunk_t
ldap_parse(LDAP
*ldap
, LDAPMessage
*result
)
186 chunk_t response
= chunk_empty
;
189 LDAPMessage
*entry
= ldap_first_entry(ldap
, result
);
193 BerElement
*ber
= NULL
;
196 attr
= ldap_first_attribute(ldap
, entry
, &ber
);
200 struct berval
**values
= ldap_get_values_len(ldap
, entry
, attr
);
204 if (values
[0] != NULL
)
206 response
.len
= values
[0]->bv_len
;
207 response
.ptr
= malloc(response
.len
);
208 memcpy(response
.ptr
, values
[0]->bv_val
, response
.len
);
210 if (values
[1] != NULL
)
212 ugh
= "more than one value was fetched - first selected";
217 ugh
= "no values in attribute";
219 ldap_value_free_len(values
);
223 ugh
= ldap_err2string(ldap_result2error(ldap
, entry
, 0));
229 ugh
= ldap_err2string(ldap_result2error(ldap
, entry
, 0));
235 ugh
= ldap_err2string(ldap_result2error(ldap
, result
, 0));
239 DBG1("ldap request failed: %s", ugh
);
246 * Implements fetcher_t.get for curl methods
248 static chunk_t
ldap_get(private_fetcher_t
*this)
250 chunk_t response
= chunk_empty
;
257 int ldap_version
= LDAP_VERSION3
;
259 struct timeval timeout
;
261 timeout
.tv_sec
= FETCHER_TIMEOUT
;
264 ldap_set_option(this->ldap
, LDAP_OPT_PROTOCOL_VERSION
, &ldap_version
);
265 ldap_set_option(this->ldap
, LDAP_OPT_NETWORK_TIMEOUT
, &timeout
);
267 DBG1("sending ldap request to '%s'...", this->uri
);
269 rc
= ldap_simple_bind_s(this->ldap
, NULL
, NULL
);
270 if (rc
== LDAP_SUCCESS
)
274 timeout
.tv_sec
= FETCHER_TIMEOUT
;
277 rc
= ldap_search_st(this->ldap
, this->lurl
->lud_dn
,
278 this->lurl
->lud_scope
,
279 this->lurl
->lud_filter
,
280 this->lurl
->lud_attrs
,
281 0, &timeout
, &result
);
283 if (rc
== LDAP_SUCCESS
)
285 response
= ldap_parse(this->ldap
, result
);
288 DBG1("received valid ldap response");
290 ldap_msgfree(result
);
294 ugh
= ldap_err2string(rc
);
299 ugh
= ldap_err2string(rc
);
301 ldap_unbind_s(this->ldap
);
305 DBG1("ldap request failed: %s", ugh
);
309 DBG1("warning: libldap fetching not compiled in");
310 #endif /* !LIBLDAP */
315 * Implements fetcher_t.destroy
317 static void destroy(private_fetcher_t
*this)
322 curl_easy_cleanup(this->curl
);
329 ldap_free_urldesc(this->lurl
);
337 * Described in header.
339 fetcher_t
*fetcher_create(const char *uri
)
341 private_fetcher_t
*this = malloc_thing(private_fetcher_t
);
355 if (strlen(uri
) >= 4 && strncasecmp(uri
, "ldap", 4) == 0)
358 int rc
= ldap_url_parse(uri
, &this->lurl
);
360 if (rc
== LDAP_SUCCESS
)
362 this->ldap
= ldap_init(this->lurl
->lud_host
,
363 this->lurl
->lud_port
);
367 DBG1("ldap: %s", ldap_err2string(rc
));
371 this->public.get
= (chunk_t (*) (fetcher_t
*))ldap_get
;
376 this->curl
= curl_easy_init();
377 if (this->curl
== NULL
)
379 DBG1("curl_easy_init_failed()");
382 this->public.get
= (chunk_t (*) (fetcher_t
*))curl_get
;
385 /* public functions */
386 this->public.post
= (chunk_t (*) (fetcher_t
*,const char*,chunk_t
))http_post
;
387 this->public.destroy
= (void (*) (fetcher_t
*))destroy
;
389 return &this->public;
393 * Described in header.
395 void fetcher_initialize(void)
400 /* initialize libcurl */
401 DBG1("initializing libcurl");
402 res
= curl_global_init(CURL_GLOBAL_NOTHING
);
405 DBG1("libcurl could not be initialized: %s", curl_easy_strerror(res
));
411 * Described in header.
413 void fetcher_finalize(void)
416 /* finalize libcurl */
417 DBG1("finalizing libcurl");
418 curl_global_cleanup();