1 | //======================================================================== |
2 | // |
3 | // CurlCachedFile.cc |
4 | // |
5 | // This file is licensed under the GPLv2 or later |
6 | // |
7 | // Copyright 2009 Stefan Thomas <thomas@eload24.com> |
8 | // Copyright 2010, 2011 Hib Eris <hib@hiberis.nl> |
9 | // Copyright 2010, 2019, 2021, 2022 Albert Astals Cid <aacid@kde.org> |
10 | // |
11 | //======================================================================== |
12 | |
13 | #include <config.h> |
14 | |
15 | #include "CurlCachedFile.h" |
16 | |
17 | #include "goo/GooString.h" |
18 | |
19 | //------------------------------------------------------------------------ |
20 | |
21 | CurlCachedFileLoader::CurlCachedFileLoader(const std::string &urlA) : url(urlA) |
22 | { |
23 | cachedFile = nullptr; |
24 | curl = nullptr; |
25 | } |
26 | |
27 | CurlCachedFileLoader::~CurlCachedFileLoader() |
28 | { |
29 | curl_easy_cleanup(curl); |
30 | } |
31 | |
32 | static size_t noop_cb(char *ptr, size_t size, size_t nmemb, void *ptr2) |
33 | { |
34 | return size * nmemb; |
35 | } |
36 | |
37 | size_t CurlCachedFileLoader::init(CachedFile *cachedFileA) |
38 | { |
39 | curl_off_t contentLength = -1; |
40 | long code = 0; |
41 | size_t size; |
42 | |
43 | cachedFile = cachedFileA; |
44 | curl = curl_easy_init(); |
45 | |
46 | curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); |
47 | curl_easy_setopt(curl, CURLOPT_HEADER, 1); |
48 | curl_easy_setopt(curl, CURLOPT_NOBODY, 1); |
49 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &noop_cb); |
50 | curl_easy_perform(curl); |
51 | curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code); |
52 | if (code) { |
53 | curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &contentLength); |
54 | size = contentLength; |
55 | } else { |
56 | error(category: errInternal, pos: -1, msg: "Failed to get size of '{0:s}'." , url.c_str()); |
57 | size = -1; |
58 | } |
59 | curl_easy_reset(curl); |
60 | |
61 | return size; |
62 | } |
63 | |
64 | static size_t load_cb(const char *ptr, size_t size, size_t nmemb, void *data) |
65 | { |
66 | CachedFileWriter *writer = (CachedFileWriter *)data; |
67 | return (writer->write)(ptr, size: size * nmemb); |
68 | } |
69 | |
70 | int CurlCachedFileLoader::load(const std::vector<ByteRange> &ranges, CachedFileWriter *writer) |
71 | { |
72 | CURLcode r = CURLE_OK; |
73 | unsigned long long fromByte, toByte; |
74 | for (const ByteRange &bRange : ranges) { |
75 | |
76 | fromByte = bRange.offset; |
77 | toByte = fromByte + bRange.length - 1; |
78 | const std::unique_ptr<GooString> range = GooString::format(fmt: "{0:ulld}-{1:ulld}" , fromByte, toByte); |
79 | |
80 | curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); |
81 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, load_cb); |
82 | curl_easy_setopt(curl, CURLOPT_WRITEDATA, writer); |
83 | curl_easy_setopt(curl, CURLOPT_RANGE, range->c_str()); |
84 | r = curl_easy_perform(curl); |
85 | curl_easy_reset(curl); |
86 | |
87 | if (r != CURLE_OK) { |
88 | break; |
89 | } |
90 | } |
91 | return r; |
92 | } |
93 | |
94 | //------------------------------------------------------------------------ |
95 | |