Annotation of embedaddon/strongswan/src/libstrongswan/plugins/curl/curl_fetcher.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2008 Martin Willi
3: * Copyright (C) 2007 Andreas Steffen
4: * HSR Hochschule fuer Technik Rapperswil
5: *
6: * This program is free software; you can redistribute it and/or modify it
7: * under the terms of the GNU General Public License as published by the
8: * Free Software Foundation; either version 2 of the License, or (at your
9: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10: *
11: * This program is distributed in the hope that it will be useful, but
12: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14: * for more details.
15: */
16:
17: #include <curl/curl.h>
18:
19: #include <library.h>
20: #include <utils/debug.h>
21:
22: #include "curl_fetcher.h"
23:
24: #define CONNECT_TIMEOUT 10
25:
26: typedef struct private_curl_fetcher_t private_curl_fetcher_t;
27:
28: /**
29: * private data of a curl_fetcher_t object.
30: */
31: struct private_curl_fetcher_t {
32: /**
33: * Public data
34: */
35: curl_fetcher_t public;
36:
37: /**
38: * CURL handle
39: */
40: CURL* curl;
41:
42: /**
43: * Optional HTTP headers
44: */
45: struct curl_slist *headers;
46:
47: /**
48: * Callback function
49: */
50: fetcher_callback_t cb;
51:
52: /**
53: * Variable that receives the response code
54: */
55: u_int *result;
56:
57: /**
58: * Timeout for a transfer
59: */
60: long timeout;
61:
62: /**
63: * Maximum number of redirects to follow
64: */
65: long redir;
66: };
67:
68: /**
69: * Data to pass to curl callback
70: */
71: typedef struct {
72: fetcher_callback_t cb;
73: void *user;
74: } cb_data_t;
75:
76: /**
77: * Curl callback function, invokes fetcher_callback_t function
78: */
79: static size_t curl_cb(void *ptr, size_t size, size_t nmemb, cb_data_t *data)
80: {
81: size_t realsize = size * nmemb;
82:
83: if (data->cb(data->user, chunk_create(ptr, realsize)))
84: {
85: return realsize;
86: }
87: return 0;
88: }
89:
90: METHOD(fetcher_t, fetch, status_t,
91: private_curl_fetcher_t *this, char *uri, void *userdata)
92: {
93: char error[CURL_ERROR_SIZE], *enc_uri, *p1, *p2;
94: CURLcode curl_status;
95: status_t status;
96: long result = 0;
97: cb_data_t data = {
98: .cb = this->cb,
99: .user = userdata,
100: };
101:
102: if (this->cb == fetcher_default_callback)
103: {
104: *(chunk_t*)userdata = chunk_empty;
105: }
106:
107: /* the URI has to be URL-encoded, we only replace spaces as replacing other
108: * characters (e.g. '/' or ':') would render the URI invalid */
109: enc_uri = strreplace(uri, " ", "%20");
110:
111: if (curl_easy_setopt(this->curl, CURLOPT_URL, enc_uri) != CURLE_OK)
112: { /* URL type not supported by curl */
113: status = NOT_SUPPORTED;
114: goto out;
115: }
116: curl_easy_setopt(this->curl, CURLOPT_ERRORBUFFER, error);
117: curl_easy_setopt(this->curl, CURLOPT_FAILONERROR, FALSE);
118: curl_easy_setopt(this->curl, CURLOPT_NOSIGNAL, TRUE);
119: if (this->timeout)
120: {
121: curl_easy_setopt(this->curl, CURLOPT_TIMEOUT, this->timeout);
122: }
123: curl_easy_setopt(this->curl, CURLOPT_CONNECTTIMEOUT, CONNECT_TIMEOUT);
124: curl_easy_setopt(this->curl, CURLOPT_FOLLOWLOCATION, TRUE);
125: curl_easy_setopt(this->curl, CURLOPT_MAXREDIRS, this->redir);
126: curl_easy_setopt(this->curl, CURLOPT_WRITEFUNCTION, (void*)curl_cb);
127: curl_easy_setopt(this->curl, CURLOPT_WRITEDATA, &data);
128: if (this->headers)
129: {
130: curl_easy_setopt(this->curl, CURLOPT_HTTPHEADER, this->headers);
131: }
132:
133: /* if the URI contains a username[:password] prefix then mask it */
134: p1 = strstr(uri, "://");
135: p2 = strchr(uri, '@');
136: if (p1 && p2)
137: {
138: DBG2(DBG_LIB, " sending request to '%.*sxxxx%s'...", p1+3-uri, uri, p2);
139: }
140: else
141: {
142: DBG2(DBG_LIB, " sending request to '%s'...", uri);
143: }
144: curl_status = curl_easy_perform(this->curl);
145: switch (curl_status)
146: {
147: case CURLE_UNSUPPORTED_PROTOCOL:
148: status = NOT_SUPPORTED;
149: break;
150: case CURLE_OK:
151: curl_easy_getinfo(this->curl, CURLINFO_RESPONSE_CODE,
152: &result);
153: if (this->result)
154: {
155: *this->result = result;
156: }
157: status = (result < 400) ? SUCCESS : FAILED;
158: break;
159: default:
160: DBG1(DBG_LIB, "libcurl request failed [%d]: %s", curl_status,
161: error);
162: status = FAILED;
163: break;
164: }
165:
166: out:
167: if (enc_uri != uri)
168: {
169: free(enc_uri);
170: }
171: return status;
172: }
173:
174: METHOD(fetcher_t, set_option, bool,
175: private_curl_fetcher_t *this, fetcher_option_t option, ...)
176: {
177: bool supported = TRUE;
178: va_list args;
179:
180: va_start(args, option);
181: switch (option)
182: {
183: case FETCH_REQUEST_DATA:
184: {
185: chunk_t data = va_arg(args, chunk_t);
186:
187: curl_easy_setopt(this->curl, CURLOPT_POSTFIELDS, (char*)data.ptr);
188: curl_easy_setopt(this->curl, CURLOPT_POSTFIELDSIZE, data.len);
189: break;
190: }
191: case FETCH_REQUEST_TYPE:
192: {
193: char header[BUF_LEN];
194: char *request_type = va_arg(args, char*);
195:
196: snprintf(header, BUF_LEN, "Content-Type: %s", request_type);
197: this->headers = curl_slist_append(this->headers, header);
198: break;
199: }
200: case FETCH_REQUEST_HEADER:
201: {
202: char *header = va_arg(args, char*);
203:
204: this->headers = curl_slist_append(this->headers, header);
205: break;
206: }
207: case FETCH_HTTP_VERSION_1_0:
208: {
209: curl_easy_setopt(this->curl, CURLOPT_HTTP_VERSION,
210: CURL_HTTP_VERSION_1_0);
211: break;
212: }
213: case FETCH_TIMEOUT:
214: {
215: this->timeout = va_arg(args, u_int);
216: break;
217: }
218: case FETCH_CALLBACK:
219: {
220: this->cb = va_arg(args, fetcher_callback_t);
221: break;
222: }
223: case FETCH_RESPONSE_CODE:
224: {
225: this->result = va_arg(args, u_int*);
226: break;
227: }
228: case FETCH_SOURCEIP:
229: {
230: char buf[64];
231:
232: snprintf(buf, sizeof(buf), "%H", va_arg(args, host_t*));
233: supported = curl_easy_setopt(this->curl, CURLOPT_INTERFACE,
234: buf) == CURLE_OK;
235: break;
236: }
237: default:
238: supported = FALSE;
239: break;
240: }
241: va_end(args);
242: return supported;
243: }
244:
245: METHOD(fetcher_t, destroy, void,
246: private_curl_fetcher_t *this)
247: {
248: curl_slist_free_all(this->headers);
249: curl_easy_cleanup(this->curl);
250: free(this);
251: }
252:
253: /*
254: * Described in header.
255: */
256: curl_fetcher_t *curl_fetcher_create()
257: {
258: private_curl_fetcher_t *this;
259:
260: INIT(this,
261: .public = {
262: .interface = {
263: .fetch = _fetch,
264: .set_option = _set_option,
265: .destroy = _destroy,
266: },
267: },
268: .curl = curl_easy_init(),
269: .cb = fetcher_default_callback,
270: .redir = lib->settings->get_int(lib->settings, "%s.plugins.curl.redir",
271: -1, lib->ns),
272: );
273:
274: if (!this->curl)
275: {
276: free(this);
277: return NULL;
278: }
279: return &this->public;
280: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>