makhlouf
makhlouf

Reputation: 41

Using Libcurl library for file download

I am trying to implement autoupdate by downloading the update files from a share link in Dropbox or google drive. At first, I used windows API function URLDownloadToFile() to download public files from the web. It works fine, but when I used it for cloud files, it did not download the file. It rather get an HTML file that when opened with a browser, I can download the file using the browser.

So, I shifted to using Libcurl library and followed their tutorial. I always received error

(60) : CURL_PEER_FAILED_VERIFICATION.

I followed the example at https://curl.haxx.se/libcurl/c/url2file.html. And tried to get same public file I already downloaded the windows API and still received same error. So I know it is not related to server authentication or similar issues.

Here is my download function using both windows api and Libcurl:

static size_t write_data (void *ptr,size_t size,size_t nmemb,void* stream)
{
  size_t written = fwrite (ptr,size,nmemb,(FILE *) stream) ;
  return written ;
} /* write_data */


int DownloadFile ()
{
  static const char FileURL[] = "https://www.pexels.com/photo/618608/download/?search_query=park&tracking_id=6qgsqm6nzau" :
  static char TargetURL[]  = "D:\\Download\\DownloadURL\\Test.jpg" ;
  static char TargetCURL[] = "D:\\Download\\DownloadCURL\\Test.jpg" ;

  // Download the file using windows function into DownloadURL folder
  URLDownloadToFile (nullptr,FileURL[2],TargetURL,0,nullptr) ; // OK

  // Download the file using curl library into DownloadCURL folder
  if (auto curl = curl_easy_init ()) {
      auto fp = fopen (TargetCURL,"wb") ;
      curl_easy_setopt (curl,CURLOPT_URL,FileURL[1]) ;
      curl_easy_setopt (curl,CURLOPT_FAILONERROR,1) ;
      curl_easy_setopt (curl,CURLOPT_WRITEDATA,fp) ;

      /* Perform the request, res will get the return code */
      auto res = curl_easy_perform (curl) ;                     // Always Fail

      fclose (fp) ;
      curl_easy_cleanup (curl) ;
  } /* if (auto curl = curl_easy_init ()) */

  return true ;

} /* Download */

My system is running Windows 10 x64. I use Visual Studio 2017, Libcurl revision 7.67 with openSSL.

Can anyone help me figure out what is missing?

Upvotes: 1

Views: 2649

Answers (3)

Winsoft666
Winsoft666

Reputation: 1

You need set these options:

curl_setopt (curl, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt (curl, CURLOPT_SSL_VERIFYPEER, 0); 

Maybe you can try teemo library, it based libcurl, and support multi-thread download

Upvotes: 0

rustyx
rustyx

Reputation: 85341

The error is about TLS certificate issuer validation. You're missing the CA cert for the server. On Windows OpenSSL by default comes with an empty cert store. On Windows is better to compile libcurl with schannel support instead of OpenSSL, then it'll use the Windows built-in cert store.

Upvotes: 1

Ted Lyngmo
Ted Lyngmo

Reputation: 117298

The URL you use redirects to this URL: https://images.pexels.com/photos/618608/pexels-photo-618608.jpeg?cs=srgb&dl=worm-s-eyeview-of-tall-tree-under-a-gray-sky-618608.jpg&fm=jpg so you need to enable following redirects in curl:

curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); // follow redirects

You also need to supply the write_data function:

curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);

And
curl_easy_setopt (curl,CURLOPT_URL,FileURL[1]) ;
should be
curl_easy_setopt (curl,CURLOPT_URL,FileURL);

If you are behind a http proxy, you may also need
curl_easy_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, 1L);

#include "curl/curl.h"
#include <cstdio>

static size_t write_data(void* ptr, size_t size, size_t nmemb, void* stream) {
    size_t written = fwrite(ptr, size, nmemb, static_cast<FILE*>(stream));
    return written;
} /* write_data */

bool DownloadFile() {
    bool retval = false;
    static const char FileURL[] =
        "https://www.pexels.com/photo/618608/download/"
        "?search_query=park&tracking_id=6qgsqm6nzau";
    static char TargetCURL[] = "D:\\Download\\DownloadCURL\\Test.jpg";

    // Download the file using curl library into DownloadCURL folder
    if(CURL* curl = curl_easy_init()) {
        if(FILE* fp = fopen(TargetCURL, "wb")) {
            curl_easy_setopt(curl, CURLOPT_URL, FileURL);
            curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
            curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
            curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
            curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); // follow redirects
            curl_easy_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, 1L); // corp. proxies etc.

            /* Perform the request, res will get the return code */
            CURLcode res = curl_easy_perform(curl);
            if(!res) retval = true;

            fclose(fp);
        }
        curl_easy_cleanup(curl);
    } /* if (auto curl = curl_easy_init ()) */

    return retval;

} /* Download */

int main() {
    CURLcode res = curl_global_init(CURL_GLOBAL_ALL);
    if(res) return 1;
    DownloadFile();
    curl_global_cleanup();
}

Upvotes: 1

Related Questions