19 #include <curl/curl.h>
24 #include "curl_utils.h"
26 void curl_header_data_free(
void *obj)
40 size_t nitems,
void *client_data)
43 size_t realsize = size * nitems;
44 size_t adjusted_size = realsize;
51 SCOPE_ENTER(5,
"'%s': Header received with %zu bytes\n",
52 debug_info, realsize);
62 SCOPE_EXIT_RTN_VALUE(realsize,
"oversize header: %zu > %zu\n",
69 while (*start && ((
unsigned char) *start) < 33 && start < data + realsize) {
74 if (adjusted_size < strlen(
"HTTP/") + 1) {
76 cb_data->_capture = 0;
77 SCOPE_EXIT_RTN_VALUE(realsize,
"undersized header. probably end-of-headers marker: %zu\n",
94 int rc = sscanf(start,
"HTTP/%*s %d %*s", &code);
96 if (code / 100 == 2) {
97 cb_data->_capture = 1;
100 SCOPE_EXIT_RTN_VALUE(realsize,
"HTTP response code: %d\n",
104 if (!cb_data->_capture) {
105 SCOPE_EXIT_RTN_VALUE(realsize,
"not capturing\n");
113 colon = strchr(header,
':');
115 SCOPE_EXIT_RTN_VALUE(realsize,
"No colon in the header. Weird\n");
122 h = ast_variable_new(header, value, __FILE__);
124 SCOPE_EXIT_LOG_RTN_VALUE(CURL_WRITEFUNC_ERROR, LOG_WARNING,
125 "'%s': Unable to allocate memory for header '%s'\n",
128 ast_variable_list_append(&cb_data->
headers, h);
130 SCOPE_EXIT_RTN_VALUE(realsize,
"header: <%s> value: <%s>",
134 void curl_write_data_free(
void *obj)
151 size_t nmemb,
void *client_data)
154 size_t realsize = size * nmemb;
155 size_t bytes_written = 0;
157 SCOPE_ENTER(5,
"'%s': Writing data chunk of %zu bytes\n",
158 debug_info, realsize);
161 cb_data->
output = open_memstream(
165 SCOPE_EXIT_LOG_RTN_VALUE(CURL_WRITEFUNC_ERROR, LOG_WARNING,
166 "'%s': Xfer failed. "
167 "open_memstream failed: %s\n", debug_info, strerror(errno));
169 cb_data->_internal_memstream = 1;
175 SCOPE_EXIT_LOG_RTN_VALUE(CURL_WRITEFUNC_ERROR, LOG_WARNING,
176 "'%s': Xfer failed. "
177 "Exceeded maximum %zu bytes transferred\n", debug_info,
181 bytes_written = fwrite(data, 1, realsize, cb_data->
output);
183 if (bytes_written != realsize) {
184 SCOPE_EXIT_LOG_RTN_VALUE(CURL_WRITEFUNC_ERROR, LOG_WARNING,
185 "'%s': Xfer failed. "
186 "Expected to write %zu bytes but wrote %zu\n",
187 debug_info, realsize, bytes_written);
190 SCOPE_EXIT_RTN_VALUE(realsize,
"Wrote %zu bytes\n", bytes_written);
193 void curl_open_socket_data_free(
void *obj)
206 curlsocktype purpose,
struct curl_sockaddr *address)
210 SCOPE_ENTER(5,
"'%s': Opening socket\n", debug_info);
218 SCOPE_EXIT_LOG_RTN_VALUE(CURL_SOCKET_BAD, LOG_WARNING,
219 "'%s': Unable to apply acl\n", debug_info);
223 cb_data->sockfd = socket(address->family, address->socktype, address->protocol);
224 if (cb_data->sockfd < 0) {
225 SCOPE_EXIT_LOG_RTN_VALUE(CURL_SOCKET_BAD, LOG_WARNING,
226 "'%s': Failed to open socket: %s\n", debug_info, strerror(errno));
229 SCOPE_EXIT_RTN_VALUE(cb_data->sockfd,
"Success");
232 long curler(
const char *url,
int request_timeout,
237 RAII_VAR(CURL *, curl, NULL, curl_easy_cleanup);
241 SCOPE_ENTER(1,
"'%s': Retrieving\n", url);
243 if (ast_strlen_zero(url)) {
244 SCOPE_EXIT_LOG_RTN_VALUE(500, LOG_ERROR,
"'missing': url is missing\n");
248 SCOPE_EXIT_LOG_RTN_VALUE(500, LOG_ERROR,
"'%s': Either wite_cb and write_data are missing\n", url);
251 curl = curl_easy_init();
253 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_ERROR,
"'%s': Failed to set up CURL instance\n", url);
256 curl_easy_setopt(curl, CURLOPT_URL, url);
257 if (request_timeout) {
258 curl_easy_setopt(curl, CURLOPT_TIMEOUT, request_timeout);
260 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
curl_write_cb);
261 curl_easy_setopt(curl, CURLOPT_WRITEDATA, write_data);
265 curl_easy_setopt(curl, CURLOPT_HEADERDATA, header_data);
268 curl_easy_setopt(curl, CURLOPT_USERAGENT, AST_CURL_USER_AGENT);
270 if (open_socket_data) {
272 curl_easy_setopt(curl, CURLOPT_OPENSOCKETDATA, open_socket_data);
275 curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
279 curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 0);
281 rc = curl_easy_perform(curl);
282 if (rc != CURLE_OK) {
284 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_ERROR,
"'%s': %s\n", url, err);
287 fflush(write_data->
output);
288 if (write_data->_internal_memstream) {
289 fclose(write_data->
output);
290 write_data->
output = NULL;
293 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
294 curl_easy_cleanup(curl);
297 SCOPE_EXIT_RTN_VALUE(http_code,
"'%s': Done: %ld\n", url, http_code);
310 long rc =
curler(url, 0, &data, headers ? &hdata : NULL, NULL);
329 if (ast_strlen_zero(url) || ast_strlen_zero(filename)) {
330 ast_log(LOG_ERROR,
"url or filename was NULL\n");
333 data.
output = fopen(filename,
"w");
335 ast_log(LOG_ERROR,
"Unable to open file '%s': %s\n", filename,
339 rc =
curler(url, 0, &data, NULL, NULL);
Asterisk main include file. File version handling, generic pbx functions.
size_t curl_write_cb(char *data, size_t size, size_t nmemb, void *client_data)
A default implementation of a write data callback.
Context structure passed to ast_curl_open_socket_default_cb.
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
const struct ast_acl_list * acl
Structure for variables, used for configurations and for channel variables.
Wrapper for an ast_acl linked list.
#define ast_strdup(str)
A wrapper for strdup()
Socket address structure.
Configuration File Parser.
Context structure passed to ast_curl_write_default_cb.
static void ast_sockaddr_copy_sockaddr(struct ast_sockaddr *dst, struct sockaddr *src, socklen_t len)
Copies the data from a sockaddr to an ast_sockaddr.
#define ast_strdupa(s)
duplicate a string in memory from the stack
enum ast_acl_sense ast_apply_acl(struct ast_acl_list *acl_list, const struct ast_sockaddr *addr, const char *purpose)
Apply a set of rules to a given IP address.
long curler(const char *url, int request_timeout, struct curl_write_data *write_data, struct curl_header_data *header_data, struct curl_open_socket_data *open_socket_data)
Perform a curl request.
int ast_acl_list_is_empty(struct ast_acl_list *acl_list)
Determines if an ACL is empty or if it contains entries.
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
size_t max_download_bytes
char * ast_skip_blanks(const char *str)
Gets a pointer to the first non-whitespace character in a string.
char * ast_trim_blanks(char *str)
Trims trailing whitespace characters from a string.
curl_socket_t curl_open_socket_cb(void *client_data, curlsocktype purpose, struct curl_sockaddr *address)
A default implementation of an open socket callback.
long curl_download_to_file(const char *url, char *filename)
Really simple document retrieval to file.
long curl_download_to_memory(const char *url, size_t *returned_length, char **returned_data, struct ast_variable **headers)
Really simple document retrieval to memory.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
static int force_inline attribute_pure ast_begins_with(const char *str, const char *prefix)
Checks whether a string begins with another.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
size_t stream_bytes_downloaded