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