# HG changeset patch # User Sebastien Jodogne # Date 1535022708 -7200 # Node ID dc73300897366614fd2cbe9679c7185cc9e5cf1b # Parent 6e3a60b85da6e5fdfc98b09d270dcc3b33c77d9c "OrthancPeers" configuration option now allows to specify HTTP headers diff -r 6e3a60b85da6 -r dc7330089736 Core/HttpClient.cpp --- a/Core/HttpClient.cpp Wed Aug 22 16:55:07 2018 +0200 +++ b/Core/HttpClient.cpp Thu Aug 23 13:11:48 2018 +0200 @@ -400,6 +400,13 @@ SetPkcs11Enabled(service.IsPkcs11Enabled()); SetUrl(service.GetUrl() + uri); + + for (WebServiceParameters::HttpHeaders::const_iterator + it = service.GetHttpHeaders().begin(); + it != service.GetHttpHeaders().end(); ++it) + { + AddHeader(it->first, it->second); + } } diff -r 6e3a60b85da6 -r dc7330089736 Core/WebServiceParameters.cpp --- a/Core/WebServiceParameters.cpp Wed Aug 22 16:55:07 2018 +0200 +++ b/Core/WebServiceParameters.cpp Thu Aug 23 13:11:48 2018 +0200 @@ -37,20 +37,31 @@ #include "Logging.h" #include "OrthancException.h" #include "SerializationToolbox.h" +#include "Toolbox.h" #if ORTHANC_SANDBOXED == 0 -# include "../Core/SystemToolbox.h" +# include "SystemToolbox.h" #endif #include namespace Orthanc { + static const char* KEY_CERTIFICATE_FILE = "CertificateFile"; + static const char* KEY_CERTIFICATE_KEY_FILE = "CertificateKeyFile"; + static const char* KEY_CERTIFICATE_KEY_PASSWORD = "CertificateKeyPassword"; + static const char* KEY_HTTP_HEADERS = "HttpHeaders"; + static const char* KEY_PASSWORD = "Password"; + static const char* KEY_PKCS11 = "Pkcs11"; + static const char* KEY_URL = "Url"; + static const char* KEY_URL_2 = "URL"; + static const char* KEY_USERNAME = "Username"; + + WebServiceParameters::WebServiceParameters() : - advancedFormat_(false), - url_("http://127.0.0.1:8042/"), pkcs11Enabled_(false) { + SetUrl("http://127.0.0.1:8042/"); } @@ -62,7 +73,50 @@ } -#if ORTHANC_SANDBOXED == 0 + void WebServiceParameters::SetUrl(const std::string& url) + { + if (!Toolbox::StartsWith(url, "http://") && + !Toolbox::StartsWith(url, "https://")) + { + LOG(ERROR) << "Bad URL: " << url; + throw OrthancException(ErrorCode_BadFileFormat); + } + + // Add trailing slash if needed + if (url[url.size() - 1] == '/') + { + url_ = url; + } + else + { + url_ = url + '/'; + } + } + + + void WebServiceParameters::ClearCredentials() + { + username_.clear(); + password_.clear(); + } + + + void WebServiceParameters::SetCredentials(const std::string& username, + const std::string& password) + { + if (username.empty() && + !password.empty()) + { + throw OrthancException(ErrorCode_BadFileFormat); + } + else + { + username_ = username; + password_ = password; + } + } + + void WebServiceParameters::SetClientCertificate(const std::string& certificateFile, const std::string& certificateKeyFile, const std::string& certificateKeyPassword) @@ -72,43 +126,24 @@ throw OrthancException(ErrorCode_ParameterOutOfRange); } - if (!SystemToolbox::IsRegularFile(certificateFile)) + if (certificateKeyPassword.empty()) { - LOG(ERROR) << "Cannot open certificate file: " << certificateFile; - throw OrthancException(ErrorCode_InexistentFile); + LOG(ERROR) << "The password for the HTTPS certificate is not provided: " << certificateFile; + throw OrthancException(ErrorCode_BadFileFormat); } - if (!certificateKeyFile.empty() && - !SystemToolbox::IsRegularFile(certificateKeyFile)) - { - LOG(ERROR) << "Cannot open key file: " << certificateKeyFile; - throw OrthancException(ErrorCode_InexistentFile); - } - - advancedFormat_ = true; certificateFile_ = certificateFile; certificateKeyFile_ = certificateKeyFile; certificateKeyPassword_ = certificateKeyPassword; } -#endif - static void AddTrailingSlash(std::string& url) - { - if (url.size() != 0 && - url[url.size() - 1] != '/') - { - url += '/'; - } - } - - - void WebServiceParameters::FromJsonArray(const Json::Value& peer) + void WebServiceParameters::FromSimpleFormat(const Json::Value& peer) { assert(peer.isArray()); - advancedFormat_ = false; pkcs11Enabled_ = false; + ClearClientCertificate(); if (peer.size() != 1 && peer.size() != 3) @@ -116,19 +151,11 @@ throw OrthancException(ErrorCode_BadFileFormat); } - std::string url = peer.get(0u, "").asString(); - if (url.empty()) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - AddTrailingSlash(url); - SetUrl(url); + SetUrl(peer.get(0u, "").asString()); if (peer.size() == 1) { - SetUsername(""); - SetPassword(""); + ClearCredentials(); } else if (peer.size() == 2) { @@ -137,8 +164,8 @@ } else if (peer.size() == 3) { - SetUsername(peer.get(1u, "").asString()); - SetPassword(peer.get(2u, "").asString()); + SetCredentials(peer.get(1u, "").asString(), + peer.get(2u, "").asString()); } else { @@ -166,70 +193,90 @@ } - void WebServiceParameters::FromJsonObject(const Json::Value& peer) + void WebServiceParameters::FromAdvancedFormat(const Json::Value& peer) { assert(peer.isObject()); - advancedFormat_ = true; - std::string url = GetStringMember(peer, "Url", ""); + std::string url = GetStringMember(peer, KEY_URL, ""); if (url.empty()) { - throw OrthancException(ErrorCode_BadFileFormat); + SetUrl(GetStringMember(peer, KEY_URL_2, "")); + } + else + { + SetUrl(url); } - AddTrailingSlash(url); - SetUrl(url); - - SetUsername(GetStringMember(peer, "Username", "")); - SetPassword(GetStringMember(peer, "Password", "")); + SetCredentials(GetStringMember(peer, KEY_USERNAME, ""), + GetStringMember(peer, KEY_PASSWORD, "")); - if (!username_.empty() && - !peer.isMember("Password")) + std::string file = GetStringMember(peer, KEY_CERTIFICATE_FILE, ""); + if (!file.empty()) { - LOG(ERROR) << "The HTTP password is not provided"; - throw OrthancException(ErrorCode_BadFileFormat); + SetClientCertificate(file, GetStringMember(peer, KEY_CERTIFICATE_KEY_FILE, ""), + GetStringMember(peer, KEY_CERTIFICATE_KEY_PASSWORD, "")); + } + else + { + ClearClientCertificate(); } -#if ORTHANC_SANDBOXED == 0 - if (peer.isMember("CertificateFile")) + if (peer.isMember(KEY_PKCS11)) { - SetClientCertificate(GetStringMember(peer, "CertificateFile", ""), - GetStringMember(peer, "CertificateKeyFile", ""), - GetStringMember(peer, "CertificateKeyPassword", "")); - - if (!peer.isMember("CertificateKeyPassword")) + if (peer[KEY_PKCS11].type() == Json::booleanValue) { - LOG(ERROR) << "The password for the HTTPS certificate is not provided"; - throw OrthancException(ErrorCode_BadFileFormat); - } - } -#endif - - if (peer.isMember("Pkcs11")) - { - if (peer["Pkcs11"].type() == Json::booleanValue) - { - pkcs11Enabled_ = peer["Pkcs11"].asBool(); + pkcs11Enabled_ = peer[KEY_PKCS11].asBool(); } else { throw OrthancException(ErrorCode_BadFileFormat); } } + else + { + pkcs11Enabled_ = false; + } + + headers_.clear(); + + if (peer.isMember(KEY_HTTP_HEADERS)) + { + const Json::Value& h = peer[KEY_HTTP_HEADERS]; + if (h.type() != Json::objectValue) + { + throw OrthancException(ErrorCode_BadFileFormat); + } + else + { + Json::Value::Members keys = h.getMemberNames(); + for (size_t i = 0; i < keys.size(); i++) + { + const Json::Value& value = h[keys[i]]; + if (value.type() != Json::stringValue) + { + throw OrthancException(ErrorCode_BadFileFormat); + } + else + { + headers_[keys[i]] = value.asString(); + } + } + } + } } - void WebServiceParameters::FromJson(const Json::Value& peer) + void WebServiceParameters::Unserialize(const Json::Value& peer) { try { if (peer.isArray()) { - FromJsonArray(peer); + FromSimpleFormat(peer); } else if (peer.isObject()) { - FromJsonObject(peer); + FromAdvancedFormat(peer); } else { @@ -247,39 +294,89 @@ } - void WebServiceParameters::ToJson(Json::Value& value, - bool includePasswords) const + void WebServiceParameters::ListHttpHeaders(std::set& target) const + { + target.clear(); + + for (HttpHeaders::const_iterator it = headers_.begin(); + it != headers_.end(); ++it) + { + target.insert(it->first); + } + } + + + bool WebServiceParameters::LookupHttpHeader(std::string& value, + const std::string& key) const { - if (advancedFormat_) + HttpHeaders::const_iterator found = headers_.find(key); + + if (found == headers_.end()) + { + return false; + } + else + { + value = found->second; + return true; + } + } + + + bool WebServiceParameters::IsAdvancedFormatNeeded() const + { + return (!certificateFile_.empty() || + !certificateKeyFile_.empty() || + !certificateKeyPassword_.empty() || + pkcs11Enabled_ || + !headers_.empty()); + } + + + void WebServiceParameters::Serialize(Json::Value& value, + bool forceAdvancedFormat, + bool includePasswords) const + { + if (forceAdvancedFormat || + IsAdvancedFormatNeeded()) { value = Json::objectValue; - value["Url"] = url_; + value[KEY_URL] = url_; if (!username_.empty() || !password_.empty()) { - value["Username"] = username_; + value[KEY_USERNAME] = username_; if (includePasswords) { - value["Password"] = password_; + value[KEY_PASSWORD] = password_; } } if (!certificateFile_.empty()) { - value["CertificateFile"] = certificateFile_; + value[KEY_CERTIFICATE_FILE] = certificateFile_; } if (!certificateKeyFile_.empty()) { - value["CertificateKeyFile"] = certificateKeyFile_; + value[KEY_CERTIFICATE_KEY_FILE] = certificateKeyFile_; } if (!certificateKeyPassword_.empty() && includePasswords) { - value["CertificateKeyPassword"] = certificateKeyPassword_; + value[KEY_CERTIFICATE_KEY_PASSWORD] = certificateKeyPassword_; + } + + value[KEY_PKCS11] = pkcs11Enabled_; + + value[KEY_HTTP_HEADERS] = Json::objectValue; + for (HttpHeaders::const_iterator it = headers_.begin(); + it != headers_.end(); ++it) + { + value[KEY_HTTP_HEADERS][it->first] = it->second; } } else @@ -291,50 +388,30 @@ !password_.empty()) { value.append(username_); - - if (includePasswords) - { - value.append(password_); - } + value.append(includePasswords ? password_ : ""); } } } - - void WebServiceParameters::Serialize(Json::Value& target) const - { - target = Json::objectValue; - target["URL"] = url_; - target["Username"] = username_; - target["Password"] = password_; - target["CertificateFile"] = certificateFile_; - target["CertificateKeyFile"] = certificateKeyFile_; - target["CertificateKeyPassword"] = certificateKeyPassword_; - target["PKCS11"] = pkcs11Enabled_; - target["AdvancedFormat"] = advancedFormat_; - } - #if ORTHANC_SANDBOXED == 0 - WebServiceParameters::WebServiceParameters(const Json::Value& serialized) : - advancedFormat_(true) + void WebServiceParameters::CheckClientCertificate() const { - url_ = SerializationToolbox::ReadString(serialized, "URL"); - username_ = SerializationToolbox::ReadString(serialized, "Username"); - password_ = SerializationToolbox::ReadString(serialized, "Password"); + if (!certificateFile_.empty()) + { + if (!SystemToolbox::IsRegularFile(certificateFile_)) + { + LOG(ERROR) << "Cannot open certificate file: " << certificateFile_; + throw OrthancException(ErrorCode_InexistentFile); + } - std::string a, b, c; - a = SerializationToolbox::ReadString(serialized, "CertificateFile"); - b = SerializationToolbox::ReadString(serialized, "CertificateKeyFile"); - c = SerializationToolbox::ReadString(serialized, "CertificateKeyPassword"); - - if (!a.empty()) - { - SetClientCertificate(a, b, c); + if (!certificateKeyFile_.empty() && + !SystemToolbox::IsRegularFile(certificateKeyFile_)) + { + LOG(ERROR) << "Cannot open key file: " << certificateKeyFile_; + throw OrthancException(ErrorCode_InexistentFile); + } } - - pkcs11Enabled_ = SerializationToolbox::ReadBoolean(serialized, "PKCS11"); - advancedFormat_ = SerializationToolbox::ReadBoolean(serialized, "AdvancedFormat"); } #endif } diff -r 6e3a60b85da6 -r dc7330089736 Core/WebServiceParameters.h --- a/Core/WebServiceParameters.h Wed Aug 22 16:55:07 2018 +0200 +++ b/Core/WebServiceParameters.h Thu Aug 23 13:11:48 2018 +0200 @@ -37,6 +37,8 @@ # error The macro ORTHANC_SANDBOXED must be defined #endif +#include +#include #include #include @@ -44,64 +46,58 @@ { class WebServiceParameters { + public: + typedef std::map HttpHeaders; + private: - bool advancedFormat_; - std::string url_; - std::string username_; - std::string password_; - std::string certificateFile_; - std::string certificateKeyFile_; - std::string certificateKeyPassword_; - bool pkcs11Enabled_; + std::string url_; + std::string username_; + std::string password_; + std::string certificateFile_; + std::string certificateKeyFile_; + std::string certificateKeyPassword_; + bool pkcs11Enabled_; + HttpHeaders headers_; - void FromJsonArray(const Json::Value& peer); + void FromSimpleFormat(const Json::Value& peer); - void FromJsonObject(const Json::Value& peer); + void FromAdvancedFormat(const Json::Value& peer); public: WebServiceParameters(); -#if ORTHANC_SANDBOXED == 0 - WebServiceParameters(const Json::Value& serialized); -#endif + WebServiceParameters(const Json::Value& serialized) + { + Unserialize(serialized); + } const std::string& GetUrl() const { return url_; } - void SetUrl(const std::string& url) - { - url_ = url; - } + void SetUrl(const std::string& url); + + void ClearCredentials(); + void SetCredentials(const std::string& username, + const std::string& password); + const std::string& GetUsername() const { return username_; } - void SetUsername(const std::string& username) - { - username_ = username; - } - const std::string& GetPassword() const { return password_; } - void SetPassword(const std::string& password) - { - password_ = password; - } - void ClearClientCertificate(); -#if ORTHANC_SANDBOXED == 0 void SetClientCertificate(const std::string& certificateFile, const std::string& certificateKeyFile, const std::string& certificateKeyPassword); -#endif const std::string& GetCertificateFile() const { @@ -118,9 +114,9 @@ return certificateKeyPassword_; } - void SetPkcs11Enabled(bool pkcs11Enabled) + void SetPkcs11Enabled(bool enabled) { - pkcs11Enabled_ = pkcs11Enabled; + pkcs11Enabled_ = enabled; } bool IsPkcs11Enabled() const @@ -128,11 +124,37 @@ return pkcs11Enabled_; } - void FromJson(const Json::Value& peer); + void AddHttpHeader(const std::string& key, + const std::string& value) + { + headers_[key] = value; + } + + void ClearHttpHeaders() + { + headers_.clear(); + } + + const HttpHeaders& GetHttpHeaders() const + { + return headers_; + } - void ToJson(Json::Value& value, - bool includePasswords) const; + void ListHttpHeaders(std::set& target) const; + + bool LookupHttpHeader(std::string& value, + const std::string& key) const; + + bool IsAdvancedFormatNeeded() const; - void Serialize(Json::Value& target) const; + void Unserialize(const Json::Value& peer); + + void Serialize(Json::Value& value, + bool forceAdvancedFormat, + bool includePasswords) const; + +#if ORTHANC_SANDBOXED == 0 + void CheckClientCertificate() const; +#endif }; } diff -r 6e3a60b85da6 -r dc7330089736 NEWS --- a/NEWS Wed Aug 22 16:55:07 2018 +0200 +++ b/NEWS Thu Aug 23 13:11:48 2018 +0200 @@ -1,6 +1,10 @@ Pending changes in the mainline =============================== +General +------- + +* "OrthancPeers" configuration option now allows to specify HTTP headers Plugins ------- diff -r 6e3a60b85da6 -r dc7330089736 OrthancServer/OrthancInitialization.cpp --- a/OrthancServer/OrthancInitialization.cpp Wed Aug 22 16:55:07 2018 +0200 +++ b/OrthancServer/OrthancInitialization.cpp Thu Aug 23 13:11:48 2018 +0200 @@ -277,6 +277,7 @@ { WebServiceParameters peer; Configuration::GetOrthancPeer(peer, *it); + peer.CheckClientCertificate(); } Configuration::GetListOfDicomModalities(ids); @@ -628,7 +629,7 @@ } else { - peer.FromJson(modalities[name]); + peer.Unserialize(modalities[name]); return true; } } @@ -942,6 +943,8 @@ void Configuration::UpdatePeer(const std::string& symbolicName, const WebServiceParameters& peer) { + peer.CheckClientCertificate(); + boost::recursive_mutex::scoped_lock lock(globalMutex_); if (!configuration_.isMember("OrthancPeers")) @@ -960,7 +963,9 @@ peers.removeMember(symbolicName); Json::Value v; - peer.ToJson(v, true); + peer.Serialize(v, + false /* use simple format if possible */, + true /* include passwords */); peers[symbolicName] = v; } diff -r 6e3a60b85da6 -r dc7330089736 OrthancServer/OrthancRestApi/OrthancRestModalities.cpp --- a/OrthancServer/OrthancRestApi/OrthancRestModalities.cpp Wed Aug 22 16:55:07 2018 +0200 +++ b/OrthancServer/OrthancRestApi/OrthancRestModalities.cpp Thu Aug 23 13:11:48 2018 +0200 @@ -983,7 +983,7 @@ if (reader.parse(call.GetBodyData(), call.GetBodyData() + call.GetBodySize(), json)) { WebServiceParameters peer; - peer.FromJson(json); + peer.Unserialize(json); Configuration::UpdatePeer(call.GetUriComponent("id", ""), peer); call.GetOutput().AnswerBuffer("", "text/plain"); } diff -r 6e3a60b85da6 -r dc7330089736 OrthancServer/ServerJobs/Operations/StorePeerOperation.cpp --- a/OrthancServer/ServerJobs/Operations/StorePeerOperation.cpp Wed Aug 22 16:55:07 2018 +0200 +++ b/OrthancServer/ServerJobs/Operations/StorePeerOperation.cpp Thu Aug 23 13:11:48 2018 +0200 @@ -87,7 +87,9 @@ { result = Json::objectValue; result["Type"] = "StorePeer"; - peer_.Serialize(result["Peer"]); + peer_.Serialize(result["Peer"], + true /* force advanced format */, + true /* include passwords */); } diff -r 6e3a60b85da6 -r dc7330089736 OrthancServer/ServerJobs/OrthancPeerStoreJob.cpp --- a/OrthancServer/ServerJobs/OrthancPeerStoreJob.cpp Wed Aug 22 16:55:07 2018 +0200 +++ b/OrthancServer/ServerJobs/OrthancPeerStoreJob.cpp Thu Aug 23 13:11:48 2018 +0200 @@ -98,7 +98,9 @@ SetOfInstancesJob::GetPublicContent(value); Json::Value v; - peer_.ToJson(v, false /* don't include passwords */); + peer_.Serialize(v, + false /* allow simple format if possible */, + false /* don't include passwords */); value["Peer"] = v; } @@ -122,7 +124,9 @@ } else { - peer_.Serialize(target[PEER]); + peer_.Serialize(target[PEER], + true /* force advanced format */, + true /* include passwords */); return true; } } diff -r 6e3a60b85da6 -r dc7330089736 Resources/Configuration.json --- a/Resources/Configuration.json Wed Aug 22 16:55:07 2018 +0200 +++ b/Resources/Configuration.json Thu Aug 23 13:11:48 2018 +0200 @@ -210,14 +210,15 @@ /** * This is another, more advanced format to define Orthanc - * peers. It notably allows to specify a HTTPS client certificate - * in the PEM format (as in the "--cert" option of curl), or to - * enable PKCS#11 authentication for smart cards. + * peers. It notably allows to specify HTTP headers, a HTTPS + * client certificate in the PEM format (as in the "--cert" option + * of curl), or to enable PKCS#11 authentication for smart cards. **/ // "peer" : { // "Url" : "http://127.0.0.1:8043/", // "Username" : "alice", // "Password" : "alicePassword", + // "HttpHeaders" : { "Token" : "Hello world" }, // "CertificateFile" : "client.crt", // "CertificateKeyFile" : "client.key", // "CertificateKeyPassword" : "certpass", diff -r 6e3a60b85da6 -r dc7330089736 UnitTestsSources/MultiThreadingTests.cpp --- a/UnitTestsSources/MultiThreadingTests.cpp Wed Aug 22 16:55:07 2018 +0200 +++ b/UnitTestsSources/MultiThreadingTests.cpp Thu Aug 23 13:11:48 2018 +0200 @@ -1299,8 +1299,7 @@ { WebServiceParameters peer; peer.SetUrl("http://localhost/"); - peer.SetUsername("username"); - peer.SetPassword("password"); + peer.SetCredentials("username", "password"); peer.SetPkcs11Enabled(true); StorePeerOperation operation(peer); @@ -1443,8 +1442,7 @@ { WebServiceParameters peer; peer.SetUrl("http://localhost/"); - peer.SetUsername("username"); - peer.SetPassword("password"); + peer.SetCredentials("username", "password"); peer.SetPkcs11Enabled(true); OrthancPeerStoreJob job(GetContext()); diff -r 6e3a60b85da6 -r dc7330089736 UnitTestsSources/RestApiTests.cpp --- a/UnitTestsSources/RestApiTests.cpp Wed Aug 22 16:55:07 2018 +0200 +++ b/UnitTestsSources/RestApiTests.cpp Thu Aug 23 13:11:48 2018 +0200 @@ -469,3 +469,137 @@ ASSERT_EQ("plain", h.GetSubType()); } } + + +TEST(WebServiceParameters, Serialization) +{ + { + Json::Value v = Json::arrayValue; + v.append("http://localhost:8042/"); + + WebServiceParameters p(v); + ASSERT_FALSE(p.IsAdvancedFormatNeeded()); + + Json::Value v2; + p.Serialize(v2, false, true); + ASSERT_EQ(v, v2); + + WebServiceParameters p2(v2); + ASSERT_EQ("http://localhost:8042/", p2.GetUrl()); + ASSERT_TRUE(p2.GetUsername().empty()); + ASSERT_TRUE(p2.GetPassword().empty()); + ASSERT_TRUE(p2.GetCertificateFile().empty()); + ASSERT_TRUE(p2.GetCertificateKeyFile().empty()); + ASSERT_TRUE(p2.GetCertificateKeyPassword().empty()); + ASSERT_FALSE(p2.IsPkcs11Enabled()); + } + + { + Json::Value v = Json::arrayValue; + v.append("http://localhost:8042/"); + v.append("user"); + v.append("pass"); + + WebServiceParameters p(v); + ASSERT_FALSE(p.IsAdvancedFormatNeeded()); + ASSERT_EQ("http://localhost:8042/", p.GetUrl()); + ASSERT_EQ("user", p.GetUsername()); + ASSERT_EQ("pass", p.GetPassword()); + ASSERT_TRUE(p.GetCertificateFile().empty()); + ASSERT_TRUE(p.GetCertificateKeyFile().empty()); + ASSERT_TRUE(p.GetCertificateKeyPassword().empty()); + ASSERT_FALSE(p.IsPkcs11Enabled()); + + Json::Value v2; + p.Serialize(v2, false, true); + ASSERT_EQ(v, v2); + + p.Serialize(v2, false, false /* no password */); + WebServiceParameters p2(v2); + ASSERT_EQ(Json::arrayValue, v2.type()); + ASSERT_EQ(3u, v2.size()); + ASSERT_EQ("http://localhost:8042/", v2[0u].asString()); + ASSERT_EQ("user", v2[1u].asString()); + ASSERT_TRUE(v2[2u].asString().empty()); + } + + { + Json::Value v = Json::arrayValue; + v.append("http://localhost:8042/"); + + WebServiceParameters p(v); + ASSERT_FALSE(p.IsAdvancedFormatNeeded()); + p.SetPkcs11Enabled(true); + ASSERT_TRUE(p.IsAdvancedFormatNeeded()); + + Json::Value v2; + p.Serialize(v2, false, true); + WebServiceParameters p2(v2); + + ASSERT_EQ(Json::objectValue, v2.type()); + ASSERT_EQ(3u, v2.size()); + ASSERT_EQ("http://localhost:8042/", v2["Url"].asString()); + ASSERT_TRUE(v2["Pkcs11"].asBool()); + ASSERT_EQ(Json::objectValue, v2["HttpHeaders"].type()); + ASSERT_EQ(0u, v2["HttpHeaders"].size()); + } + + { + Json::Value v = Json::arrayValue; + v.append("http://localhost:8042/"); + + WebServiceParameters p(v); + ASSERT_FALSE(p.IsAdvancedFormatNeeded()); + p.SetClientCertificate("a", "b", "c"); + ASSERT_TRUE(p.IsAdvancedFormatNeeded()); + + Json::Value v2; + p.Serialize(v2, false, true); + WebServiceParameters p2(v2); + + ASSERT_EQ(Json::objectValue, v2.type()); + ASSERT_EQ(6u, v2.size()); + ASSERT_EQ("http://localhost:8042/", v2["Url"].asString()); + ASSERT_EQ("a", v2["CertificateFile"].asString()); + ASSERT_EQ("b", v2["CertificateKeyFile"].asString()); + ASSERT_EQ("c", v2["CertificateKeyPassword"].asString()); + ASSERT_FALSE(v2["Pkcs11"].asBool()); + ASSERT_EQ(Json::objectValue, v2["HttpHeaders"].type()); + ASSERT_EQ(0u, v2["HttpHeaders"].size()); + } + + { + Json::Value v = Json::arrayValue; + v.append("http://localhost:8042/"); + + WebServiceParameters p(v); + ASSERT_FALSE(p.IsAdvancedFormatNeeded()); + p.AddHttpHeader("a", "b"); + p.AddHttpHeader("c", "d"); + ASSERT_TRUE(p.IsAdvancedFormatNeeded()); + + Json::Value v2; + p.Serialize(v2, false, true); + WebServiceParameters p2(v2); + + ASSERT_EQ(Json::objectValue, v2.type()); + ASSERT_EQ(3u, v2.size()); + ASSERT_EQ("http://localhost:8042/", v2["Url"].asString()); + ASSERT_FALSE(v2["Pkcs11"].asBool()); + ASSERT_EQ(Json::objectValue, v2["HttpHeaders"].type()); + ASSERT_EQ(2u, v2["HttpHeaders"].size()); + ASSERT_EQ("b", v2["HttpHeaders"]["a"].asString()); + ASSERT_EQ("d", v2["HttpHeaders"]["c"].asString()); + + std::set a; + p2.ListHttpHeaders(a); + ASSERT_EQ(2u, a.size()); + ASSERT_TRUE(a.find("a") != a.end()); + ASSERT_TRUE(a.find("c") != a.end()); + + std::string s; + ASSERT_TRUE(p2.LookupHttpHeader(s, "a")); ASSERT_EQ("b", s); + ASSERT_TRUE(p2.LookupHttpHeader(s, "c")); ASSERT_EQ("d", s); + ASSERT_FALSE(p2.LookupHttpHeader(s, "nope")); + } +}