Mercurial > hg > orthanc
comparison Core/HttpClient.cpp @ 1533:0011cc99443c
improving HTTPS support
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 12 Aug 2015 17:52:10 +0200 |
parents | 8a330b258491 |
children | 95b3b0260240 |
comparison
equal
deleted
inserted
replaced
1532:b5eb5210af91 | 1533:0011cc99443c |
---|---|
33 #include "PrecompiledHeaders.h" | 33 #include "PrecompiledHeaders.h" |
34 #include "HttpClient.h" | 34 #include "HttpClient.h" |
35 | 35 |
36 #include "Toolbox.h" | 36 #include "Toolbox.h" |
37 #include "OrthancException.h" | 37 #include "OrthancException.h" |
38 #include "Logging.h" | |
38 | 39 |
39 #include <string.h> | 40 #include <string.h> |
40 #include <curl/curl.h> | 41 #include <curl/curl.h> |
42 #include <boost/algorithm/string/predicate.hpp> | |
43 | |
44 | |
45 static std::string cacert_; | |
46 static bool httpsVerifyPeers_ = true; | |
47 | |
48 extern "C" | |
49 { | |
50 static CURLcode GetHttpStatus(CURLcode code, CURL* curl, long* status) | |
51 { | |
52 if (code == CURLE_OK) | |
53 { | |
54 code = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, status); | |
55 return code; | |
56 } | |
57 else | |
58 { | |
59 *status = 0; | |
60 return code; | |
61 } | |
62 } | |
63 | |
64 // This is a dummy wrapper function to suppress any OpenSSL-related | |
65 // problem in valgrind. Inlining is prevented. | |
66 #if defined(__GNUC__) || defined(__clang__) | |
67 __attribute__((noinline)) | |
68 #endif | |
69 static CURLcode OrthancHttpClientPerformSSL(CURL* curl, long* status) | |
70 { | |
71 return GetHttpStatus(curl_easy_perform(curl), curl, status); | |
72 } | |
73 } | |
74 | |
41 | 75 |
42 | 76 |
43 namespace Orthanc | 77 namespace Orthanc |
44 { | 78 { |
45 struct HttpClient::PImpl | 79 struct HttpClient::PImpl |
51 | 85 |
52 static CURLcode CheckCode(CURLcode code) | 86 static CURLcode CheckCode(CURLcode code) |
53 { | 87 { |
54 if (code != CURLE_OK) | 88 if (code != CURLE_OK) |
55 { | 89 { |
56 throw OrthancException("libCURL error: " + std::string(curl_easy_strerror(code))); | 90 LOG(ERROR) << "libCURL error: " + std::string(curl_easy_strerror(code)); |
91 throw OrthancException(ErrorCode_NetworkProtocol); | |
57 } | 92 } |
58 | 93 |
59 return code; | 94 return code; |
60 } | 95 } |
61 | 96 |
95 CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_WRITEFUNCTION, &CurlCallback)); | 130 CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_WRITEFUNCTION, &CurlCallback)); |
96 CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_HEADER, 0)); | 131 CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_HEADER, 0)); |
97 CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_FOLLOWLOCATION, 1)); | 132 CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_FOLLOWLOCATION, 1)); |
98 | 133 |
99 #if ORTHANC_SSL_ENABLED == 1 | 134 #if ORTHANC_SSL_ENABLED == 1 |
100 CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSL_VERIFYPEER, 0)); | 135 if (httpsVerifyPeers_) |
136 { | |
137 CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_CAINFO, cacert_.c_str())); | |
138 CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSL_VERIFYPEER, 1)); | |
139 } | |
140 else | |
141 { | |
142 CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSL_VERIFYPEER, 0)); | |
143 } | |
101 #endif | 144 #endif |
102 | 145 |
103 // This fixes the "longjmp causes uninitialized stack frame" crash | 146 // This fixes the "longjmp causes uninitialized stack frame" crash |
104 // that happens on modern Linux versions. | 147 // that happens on modern Linux versions. |
105 // http://stackoverflow.com/questions/9191668/error-longjmp-causes-uninitialized-stack-frame | 148 // http://stackoverflow.com/questions/9191668/error-longjmp-causes-uninitialized-stack-frame |
241 } | 284 } |
242 } | 285 } |
243 | 286 |
244 | 287 |
245 // Do the actual request | 288 // Do the actual request |
246 CheckCode(curl_easy_perform(pimpl_->curl_)); | 289 CURLcode code; |
247 | 290 long status = 0; |
248 long status; | 291 |
249 CheckCode(curl_easy_getinfo(pimpl_->curl_, CURLINFO_RESPONSE_CODE, &status)); | 292 if (boost::starts_with(url_, "https://")) |
293 { | |
294 code = OrthancHttpClientPerformSSL(pimpl_->curl_, &status); | |
295 } | |
296 else | |
297 { | |
298 code = GetHttpStatus(curl_easy_perform(pimpl_->curl_), pimpl_->curl_, &status); | |
299 } | |
300 | |
301 CheckCode(code); | |
250 | 302 |
251 if (status == 0) | 303 if (status == 0) |
252 { | 304 { |
253 // This corresponds to a call to an inexistent host | 305 // This corresponds to a call to an inexistent host |
254 lastStatus_ = HttpStatus_500_InternalServerError; | 306 lastStatus_ = HttpStatus_500_InternalServerError; |
282 { | 334 { |
283 credentials_ = std::string(username) + ":" + std::string(password); | 335 credentials_ = std::string(username) + ":" + std::string(password); |
284 } | 336 } |
285 | 337 |
286 | 338 |
287 void HttpClient::GlobalInitialize() | 339 void HttpClient::GlobalInitialize(bool httpsVerifyPeers, |
288 { | 340 const std::string& httpsVerifyCertificates) |
341 { | |
342 #if ORTHANC_SSL_ENABLED == 1 | |
343 httpsVerifyPeers_ = httpsVerifyPeers; | |
344 cacert_ = httpsVerifyCertificates; | |
345 | |
346 // TODO | |
347 /*if (cacert_.empty()) | |
348 { | |
349 cacert_ = "/etc/ssl/certs/ca-certificates.crt"; | |
350 }*/ | |
351 | |
352 if (httpsVerifyPeers) | |
353 { | |
354 if (cacert_.empty()) | |
355 { | |
356 LOG(WARNING) << "No certificates are provided to validate peers, " | |
357 << "set \"HttpsCertificatesFile\" if you need to do HTTPS requests"; | |
358 } | |
359 else | |
360 { | |
361 LOG(WARNING) << "HTTPS will use the certificates from this file: " << cacert_; | |
362 } | |
363 } | |
364 else | |
365 { | |
366 LOG(WARNING) << "The verification of the peers in HTTPS requests is disabled!"; | |
367 } | |
368 #endif | |
369 | |
289 CheckCode(curl_global_init(CURL_GLOBAL_DEFAULT)); | 370 CheckCode(curl_global_init(CURL_GLOBAL_DEFAULT)); |
290 } | 371 } |
372 | |
291 | 373 |
292 void HttpClient::GlobalFinalize() | 374 void HttpClient::GlobalFinalize() |
293 { | 375 { |
294 curl_global_cleanup(); | 376 curl_global_cleanup(); |
295 } | 377 } |