comparison Core/HttpClient.cpp @ 1987:ce90d109bb64

new plugin functions: OrthancPluginHttpClient and OrthancPluginGenerateUuid
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 26 Apr 2016 17:40:55 +0200
parents 99b249867052
children f3339c4f8bf4
comparison
equal deleted inserted replaced
1986:99b249867052 1987:ce90d109bb64
40 #include <string.h> 40 #include <string.h>
41 #include <curl/curl.h> 41 #include <curl/curl.h>
42 #include <boost/algorithm/string/predicate.hpp> 42 #include <boost/algorithm/string/predicate.hpp>
43 43
44 44
45 static std::string globalCACertificates_;
46 static bool globalVerifyPeers_ = true;
47 static long globalTimeout_ = 0;
48
49 extern "C" 45 extern "C"
50 { 46 {
51 static CURLcode GetHttpStatus(CURLcode code, CURL* curl, long* status) 47 static CURLcode GetHttpStatus(CURLcode code, CURL* curl, long* status)
52 { 48 {
53 if (code == CURLE_OK) 49 if (code == CURLE_OK)
75 71
76 72
77 73
78 namespace Orthanc 74 namespace Orthanc
79 { 75 {
76 class HttpClient::GlobalParameters
77 {
78 private:
79 boost::mutex mutex_;
80 bool httpsVerifyPeers_;
81 std::string httpsCACertificates_;
82 std::string proxy_;
83 long timeout_;
84
85 GlobalParameters() :
86 httpsVerifyPeers_(true),
87 timeout_(0)
88 {
89 }
90
91 public:
92 // Singleton pattern
93 static GlobalParameters& GetInstance()
94 {
95 static GlobalParameters parameters;
96 return parameters;
97 }
98
99 void ConfigureSsl(bool httpsVerifyPeers,
100 const std::string& httpsCACertificates)
101 {
102 boost::mutex::scoped_lock lock(mutex_);
103 httpsVerifyPeers_ = httpsVerifyPeers;
104 httpsCACertificates_ = httpsCACertificates;
105 }
106
107 void GetSslConfiguration(bool& httpsVerifyPeers,
108 std::string& httpsCACertificates)
109 {
110 boost::mutex::scoped_lock lock(mutex_);
111 httpsVerifyPeers = httpsVerifyPeers_;
112 httpsCACertificates = httpsCACertificates_;
113 }
114
115 void SetDefaultProxy(const std::string& proxy)
116 {
117 LOG(INFO) << "Setting the default proxy for HTTP client connections: " << proxy;
118
119 {
120 boost::mutex::scoped_lock lock(mutex_);
121 proxy_ = proxy;
122 }
123 }
124
125 void GetDefaultProxy(std::string& target)
126 {
127 boost::mutex::scoped_lock lock(mutex_);
128 target = proxy_;
129 }
130
131 void SetDefaultTimeout(long seconds)
132 {
133 LOG(INFO) << "Setting the default timeout for HTTP client connections: " << seconds << " seconds";
134
135 {
136 boost::mutex::scoped_lock lock(mutex_);
137 timeout_ = seconds;
138 }
139 }
140
141 long GetDefaultTimeout()
142 {
143 boost::mutex::scoped_lock lock(mutex_);
144 return timeout_;
145 }
146 };
147
148
80 struct HttpClient::PImpl 149 struct HttpClient::PImpl
81 { 150 {
82 CURL* curl_; 151 CURL* curl_;
83 struct curl_slist *defaultPostHeaders_; 152 struct curl_slist *defaultPostHeaders_;
84 struct curl_slist *userHeaders_; 153 struct curl_slist *userHeaders_;
91 { 160 {
92 case HttpStatus_400_BadRequest: 161 case HttpStatus_400_BadRequest:
93 throw OrthancException(ErrorCode_BadRequest); 162 throw OrthancException(ErrorCode_BadRequest);
94 163
95 case HttpStatus_401_Unauthorized: 164 case HttpStatus_401_Unauthorized:
165 case HttpStatus_403_Forbidden:
96 throw OrthancException(ErrorCode_Unauthorized); 166 throw OrthancException(ErrorCode_Unauthorized);
97 167
98 case HttpStatus_404_NotFound: 168 case HttpStatus_404_NotFound:
99 throw OrthancException(ErrorCode_InexistentItem); 169 throw OrthancException(ErrorCode_InexistentItem);
100 170
161 231
162 url_ = ""; 232 url_ = "";
163 method_ = HttpMethod_Get; 233 method_ = HttpMethod_Get;
164 lastStatus_ = HttpStatus_200_Ok; 234 lastStatus_ = HttpStatus_200_Ok;
165 isVerbose_ = false; 235 isVerbose_ = false;
166 timeout_ = globalTimeout_; 236 timeout_ = GlobalParameters::GetInstance().GetDefaultTimeout();
167 verifyPeers_ = globalVerifyPeers_; 237 GlobalParameters::GetInstance().GetDefaultProxy(proxy_);
238 GlobalParameters::GetInstance().GetSslConfiguration(verifyPeers_, caCertificates_);
168 } 239 }
169 240
170 241
171 HttpClient::HttpClient() : pimpl_(new PImpl) 242 HttpClient::HttpClient() : pimpl_(new PImpl)
172 { 243 {
173 Setup(); 244 Setup();
174 }
175
176
177 HttpClient::HttpClient(const HttpClient& other) : pimpl_(new PImpl)
178 {
179 Setup();
180
181 if (other.IsVerbose())
182 {
183 SetVerbose(true);
184 }
185
186 if (other.credentials_.size() != 0)
187 {
188 credentials_ = other.credentials_;
189 }
190 } 245 }
191 246
192 247
193 HttpClient::~HttpClient() 248 HttpClient::~HttpClient()
194 { 249 {
246 CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_URL, url_.c_str())); 301 CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_URL, url_.c_str()));
247 CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_WRITEDATA, &answer)); 302 CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_WRITEDATA, &answer));
248 303
249 // Setup HTTPS-related options 304 // Setup HTTPS-related options
250 #if ORTHANC_SSL_ENABLED == 1 305 #if ORTHANC_SSL_ENABLED == 1
251 if (IsHttpsVerifyPeers()) 306 if (verifyPeers_)
252 { 307 {
253 CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_CAINFO, GetHttpsCACertificates().c_str())); 308 CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_CAINFO, caCertificates_.c_str()));
254 CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSL_VERIFYHOST, 2)); // libcurl default is strict verifyhost 309 CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSL_VERIFYHOST, 2)); // libcurl default is strict verifyhost
255 CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSL_VERIFYPEER, 1)); 310 CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSL_VERIFYPEER, 1));
256 } 311 }
257 else 312 else
258 { 313 {
373 else 428 else
374 { 429 {
375 lastStatus_ = static_cast<HttpStatus>(status); 430 lastStatus_ = static_cast<HttpStatus>(status);
376 } 431 }
377 432
378 return (status >= 200 && status < 300); 433 bool success = (status >= 200 && status < 300);
434
435 if (!success)
436 {
437 LOG(INFO) << "Error in HTTP request, received HTTP status " << status
438 << " (" << EnumerationToString(lastStatus_) << ")";
439 }
440
441 return success;
379 } 442 }
380 443
381 444
382 bool HttpClient::Apply(Json::Value& answer) 445 bool HttpClient::Apply(Json::Value& answer)
383 { 446 {
398 const char* password) 461 const char* password)
399 { 462 {
400 credentials_ = std::string(username) + ":" + std::string(password); 463 credentials_ = std::string(username) + ":" + std::string(password);
401 } 464 }
402 465
403 466
404 const std::string& HttpClient::GetHttpsCACertificates() const 467 void HttpClient::ConfigureSsl(bool httpsVerifyPeers,
405 { 468 const std::string& httpsVerifyCertificates)
406 if (caCertificates_.empty()) 469 {
407 {
408 return globalCACertificates_;
409 }
410 else
411 {
412 return caCertificates_;
413 }
414 }
415
416
417 void HttpClient::GlobalInitialize(bool httpsVerifyPeers,
418 const std::string& httpsVerifyCertificates)
419 {
420 globalVerifyPeers_ = httpsVerifyPeers;
421 globalCACertificates_ = httpsVerifyCertificates;
422
423 #if ORTHANC_SSL_ENABLED == 1 470 #if ORTHANC_SSL_ENABLED == 1
424 if (httpsVerifyPeers) 471 if (httpsVerifyPeers)
425 { 472 {
426 if (globalCACertificates_.empty()) 473 if (httpsVerifyCertificates.empty())
427 { 474 {
428 LOG(WARNING) << "No certificates are provided to validate peers, " 475 LOG(WARNING) << "No certificates are provided to validate peers, "
429 << "set \"HttpsCACertificates\" if you need to do HTTPS requests"; 476 << "set \"HttpsCACertificates\" if you need to do HTTPS requests";
430 } 477 }
431 else 478 else
432 { 479 {
433 LOG(WARNING) << "HTTPS will use the CA certificates from this file: " << globalCACertificates_; 480 LOG(WARNING) << "HTTPS will use the CA certificates from this file: " << httpsVerifyCertificates;
434 } 481 }
435 } 482 }
436 else 483 else
437 { 484 {
438 LOG(WARNING) << "The verification of the peers in HTTPS requests is disabled!"; 485 LOG(WARNING) << "The verification of the peers in HTTPS requests is disabled";
439 } 486 }
440 #endif 487 #endif
441 488
489 GlobalParameters::GetInstance().ConfigureSsl(httpsVerifyPeers, httpsVerifyCertificates);
490 }
491
492
493 void HttpClient::GlobalInitialize()
494 {
442 CheckCode(curl_global_init(CURL_GLOBAL_DEFAULT)); 495 CheckCode(curl_global_init(CURL_GLOBAL_DEFAULT));
443 } 496 }
444 497
498
499 void HttpClient::GlobalFinalize()
500 {
501 curl_global_cleanup();
502 }
445 503
446 void HttpClient::GlobalFinalize() 504
447 { 505 void HttpClient::SetDefaultProxy(const std::string& proxy)
448 curl_global_cleanup(); 506 {
449 } 507 GlobalParameters::GetInstance().SetDefaultProxy(proxy);
450 508 }
451 509
510
452 void HttpClient::SetDefaultTimeout(long timeout) 511 void HttpClient::SetDefaultTimeout(long timeout)
453 { 512 {
454 LOG(INFO) << "Setting the default timeout for HTTP client connections: " << timeout << " seconds"; 513 GlobalParameters::GetInstance().SetDefaultTimeout(timeout);
455 globalTimeout_ = timeout;
456 } 514 }
457 515
458 516
459 void HttpClient::ApplyAndThrowException(std::string& answer) 517 void HttpClient::ApplyAndThrowException(std::string& answer)
460 { 518 {