0

I'm using the following function to download files from a server.

void downloadFile(const char* url, const char* fname) {
    CURL *curl;
    FILE *fp;
    CURLcode res;
    curl = curl_easy_init();
    if (curl){
        fp = fopen(fname, "wb");
        curl_easy_setopt(curl, CURLOPT_URL, url);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
        res = curl_easy_perform(curl);
        curl_easy_cleanup(curl);
        fclose(fp);
    }
}

Which is used like this:

downloadFile("http://servera.com/filea.tar.gz","filea.tar.gz");

How do I add error checking into this, so if filea.tar.gz isn't available or servera.com can't be reached, I can display my chosen error messages.

UPDATE I've added:

cout << res; to the code, but this always returns 0

The server returns a 'file not found' message and that is being downloaded. Anyway around this? I want to get an error if the specified file is not found or not reachable.. Thanks

UPDATE The following is now showing a human readable error message:

void downloadFile(const char* url, const char* fname) {
    CURL *curl;
    FILE *fp;
    CURLcode res;
    curl = curl_easy_init();
    if (curl){
        fp = fopen(fname, "wb");
        curl_easy_setopt(curl, CURLOPT_URL, url);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
        curl_easy_setopt(curl, CURLOPT_FAILONERROR, true);
        res = curl_easy_perform(curl);
        cout << curl_easy_strerror(res);
        curl_easy_cleanup(curl);
        fclose(fp);
    }
}

Now I can get the error code, I should be able to trap this better. Thanks to @YSC & @Daniel Stenberg

Rocket
  • 1,065
  • 2
  • 21
  • 44

2 Answers2

3

curl_easy_perform() returns a CURLcode describing the result. RTFM:

  • CURLE_HTTP_RETURNED_ERROR
    This is returned if CURLOPT_FAILONERROR is set TRUE and the HTTP server returns an error code that is >= 400.
YSC
  • 38,212
  • 9
  • 96
  • 149
  • I've tried adding `cout << res;` and it always returns 0 regardless of if the file is found or not. any idea why ? – Rocket Feb 23 '16 at 18:18
  • 2
    "This is returned if CURLOPT_FAILONERROR is set TRUE", and whatdoyouknow, your code doesn't set CURLOPT_FAILONERROR and libcurl will return OK since the actual HTTP transfer succeeded. – Daniel Stenberg Feb 24 '16 at 07:49
  • Thanks - I've now sorted out how to do this. I'll update the original post to show what's working for me. – Rocket Feb 24 '16 at 08:48
  • @Rocket don't do that. **Don't answer your question in the question itself**. You can [answer your own question](https://blog.stackoverflow.com/2011/07/its-ok-to-ask-and-answer-your-own-questions/) or [edit my answer to improve it](http://meta.stackoverflow.com/a/255058/5470596). – YSC Feb 24 '16 at 09:05
0

You need to look at the value of res. See curl error codes for all possible values. If res is equal to CURLE_REMOTE_FILE_NOT_FOUND, then the file is probably not available. You can also get error messages from curl using CURLOPT_ERRORBUFFER.

If res is always 0 (saying CURLE_OK would be more precise), then everything probably went fine at the curl level which supports many protocols. The error is at the HTTP level. You can't work around what the server is returning, however you can get the HTTP status code : the server is probably returning a 404 code along with the "file not found" message. See Http status code with libcurl? to learn how to do it with libcurl. If you can use the curl program directly, you can first look at the HTTP answer in your terminal by using curl -I http://servera.com/filea.tar.gz.

Community
  • 1
  • 1
Quentin Pradet
  • 4,691
  • 2
  • 29
  • 41
  • I've tried adding `cout << res;` and it always returns 0 regardless of if the file is found or not. any idea why ? – Rocket Feb 23 '16 at 18:18
  • I did not look into the specifics of cpp-netlib (hence "could"). The two main issues I have with libcurl is 1/ that it's C so you have to manage memory yourself 2/ I personally only need http, and a library that handles much more is only going to be more confusing. Things like command-line curl and Python requests are a joy to use, but libcurl is not, in my experience. But hey, thanks for the library, I could not thank you enough for that. (And thanks for http2 explained, by the way.) – Quentin Pradet Feb 24 '16 at 09:11