# HG changeset patch # User Sebastien Jodogne # Date 1466519670 -7200 # Node ID 6ea2e264ca50719fa1ddc6ba7e728b4610008b21 # Parent e33e0ae51d7b104de28c56df1bc2ee4b46873117 retrieval of HTTP headers in answers within HttpClient diff -r e33e0ae51d7b -r 6ea2e264ca50 Core/ChunkedBuffer.cpp --- a/Core/ChunkedBuffer.cpp Tue Jun 21 15:17:49 2016 +0200 +++ b/Core/ChunkedBuffer.cpp Tue Jun 21 16:34:30 2016 +0200 @@ -51,17 +51,19 @@ } - void ChunkedBuffer::AddChunk(const char* chunkData, + void ChunkedBuffer::AddChunk(const void* chunkData, size_t chunkSize) { if (chunkSize == 0) { return; } - - assert(chunkData != NULL); - chunks_.push_back(new std::string(chunkData, chunkSize)); - numBytes_ += chunkSize; + else + { + assert(chunkData != NULL); + chunks_.push_back(new std::string(reinterpret_cast(chunkData), chunkSize)); + numBytes_ += chunkSize; + } } diff -r e33e0ae51d7b -r 6ea2e264ca50 Core/ChunkedBuffer.h --- a/Core/ChunkedBuffer.h Tue Jun 21 15:17:49 2016 +0200 +++ b/Core/ChunkedBuffer.h Tue Jun 21 16:34:30 2016 +0200 @@ -61,7 +61,7 @@ return numBytes_; } - void AddChunk(const char* chunkData, + void AddChunk(const void* chunkData, size_t chunkSize); void AddChunk(const std::string& chunk); diff -r e33e0ae51d7b -r 6ea2e264ca50 Core/HttpClient.cpp --- a/Core/HttpClient.cpp Tue Jun 21 15:17:49 2016 +0200 +++ b/Core/HttpClient.cpp Tue Jun 21 16:34:30 2016 +0200 @@ -36,6 +36,7 @@ #include "Toolbox.h" #include "OrthancException.h" #include "Logging.h" +#include "ChunkedBuffer.h" #include #include @@ -218,18 +219,51 @@ static size_t CurlBodyCallback(void *buffer, size_t size, size_t nmemb, void *payload) { - std::string& target = *(static_cast(payload)); + ChunkedBuffer& target = *(static_cast(payload)); + + size_t length = size * nmemb; + if (length == 0) + { + return 0; + } + else + { + target.AddChunk(buffer, length); + return length; + } + } + + + static size_t CurlHeaderCallback(void *buffer, size_t size, size_t nmemb, void *payload) + { + HttpClient::HttpHeaders& headers = *(static_cast(payload)); size_t length = size * nmemb; if (length == 0) + { return 0; - - size_t pos = target.size(); + } + else + { + std::string s(reinterpret_cast(buffer), length); + std::size_t colon = s.find(':'); + std::size_t eol = s.find("\r\n"); + if (colon != std::string::npos && + eol != std::string::npos) + { + std::string tmp; + Toolbox::ToLowerCase(tmp, s.substr(0, colon)); + std::string key = Toolbox::StripSpaces(tmp); - target.resize(pos + length); - memcpy(&target.at(pos), buffer, length); + if (!key.empty()) + { + std::string value = Toolbox::StripSpaces(s.substr(colon + 1, eol)); + headers[key] = value; + } + } - return length; + return length; + } } @@ -354,11 +388,22 @@ } - bool HttpClient::ApplyInternal(std::string& answer) + bool HttpClient::ApplyInternal(std::string& answer, + HttpHeaders* headers) { answer.clear(); CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_URL, url_.c_str())); - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_WRITEDATA, &answer)); + + if (headers == NULL) + { + CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_HEADERFUNCTION, NULL)); + CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_HEADERDATA, NULL)); + } + else + { + CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_HEADERFUNCTION, &CurlHeaderCallback)); + CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_HEADERDATA, headers)); + } #if ORTHANC_SSL_ENABLED == 1 // Setup HTTPS-related options @@ -520,6 +565,9 @@ CURLcode code; long status = 0; + ChunkedBuffer buffer; + CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_WRITEDATA, &buffer)); + if (boost::starts_with(url_, "https://")) { code = OrthancHttpClientPerformSSL(pimpl_->curl_, &status); @@ -543,8 +591,13 @@ bool success = (status >= 200 && status < 300); - if (!success) + if (success) { + buffer.Flatten(answer); + } + else + { + answer.clear(); LOG(INFO) << "Error in HTTP request, received HTTP status " << status << " (" << EnumerationToString(lastStatus_) << ")"; } @@ -553,16 +606,11 @@ } - bool HttpClient::Apply(std::string& answer) - { - return ApplyInternal(answer); - } - - - bool HttpClient::Apply(Json::Value& answer) + bool HttpClient::ApplyInternal(Json::Value& answer, + HttpClient::HttpHeaders* answerHeaders) { std::string s; - if (Apply(s)) + if (ApplyInternal(s, answerHeaders)) { Json::Reader reader; return reader.parse(s, answer); diff -r e33e0ae51d7b -r 6ea2e264ca50 Core/HttpClient.h --- a/Core/HttpClient.h Tue Jun 21 15:17:49 2016 +0200 +++ b/Core/HttpClient.h Tue Jun 21 16:34:30 2016 +0200 @@ -43,6 +43,9 @@ { class HttpClient { + public: + typedef std::map HttpHeaders; + private: class GlobalParameters; @@ -69,7 +72,11 @@ void operator= (const HttpClient&); // Assignment forbidden HttpClient(const HttpClient& base); // Copy forbidden - bool ApplyInternal(std::string& answer); + bool ApplyInternal(std::string& answer, + HttpHeaders* answerHeaders); + + bool ApplyInternal(Json::Value& answer, + HttpHeaders* answerHeaders); public: HttpClient(); @@ -141,9 +148,27 @@ void ClearHeaders(); - bool Apply(std::string& answer); + bool Apply(std::string& answer) + { + return ApplyInternal(answer, NULL); + } + + bool Apply(Json::Value& answer) + { + return ApplyInternal(answer, NULL); + } - bool Apply(Json::Value& answer); + bool Apply(std::string& answer, + HttpHeaders& answerHeaders) + { + return ApplyInternal(answer, &answerHeaders); + } + + bool Apply(Json::Value& answer, + HttpHeaders& answerHeaders) + { + return ApplyInternal(answer, &answerHeaders); + } HttpStatus GetLastStatus() const {