diff options
Diffstat (limited to 'src/core/wee-url.c')
-rw-r--r-- | src/core/wee-url.c | 127 |
1 files changed, 116 insertions, 11 deletions
diff --git a/src/core/wee-url.c b/src/core/wee-url.c index 2c6be1f4f..7ec89b94f 100644 --- a/src/core/wee-url.c +++ b/src/core/wee-url.c @@ -44,6 +44,7 @@ { #__name, CURLOPT_##__name, URL_TYPE_##__type, __constants } +int url_debug = 0; char *url_type_string[] = { "string", "long", "long long", "mask", "list" }; /* @@ -1013,8 +1014,6 @@ struct t_url_option url_options[] = { NULL, 0, 0, NULL }, }; -char url_error[CURL_ERROR_SIZE + 1]; - /* * Searches for a constant in array of constants. @@ -1116,7 +1115,7 @@ weeurl_search_option (const char *name) */ size_t -weeurl_read (void *buffer, size_t size, size_t nmemb, void *stream) +weeurl_read_stream (void *buffer, size_t size, size_t nmemb, void *stream) { return (stream) ? fread (buffer, size, nmemb, stream) : 0; } @@ -1126,12 +1125,27 @@ weeurl_read (void *buffer, size_t size, size_t nmemb, void *stream) */ size_t -weeurl_write (void *buffer, size_t size, size_t nmemb, void *stream) +weeurl_write_stream (void *buffer, size_t size, size_t nmemb, void *stream) { return (stream) ? fwrite (buffer, size, nmemb, stream) : 0; } /* + * Adds data to a dynamic string (callback called to catch stdout). + */ + +size_t +weeurl_write_string (void *buffer, size_t size, size_t nmemb, void *string) +{ + if (!string) + return 0; + + string_dyn_concat ((char **)string, buffer, size * nmemb); + + return size * nmemb; +} + +/* * Sets option in CURL easy handle (callback called for each option in hashtable * "options"). */ @@ -1303,6 +1317,17 @@ weeurl_set_proxy (CURL *curl, struct t_proxy *proxy) /* * Downloads URL using options. * + * If output is not NULL, it must be a hashtable with keys and values of type + * "string". The following keys may be added in the hashtable, + * depending on the success or error of the URL transfer: + * + * key | description + * --------------|-------------------------------------------------------- + * response_code | HTTP response code (as string) + * headers | HTTP headers in response + * output | stdout (set only if "file_out" was not set in options) + * error | error message (set only in case of error) + * * Returns: * 0: OK * 1: invalid URL @@ -1312,20 +1337,28 @@ weeurl_set_proxy (CURL *curl, struct t_proxy *proxy) */ int -weeurl_download (const char *url, struct t_hashtable *options) +weeurl_download (const char *url, struct t_hashtable *options, + struct t_hashtable *output) { CURL *curl; struct t_url_file url_file[2]; char *url_file_option[2] = { "file_in", "file_out" }; char *url_file_mode[2] = { "rb", "wb" }; + char url_error[CURL_ERROR_SIZE + 1], **string_headers, **string_output; + char str_response_code[32]; CURLoption url_file_opt_func[2] = { CURLOPT_READFUNCTION, CURLOPT_WRITEFUNCTION }; CURLoption url_file_opt_data[2] = { CURLOPT_READDATA, CURLOPT_WRITEDATA }; - void *url_file_opt_cb[2] = { &weeurl_read, &weeurl_write }; + void *url_file_opt_cb[2] = { &weeurl_read_stream, &weeurl_write_stream }; struct t_proxy *ptr_proxy; - int rc, curl_rc, i; + int rc, curl_rc, i, output_to_file; + long response_code; rc = 0; + string_headers = NULL; + string_output = NULL; + url_error[0] = '\0'; + for (i = 0; i < 2; i++) { url_file[i].filename = NULL; @@ -1334,6 +1367,7 @@ weeurl_download (const char *url, struct t_hashtable *options) if (!url || !url[0]) { + snprintf (url_error, sizeof (url_error), "%s", _("invalid URL")); rc = 1; goto end; } @@ -1341,6 +1375,7 @@ weeurl_download (const char *url, struct t_hashtable *options) curl = curl_easy_init (); if (!curl) { + snprintf (url_error, sizeof (url_error), "%s", _("not enough memory")); rc = 3; goto end; } @@ -1358,7 +1393,19 @@ weeurl_download (const char *url, struct t_hashtable *options) weeurl_set_proxy (curl, ptr_proxy); } + /* set callback to retrieve HTTP headers */ + if (output) + { + string_headers = string_dyn_alloc (1024); + if (string_headers) + { + curl_easy_setopt (curl, CURLOPT_HEADERFUNCTION, &weeurl_write_string); + curl_easy_setopt (curl, CURLOPT_HEADERDATA, string_headers); + } + } + /* set file in/out from options in hashtable */ + output_to_file = 0; if (options) { for (i = 0; i < 2; i++) @@ -1369,15 +1416,33 @@ weeurl_download (const char *url, struct t_hashtable *options) url_file[i].stream = fopen (url_file[i].filename, url_file_mode[i]); if (!url_file[i].stream) { + snprintf (url_error, sizeof (url_error), + (i == 0) ? + _("file \"%s\" not found") : + _("can not write file \"%s\""), + url_file[i].filename); rc = 4; goto end; } curl_easy_setopt (curl, url_file_opt_func[i], url_file_opt_cb[i]); curl_easy_setopt (curl, url_file_opt_data[i], url_file[i].stream); + if (i == 1) + output_to_file = 1; } } } + /* redirect stdout if no filename was given (via key "file_out") */ + if (output && !output_to_file) + { + string_output = string_dyn_alloc (1024); + if (string_output) + { + curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, &weeurl_write_string); + curl_easy_setopt (curl, CURLOPT_WRITEDATA, string_output); + } + } + /* set other options in hashtable */ hashtable_map (options, &weeurl_option_map_cb, curl); @@ -1386,11 +1451,36 @@ weeurl_download (const char *url, struct t_hashtable *options) /* perform action! */ curl_rc = curl_easy_perform (curl); - if (curl_rc != CURLE_OK) + if (curl_rc == CURLE_OK) + { + if (output) + { + curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &response_code); + snprintf (str_response_code, sizeof (str_response_code), + "%ld", response_code); + hashtable_set (output, "response_code", str_response_code); + } + } + else { - fprintf (stderr, - _("curl error %d (%s) (URL: \"%s\")\n"), - curl_rc, url_error, url); + if (output) + { + if (!url_error[0]) + { + snprintf (url_error, sizeof (url_error), + "%s", _("transfer error")); + } + } + else + { + /* + * URL transfer done in a forked process: display error on stderr, + * which will be sent to the hook_process callback + */ + fprintf (stderr, + _("curl error %d (%s) (URL: \"%s\")\n"), + curl_rc, url_error, url); + } rc = 2; } @@ -1403,6 +1493,21 @@ end: if (url_file[i].stream) fclose (url_file[i].stream); } + if (output) + { + if (string_headers) + { + hashtable_set (output, "headers", *string_headers); + string_dyn_free (string_headers, 1); + } + if (string_output) + { + hashtable_set (output, "output", *string_output); + string_dyn_free (string_output, 1); + } + if (url_error[0]) + hashtable_set (output, "error", url_error); + } return rc; } |