OpenCPN Partial API docs
Loading...
Searching...
No Matches
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 "config.h"
33#include "model/downloader.h"
34#include "model/ocpn_utils.h"
35
37static size_t throw_cb(void* ptr, size_t size, size_t nmemb, void* data) {
38 (void)ptr;
39 (void)data;
40 return (size_t)(size * nmemb);
41}
42
43static std::string GetUserAgent() {
44 std::string ua = "Mozilla/5.0 (@abi@; @abi_version@) OpenCPN/@o_version@";
45 ua += " curl/@curl_version@";
46 ocpn::replace(ua, "@o_version@", VERSION_FULL);
47 ocpn::replace(ua, "@abi@", PKG_TARGET);
48 ocpn::replace(ua, "@abi_version@", PKG_TARGET_VERSION);
49 ocpn::replace(ua, "@curl_version@", LIBCURL_VERSION);
50 return ua;
51}
52
53static unsigned write_cb(char* in, unsigned size, unsigned nmemb, void* data);
54// Forward
55
56Downloader::Downloader(std::string url_)
57 : url(url_), stream(), error_msg(""), errorcode(0) {};
58
59int Downloader::last_errorcode() { return errorcode; }
60
61std::string Downloader::last_error() { return error_msg; }
62
63void Downloader::on_chunk(const char* buff, unsigned bytes) {
64 stream->write(buff, bytes);
65}
66
67bool Downloader::download(std::ostream* stream) {
68 CURL* curl;
69 char curl_errbuf[CURL_ERROR_SIZE];
70
71 this->stream = stream;
72 curl = curl_easy_init();
73 curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
74 curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_errbuf);
75 curl_easy_setopt(curl, CURLOPT_USERAGENT, GetUserAgent().c_str());
76 curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L);
77 curl_easy_setopt(curl, CURLOPT_VERBOSE, 0L);
78 // FIXME -- Add correct certificates on host.
79 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
80 curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
81 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb);
82 curl_easy_setopt(curl, CURLOPT_WRITEDATA, this);
83 curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
84 int code = curl_easy_perform(curl);
85 curl_easy_cleanup(curl);
86 if (code != CURLE_OK) {
87 wxLogWarning("Failed to get '%s' [%s]\n", url, curl_errbuf);
88 errorcode = code;
89 error_msg = std::string(curl_errbuf);
90 return false;
91 }
92 return true;
93}
94
95bool Downloader::download(std::string& path) {
96 if (path == "") {
97 path = wxFileName::CreateTempFileName("ocpn_dl").ToStdString();
98 }
99 std::ofstream stream;
100 stream.open(path.c_str(), std::ios::out | std::ios::binary | std::ios::trunc);
101 if (!stream.is_open()) {
102 errorcode = CURLE_WRITE_ERROR;
103 error_msg = std::string("Cannot open temporary file ") + path;
104 return false;
105 }
106 bool ok = download(&stream);
107 stream.close();
108 return ok;
109}
110
112 CURL* curl;
113 char curl_errbuf[CURL_ERROR_SIZE] = {0};
114 double filesize = 0.0;
115
116 curl = curl_easy_init();
117 curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
118 curl_easy_setopt(curl, CURLOPT_USERAGENT, GetUserAgent().c_str());
119 curl_easy_setopt(curl, CURLOPT_NOBODY, 1L);
120 curl_easy_setopt(curl, CURLOPT_FILETIME, 1L);
121 curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, throw_cb);
122 curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
123 curl_easy_setopt(curl, CURLOPT_HEADER, 0L);
124 // FIXME -- Add correct certificates on host.
125 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
126
127 int r = curl_easy_perform(curl);
128 if (r == CURLE_OK) {
129 r = curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &filesize);
130 }
131 curl_easy_cleanup(curl);
132 wxLogMessage("filesize %s: %d bytes\n", url.c_str(), (int)filesize);
133 if (r != CURLE_OK) {
134 errorcode = r;
135 error_msg = std::string(curl_errbuf);
136 return 0;
137 }
138 return (long)filesize;
139}
140
142static unsigned write_cb(char* in, unsigned size, unsigned nmemb, void* data) {
143 auto downloader = static_cast<Downloader*>(data);
144 if (data == 0) {
145 return 0;
146 }
147 downloader->on_chunk(in, size * nmemb);
148 return in == NULL ? 0 : size * nmemb;
149}
Handle downloading of files from remote urls.
Definition downloader.h:38
bool download(std::ostream *stream)
Download url into stream, return false on errors.
long get_filesize()
Try to get remote filesize, return 0 on failure.
std::string last_error()
Last Curl error message.
virtual void on_chunk(const char *buff, unsigned bytes)
Called when given bytes has been transferred from remote.
int last_errorcode()
Last error code, a CURLE return code.
bool replace(std::string &str, const std::string &from, const std::string &to)
Perform in place substitution in str, replacing "from" with "to".
Miscellaneous utilities, many of which string related.