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 }