]>
git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/minicurl.cc
4 * Copyright (c) 2018-2019 powerdns.com bv
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 #include "minicurl.hh"
26 #include <curl/curl.h>
31 static std::atomic_flag s_init
= ATOMIC_FLAG_INIT
;
33 if (s_init
.test_and_set())
36 CURLcode code
= curl_global_init(CURL_GLOBAL_ALL
);
38 throw std::runtime_error("Error initializing libcurl");
42 MiniCurl::MiniCurl(const string
& useragent
)
44 d_curl
= curl_easy_init();
45 if (d_curl
== nullptr) {
46 throw std::runtime_error("Error creating a MiniCurl session");
48 curl_easy_setopt(d_curl
, CURLOPT_USERAGENT
, useragent
.c_str());
53 // NEEDS TO CLEAN HOSTLIST
54 curl_easy_cleanup(d_curl
);
57 size_t MiniCurl::write_callback(char *ptr
, size_t size
, size_t nmemb
, void *userdata
)
59 MiniCurl
* us
= (MiniCurl
*)userdata
;
60 us
->d_data
.append(ptr
, size
*nmemb
);
64 static string
extractHostFromURL(const std::string
& url
)
66 auto pos
= url
.find("://");
67 if(pos
== string::npos
)
68 throw runtime_error("Can't find host part of '"+url
+"'");
70 auto endpos
= url
.find('/', pos
);
71 if(endpos
== string::npos
)
72 return url
.substr(pos
);
74 return url
.substr(pos
, endpos
-pos
);
77 void MiniCurl::setupURL(const std::string
& str
, const ComboAddress
* rem
, const ComboAddress
* src
)
80 struct curl_slist
*hostlist
= nullptr; // THIS SHOULD BE FREED
82 // url = http://hostname.enzo/url
83 string host4
=extractHostFromURL(str
);
84 // doest the host contain port indication
85 std::size_t found
= host4
.find(':');
86 vector
<uint16_t> ports
{80, 443};
87 if (found
!= std::string::npos
) {
88 int port
= std::stoi(host4
.substr(found
+ 1));
89 if (port
<= 0 || port
> 65535)
90 throw std::overflow_error("Invalid port number");
91 ports
= {(uint16_t)port
};
92 host4
= host4
.substr(0, found
);
95 for (const auto& port
: ports
) {
96 string hcode
= boost::str(boost::format("%s:%u:%s") % host4
% port
% rem
->toString());
97 hostlist
= curl_slist_append(hostlist
, hcode
.c_str());
100 curl_easy_setopt(d_curl
, CURLOPT_RESOLVE
, hostlist
);
103 curl_easy_setopt(d_curl
, CURLOPT_INTERFACE
, src
->toString().c_str());
105 curl_easy_setopt(d_curl
, CURLOPT_FOLLOWLOCATION
, true);
106 /* only allow HTTP, TFTP and SFTP */
107 curl_easy_setopt(d_curl
, CURLOPT_PROTOCOLS
, CURLPROTO_HTTP
| CURLPROTO_HTTPS
);
108 curl_easy_setopt(d_curl
, CURLOPT_SSL_VERIFYPEER
, false);
109 curl_easy_setopt(d_curl
, CURLOPT_SSL_VERIFYHOST
, false);
110 curl_easy_setopt(d_curl
, CURLOPT_FAILONERROR
, true);
111 curl_easy_setopt(d_curl
, CURLOPT_URL
, str
.c_str());
112 curl_easy_setopt(d_curl
, CURLOPT_WRITEFUNCTION
, write_callback
);
113 curl_easy_setopt(d_curl
, CURLOPT_WRITEDATA
, this);
114 curl_easy_setopt(d_curl
, CURLOPT_TIMEOUT
, 2L);
119 std::string
MiniCurl::getURL(const std::string
& str
, const ComboAddress
* rem
, const ComboAddress
* src
)
121 setupURL(str
, rem
, src
);
122 auto res
= curl_easy_perform(d_curl
);
124 curl_easy_getinfo(d_curl
, CURLINFO_RESPONSE_CODE
, &http_code
);
126 if(res
!= CURLE_OK
|| http_code
!= 200) {
127 throw std::runtime_error("Unable to retrieve URL ("+std::to_string(http_code
)+"): "+string(curl_easy_strerror(res
)));
129 std::string ret
=d_data
;
134 std::string
MiniCurl::postURL(const std::string
& str
, const std::string
& postdata
)
137 curl_easy_setopt(d_curl
, CURLOPT_POSTFIELDS
, postdata
.c_str());
139 auto res
= curl_easy_perform(d_curl
);
141 throw std::runtime_error("Unable to post URL");
143 std::string ret
=d_data
;