2 * Copyright (C) 2008 Martin Willi
3 * Copyright (C) 2007 Andreas Steffen
4 * Hochschule fuer Technik Rapperswil
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>.
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
17 #include <curl/curl.h>
20 #include <utils/debug.h>
22 #include "curl_fetcher.h"
24 #define CONNECT_TIMEOUT 10
26 typedef struct private_curl_fetcher_t private_curl_fetcher_t
;
29 * private data of a curl_fetcher_t object.
31 struct private_curl_fetcher_t
{
35 curl_fetcher_t
public;
43 * Optional HTTP headers
45 struct curl_slist
*headers
;
50 fetcher_callback_t cb
;
53 * Timeout for a transfer
59 * Data to pass to curl callback
62 fetcher_callback_t cb
;
67 * Curl callback function, invokes fetcher_callback_t function
69 static size_t curl_cb(void *ptr
, size_t size
, size_t nmemb
, cb_data_t
*data
)
71 size_t realsize
= size
* nmemb
;
73 if (data
->cb(data
->user
, chunk_create(ptr
, realsize
)))
80 METHOD(fetcher_t
, fetch
, status_t
,
81 private_curl_fetcher_t
*this, char *uri
, void *userdata
)
83 char error
[CURL_ERROR_SIZE
];
90 if (this->cb
== fetcher_default_callback
)
92 *(chunk_t
*)userdata
= chunk_empty
;
95 if (curl_easy_setopt(this->curl
, CURLOPT_URL
, uri
) != CURLE_OK
)
96 { /* URL type not supported by curl */
99 curl_easy_setopt(this->curl
, CURLOPT_ERRORBUFFER
, error
);
100 curl_easy_setopt(this->curl
, CURLOPT_FAILONERROR
, TRUE
);
101 curl_easy_setopt(this->curl
, CURLOPT_NOSIGNAL
, TRUE
);
104 curl_easy_setopt(this->curl
, CURLOPT_TIMEOUT
, this->timeout
);
106 curl_easy_setopt(this->curl
, CURLOPT_CONNECTTIMEOUT
, CONNECT_TIMEOUT
);
107 curl_easy_setopt(this->curl
, CURLOPT_WRITEFUNCTION
, (void*)curl_cb
);
108 curl_easy_setopt(this->curl
, CURLOPT_WRITEDATA
, &data
);
111 curl_easy_setopt(this->curl
, CURLOPT_HTTPHEADER
, this->headers
);
114 DBG2(DBG_LIB
, " sending http request to '%s'...", uri
);
115 switch (curl_easy_perform(this->curl
))
117 case CURLE_UNSUPPORTED_PROTOCOL
:
118 status
= NOT_SUPPORTED
;
124 DBG1(DBG_LIB
, "libcurl http request failed: %s", error
);
131 METHOD(fetcher_t
, set_option
, bool,
132 private_curl_fetcher_t
*this, fetcher_option_t option
, ...)
134 bool supported
= TRUE
;
137 va_start(args
, option
);
140 case FETCH_REQUEST_DATA
:
142 chunk_t data
= va_arg(args
, chunk_t
);
144 curl_easy_setopt(this->curl
, CURLOPT_POSTFIELDS
, (char*)data
.ptr
);
145 curl_easy_setopt(this->curl
, CURLOPT_POSTFIELDSIZE
, data
.len
);
148 case FETCH_REQUEST_TYPE
:
150 char header
[BUF_LEN
];
151 char *request_type
= va_arg(args
, char*);
153 snprintf(header
, BUF_LEN
, "Content-Type: %s", request_type
);
154 this->headers
= curl_slist_append(this->headers
, header
);
157 case FETCH_REQUEST_HEADER
:
159 char *header
= va_arg(args
, char*);
161 this->headers
= curl_slist_append(this->headers
, header
);
164 case FETCH_HTTP_VERSION_1_0
:
166 curl_easy_setopt(this->curl
, CURLOPT_HTTP_VERSION
,
167 CURL_HTTP_VERSION_1_0
);
172 this->timeout
= va_arg(args
, u_int
);
177 this->cb
= va_arg(args
, fetcher_callback_t
);
184 snprintf(buf
, sizeof(buf
), "%H", va_arg(args
, host_t
*));
185 supported
= curl_easy_setopt(this->curl
, CURLOPT_INTERFACE
,
197 METHOD(fetcher_t
, destroy
, void,
198 private_curl_fetcher_t
*this)
200 curl_slist_free_all(this->headers
);
201 curl_easy_cleanup(this->curl
);
206 * Described in header.
208 curl_fetcher_t
*curl_fetcher_create()
210 private_curl_fetcher_t
*this;
216 .set_option
= _set_option
,
220 .curl
= curl_easy_init(),
221 .cb
= fetcher_default_callback
,
229 return &this->public;