OpenCPN Partial API docs
downloader.cpp
1 /******************************************************************************
2  *
3  * Project: OpenCPN
4  *
5  ***************************************************************************
6  * Copyright (C) 2019 Alec Leamas *
7  * *
8  * This program is free software; you can redistribute it and/or modify *
9  * it under the terms of the GNU General Public License as published by *
10  * the Free Software Foundation; either version 2 of the License, or *
11  * (at your option) any later version. *
12  * *
13  * This program is distributed in the hope that it will be useful, *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16  * GNU General Public License for more details. *
17  * *
18  * You should have received a copy of the GNU General Public License *
19  * along with this program; if not, write to the *
20  * Free Software Foundation, Inc., *
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
22  ***************************************************************************
23  */
24 
25 #include <fstream>
26 
27 #include <curl/curl.h>
28 
29 #include <wx/filename.h>
30 #include <wx/log.h>
31 
32 #include "model/downloader.h"
33 
35 static size_t throw_cb(void* ptr, size_t size, size_t nmemb, void* data) {
36  (void)ptr;
37  (void)data;
38  return (size_t)(size * nmemb);
39 }
40 
41 static unsigned write_cb(char* in, unsigned size, unsigned nmemb, void* data);
42 // Forward
43 
44 Downloader::Downloader(std::string url_)
45  : url(url_), stream(), error_msg(""), errorcode(0){};
46 
47 int Downloader::last_errorcode() { return errorcode; }
48 
49 std::string Downloader::last_error() { return error_msg; }
50 
51 void Downloader::on_chunk(const char* buff, unsigned bytes) {
52  stream->write(buff, bytes);
53 }
54 
55 bool Downloader::download(std::ostream* stream) {
56  CURL* curl;
57  char curl_errbuf[CURL_ERROR_SIZE];
58 
59  this->stream = stream;
60  curl = curl_easy_init();
61  curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
62  curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_errbuf);
63  curl_easy_setopt(curl, CURLOPT_USERAGENT, "Mozilla/5.0");
64  curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L);
65  curl_easy_setopt(curl, CURLOPT_VERBOSE, 0L);
66  // FIXME -- Add correct certificates on host.
67  curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
68  curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
69  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb);
70  curl_easy_setopt(curl, CURLOPT_WRITEDATA, this);
71  curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
72  int code = curl_easy_perform(curl);
73  curl_easy_cleanup(curl);
74  if (code != CURLE_OK) {
75  wxLogWarning("Failed to get '%s' [%s]\n", url, curl_errbuf);
76  errorcode = code;
77  error_msg = std::string(curl_errbuf);
78  return false;
79  }
80  return true;
81 }
82 
83 bool Downloader::download(std::string& path) {
84  if (path == "") {
85  path = wxFileName::CreateTempFileName("ocpn_dl").ToStdString();
86  }
87  std::ofstream stream;
88  stream.open(path.c_str(), std::ios::out | std::ios::binary | std::ios::trunc);
89  if (!stream.is_open()) {
90  errorcode = CURLE_WRITE_ERROR;
91  error_msg = std::string("Cannot open temporary file ") + path;
92  return false;
93  }
94  bool ok = download(&stream);
95  stream.close();
96  return ok;
97 }
98 
100  CURL* curl;
101  char curl_errbuf[CURL_ERROR_SIZE] = {0};
102  double filesize = 0.0;
103 
104  curl = curl_easy_init();
105  curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
106  curl_easy_setopt(curl, CURLOPT_NOBODY, 1L);
107  curl_easy_setopt(curl, CURLOPT_FILETIME, 1L);
108  curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, throw_cb);
109  curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
110  curl_easy_setopt(curl, CURLOPT_HEADER, 0L);
111  // FIXME -- Add correct certificates on host.
112  curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
113 
114  int r = curl_easy_perform(curl);
115  if (r == CURLE_OK) {
116  r = curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &filesize);
117  }
118  curl_easy_cleanup(curl);
119  wxLogMessage("filesize %s: %d bytes\n", url.c_str(), (int)filesize);
120  if (r != CURLE_OK) {
121  errorcode = r;
122  error_msg = std::string(curl_errbuf);
123  return 0;
124  }
125  return (long)filesize;
126 }
127 
129 static unsigned write_cb(char* in, unsigned size, unsigned nmemb, void* data) {
130  auto downloader = static_cast<Downloader*>(data);
131  if (data == 0) {
132  return 0;
133  }
134  downloader->on_chunk(in, size * nmemb);
135  return in == NULL ? 0 : size * nmemb;
136 }
Handle downloading of files from remote urls.
Definition: downloader.h:34
bool download(std::ostream *stream)
Download url into stream, return false on errors.
Definition: downloader.cpp:55
long get_filesize()
Try to get remote filesize, return 0 on failure.
Definition: downloader.cpp:99
std::string last_error()
Last Curl error message.
Definition: downloader.cpp:49
virtual void on_chunk(const char *buff, unsigned bytes)
Called when given bytes has been transferred from remote.
Definition: downloader.cpp:51
int last_errorcode()
Last error code, a CURLE return code.
Definition: downloader.cpp:47