From c8cc9c694786fd51d9d9088d46522243b89da055 Mon Sep 17 00:00:00 2001 From: Casper Meijn Date: Wed, 2 Jan 2019 22:19:04 +0100 Subject: [PATCH 01/19] Remove unused includes from tests --- unittests/dwservice_12_wsdl/test_dwservice_12_wsdl.cpp | 1 - .../dwservice_combined_wsdl/test_dwservice_combined_wsdl.cpp | 1 - unittests/dwservice_wsdl/test_dwservice_wsdl.cpp | 1 - unittests/encapsecurity/test_encapsecurity.cpp | 1 - unittests/groupwise_wsdl/test_groupwise_wsdl.cpp | 1 - unittests/import_definition/test_import_definition.cpp | 1 - unittests/literal_true_false/test_literal.cpp | 1 - .../msexchange_noservice_wsdl/msexchange_noservice_wsdl.cpp | 1 - unittests/msexchange_wsdl/msexchange_wsdl.cpp | 1 - unittests/salesforce_wsdl/salesforce_wsdl.cpp | 1 - unittests/unqualified_formdefault/test_unqualified.cpp | 1 - unittests/webcalls_wsdl/webcalls_wsdl.cpp | 2 -- 12 files changed, 13 deletions(-) diff --git a/unittests/dwservice_12_wsdl/test_dwservice_12_wsdl.cpp b/unittests/dwservice_12_wsdl/test_dwservice_12_wsdl.cpp index 7de010ca7..a16dfecb9 100644 --- a/unittests/dwservice_12_wsdl/test_dwservice_12_wsdl.cpp +++ b/unittests/dwservice_12_wsdl/test_dwservice_12_wsdl.cpp @@ -24,7 +24,6 @@ #include "KDSoapClientInterface.h" #include "KDSoapMessage.h" #include "KDSoapValue.h" -#include "KDSoapAuthentication.h" #include "KDDateTime.h" #include "wsdl_DWService_12.h" #include "httpserver_p.h" diff --git a/unittests/dwservice_combined_wsdl/test_dwservice_combined_wsdl.cpp b/unittests/dwservice_combined_wsdl/test_dwservice_combined_wsdl.cpp index 1851ea9ae..4a38b8343 100644 --- a/unittests/dwservice_combined_wsdl/test_dwservice_combined_wsdl.cpp +++ b/unittests/dwservice_combined_wsdl/test_dwservice_combined_wsdl.cpp @@ -24,7 +24,6 @@ #include "KDSoapClientInterface.h" #include "KDSoapMessage.h" #include "KDSoapValue.h" -#include "KDSoapAuthentication.h" #include "KDDateTime.h" #include "httpserver_p.h" #include diff --git a/unittests/dwservice_wsdl/test_dwservice_wsdl.cpp b/unittests/dwservice_wsdl/test_dwservice_wsdl.cpp index c7b9c6b1d..a68170a54 100644 --- a/unittests/dwservice_wsdl/test_dwservice_wsdl.cpp +++ b/unittests/dwservice_wsdl/test_dwservice_wsdl.cpp @@ -24,7 +24,6 @@ #include "KDSoapClientInterface.h" #include "KDSoapMessage.h" #include "KDSoapValue.h" -#include "KDSoapAuthentication.h" #include "KDDateTime.h" #include "wsdl_DWService.h" #include "httpserver_p.h" diff --git a/unittests/encapsecurity/test_encapsecurity.cpp b/unittests/encapsecurity/test_encapsecurity.cpp index e83a4db37..c514775e1 100644 --- a/unittests/encapsecurity/test_encapsecurity.cpp +++ b/unittests/encapsecurity/test_encapsecurity.cpp @@ -25,7 +25,6 @@ #include "KDSoapMessage.h" #include "KDSoapValue.h" #include "KDSoapPendingCallWatcher.h" -#include "KDSoapAuthentication.h" #include "wsdl_authstateless.h" #include "httpserver_p.h" #include diff --git a/unittests/groupwise_wsdl/test_groupwise_wsdl.cpp b/unittests/groupwise_wsdl/test_groupwise_wsdl.cpp index 90c56ef1c..557c05977 100644 --- a/unittests/groupwise_wsdl/test_groupwise_wsdl.cpp +++ b/unittests/groupwise_wsdl/test_groupwise_wsdl.cpp @@ -24,7 +24,6 @@ #include "KDSoapClientInterface.h" #include "KDSoapMessage.h" #include "KDSoapValue.h" -#include "KDSoapAuthentication.h" #include "KDDateTime.h" #include "wsdl_groupwise.h" #include "httpserver_p.h" diff --git a/unittests/import_definition/test_import_definition.cpp b/unittests/import_definition/test_import_definition.cpp index 11a8db8d4..880b22f7e 100644 --- a/unittests/import_definition/test_import_definition.cpp +++ b/unittests/import_definition/test_import_definition.cpp @@ -25,7 +25,6 @@ #include "KDSoapMessage.h" #include "KDSoapValue.h" #include "KDSoapPendingCallWatcher.h" -#include "KDSoapAuthentication.h" #include "wsdl_import_definition.h" #include "httpserver_p.h" #include diff --git a/unittests/literal_true_false/test_literal.cpp b/unittests/literal_true_false/test_literal.cpp index 20d9b4a87..2779a903e 100644 --- a/unittests/literal_true_false/test_literal.cpp +++ b/unittests/literal_true_false/test_literal.cpp @@ -25,7 +25,6 @@ #include "KDSoapMessage.h" #include "KDSoapValue.h" #include "KDSoapPendingCallWatcher.h" -#include "KDSoapAuthentication.h" #include "wsdl_literal.h" #include "httpserver_p.h" #include diff --git a/unittests/msexchange_noservice_wsdl/msexchange_noservice_wsdl.cpp b/unittests/msexchange_noservice_wsdl/msexchange_noservice_wsdl.cpp index e9b8cf2eb..c47b728ec 100644 --- a/unittests/msexchange_noservice_wsdl/msexchange_noservice_wsdl.cpp +++ b/unittests/msexchange_noservice_wsdl/msexchange_noservice_wsdl.cpp @@ -25,7 +25,6 @@ #include "KDSoapMessage.h" #include "KDSoapValue.h" #include "KDSoapPendingCallWatcher.h" -#include "KDSoapAuthentication.h" #include "wsdl_Services_noservice.h" #include "httpserver_p.h" #include diff --git a/unittests/msexchange_wsdl/msexchange_wsdl.cpp b/unittests/msexchange_wsdl/msexchange_wsdl.cpp index fb40cfe9c..f2deb316c 100644 --- a/unittests/msexchange_wsdl/msexchange_wsdl.cpp +++ b/unittests/msexchange_wsdl/msexchange_wsdl.cpp @@ -25,7 +25,6 @@ #include "KDSoapMessage.h" #include "KDSoapValue.h" #include "KDSoapPendingCallWatcher.h" -#include "KDSoapAuthentication.h" #include "wsdl_Services.h" #include "httpserver_p.h" #include diff --git a/unittests/salesforce_wsdl/salesforce_wsdl.cpp b/unittests/salesforce_wsdl/salesforce_wsdl.cpp index 9b1ae94d2..d45f99e60 100644 --- a/unittests/salesforce_wsdl/salesforce_wsdl.cpp +++ b/unittests/salesforce_wsdl/salesforce_wsdl.cpp @@ -24,7 +24,6 @@ #include "KDSoapClientInterface.h" #include "KDSoapMessage.h" #include "KDSoapValue.h" -#include "KDSoapAuthentication.h" #include "wsdl_salesforce-partner.h" #include "httpserver_p.h" #include diff --git a/unittests/unqualified_formdefault/test_unqualified.cpp b/unittests/unqualified_formdefault/test_unqualified.cpp index 354983613..c13aa9fb2 100644 --- a/unittests/unqualified_formdefault/test_unqualified.cpp +++ b/unittests/unqualified_formdefault/test_unqualified.cpp @@ -25,7 +25,6 @@ #include "KDSoapMessage.h" #include "KDSoapValue.h" #include "KDSoapPendingCallWatcher.h" -#include "KDSoapAuthentication.h" #include "wsdl_unqualified.h" #include "httpserver_p.h" #include diff --git a/unittests/webcalls_wsdl/webcalls_wsdl.cpp b/unittests/webcalls_wsdl/webcalls_wsdl.cpp index 9ee8ee89d..d612d969d 100644 --- a/unittests/webcalls_wsdl/webcalls_wsdl.cpp +++ b/unittests/webcalls_wsdl/webcalls_wsdl.cpp @@ -22,8 +22,6 @@ **********************************************************************/ #include "KDSoapClientInterface.h" -//#include "KDSoapMessage.h" -//#include "KDSoapValue.h" #include "wsdl_soapresponder.h" #include "wsdl_holidays.h" #include "wsdl_BFGlobalService.h" From 1c53d38317083023425005c43aaf5a04d25ab9fa Mon Sep 17 00:00:00 2001 From: Casper Meijn Date: Thu, 3 Jan 2019 14:39:15 +0100 Subject: [PATCH 02/19] Move internal call to be private And mark calling classes as friends --- src/KDSoapClient/KDSoapAuthentication.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/KDSoapClient/KDSoapAuthentication.h b/src/KDSoapClient/KDSoapAuthentication.h index e02c6c9c4..b60994113 100644 --- a/src/KDSoapClient/KDSoapAuthentication.h +++ b/src/KDSoapClient/KDSoapAuthentication.h @@ -40,6 +40,9 @@ QT_END_NAMESPACE class KDSOAP_EXPORT KDSoapAuthentication { public: + friend class KDSoapClientInterfacePrivate; + friend class KDSoapThreadTask; + /** * Constructs an empty authentication object. */ @@ -82,6 +85,7 @@ class KDSOAP_EXPORT KDSoapAuthentication */ KDSoapAuthentication &operator=(const KDSoapAuthentication &other); +private: /** * \internal */ From e70dd41224538a04d19043d15794003bdf9d3c36 Mon Sep 17 00:00:00 2001 From: Casper Meijn Date: Thu, 3 Jan 2019 16:44:39 +0100 Subject: [PATCH 03/19] Add support for WS-UsernameToken Extended KDSoapAuthentication to support WS-UsernameToken. When useWSUsernameToken is set, then the WS-UsernameToken headers are included in each request. --- doc/CHANGES_1_8.txt | 1 + src/KDSoapClient/KDSoapAuthentication.cpp | 100 ++++++++++++++++- src/KDSoapClient/KDSoapAuthentication.h | 45 ++++++++ src/KDSoapClient/KDSoapClientInterface.cpp | 2 +- src/KDSoapClient/KDSoapMessageWriter.cpp | 8 +- src/KDSoapClient/KDSoapMessageWriter_p.h | 4 +- src/KDSoapClient/KDSoapNamespaceManager.cpp | 10 ++ src/KDSoapClient/KDSoapNamespaceManager.h | 2 + unittests/CMakeLists.txt | 1 + unittests/unittests.pro | 3 +- .../ws_usernametoken_support/CMakeLists.txt | 8 ++ .../ws_usernametoken_support.pro | 9 ++ .../wsusernametoken.wsdl | 61 +++++++++++ .../wsusernametokentest.cpp | 101 ++++++++++++++++++ 14 files changed, 348 insertions(+), 7 deletions(-) create mode 100644 unittests/ws_usernametoken_support/CMakeLists.txt create mode 100644 unittests/ws_usernametoken_support/ws_usernametoken_support.pro create mode 100644 unittests/ws_usernametoken_support/wsusernametoken.wsdl create mode 100644 unittests/ws_usernametoken_support/wsusernametokentest.cpp diff --git a/doc/CHANGES_1_8.txt b/doc/CHANGES_1_8.txt index a39bbdd65..705725e06 100644 --- a/doc/CHANGES_1_8.txt +++ b/doc/CHANGES_1_8.txt @@ -12,6 +12,7 @@ Client-side: * Fix error code when authentication failed * Autodeletion of jobs is now configurable (github pull #125) * Add error details in faultAsString() - and the generated lastError() - coming from the SOAP 1.2 detail element. +* Add support for WS-UsernameToken, see KDSoapAuthentication Server-side: ============ diff --git a/src/KDSoapClient/KDSoapAuthentication.cpp b/src/KDSoapClient/KDSoapAuthentication.cpp index 06e5e9274..78542a729 100644 --- a/src/KDSoapClient/KDSoapAuthentication.cpp +++ b/src/KDSoapClient/KDSoapAuthentication.cpp @@ -1,5 +1,6 @@ /**************************************************************************** ** Copyright (C) 2010-2018 Klaralvdalens Datakonsult AB, a KDAB Group company, info@kdab.com. +** Copyright (C) 2019 Casper Meijn ** All rights reserved. ** ** This file is part of the KD Soap library. @@ -21,15 +22,26 @@ ** **********************************************************************/ #include "KDSoapAuthentication.h" -#include -#include #include +#include +#include +#include +#include +#include "KDSoapNamespacePrefixes_p.h" +#include "KDSoapNamespaceManager.h" class KDSoapAuthentication::Private { public: + Private() : + useWSUsernameToken(false) + {} + QString user; QString password; + bool useWSUsernameToken; + QDateTime overrideWSUsernameCreatedTime; + QByteArray overrideWSUsernameNonce; }; KDSoapAuthentication::KDSoapAuthentication() @@ -64,6 +76,21 @@ void KDSoapAuthentication::setPassword(const QString &password) d->password = password; } +void KDSoapAuthentication::setUseWSUsernameToken(bool useWSUsernameToken) +{ + d->useWSUsernameToken = useWSUsernameToken; +} + +void KDSoapAuthentication::setOverrideWSUsernameCreatedTime(QDateTime overrideWSUsernameCreatedTime) +{ + d->overrideWSUsernameCreatedTime = overrideWSUsernameCreatedTime; +} + +void KDSoapAuthentication::setOverrideWSUsernameNonce(QByteArray overrideWSUsernameNonce) +{ + d->overrideWSUsernameNonce = overrideWSUsernameNonce; +} + QString KDSoapAuthentication::user() const { return d->user; @@ -74,6 +101,21 @@ QString KDSoapAuthentication::password() const return d->password; } +bool KDSoapAuthentication::useWSUsernameToken() const +{ + return d->useWSUsernameToken; +} + +QDateTime KDSoapAuthentication::overrideWSUsernameCreatedTime() const +{ + return d->overrideWSUsernameCreatedTime; +} + +QByteArray KDSoapAuthentication::overrideWSUsernameNonce() const +{ + return d->overrideWSUsernameNonce; +} + bool KDSoapAuthentication::hasAuth() const { return !d->user.isEmpty() || !d->password.isEmpty(); @@ -91,3 +133,57 @@ void KDSoapAuthentication::handleAuthenticationRequired(QNetworkReply *reply, QA reply->setProperty("authAdded", true); } } + +bool KDSoapAuthentication::hasWSUsernameTokenHeader() const +{ + return hasAuth() && d->useWSUsernameToken; +} + +void KDSoapAuthentication::writeWSUsernameTokenHeader(KDSoapNamespacePrefixes &namespacePrefixes, QXmlStreamWriter &writer, const QString &messageNamespace, bool forceQualified) const +{ + Q_UNUSED(namespacePrefixes); + Q_UNUSED(messageNamespace); + Q_UNUSED(forceQualified); + + if (!hasAuth()) { + return; + } + + const QString securityExtentionNS = KDSoapNamespaceManager::soapSecurityExtention(); + const QString securityUtilityNS = KDSoapNamespaceManager::soapSecurityUtility(); + + QByteArray nonce = "kdsoap" + QByteArray::number(qrand()); + if (!d->overrideWSUsernameNonce.isEmpty()) { + nonce = d->overrideWSUsernameNonce; + } + QDateTime time = QDateTime::currentDateTimeUtc(); + if (d->overrideWSUsernameCreatedTime.isValid()) { + time = d->overrideWSUsernameCreatedTime; + } + QString timestamp = time.toString(QLatin1String("yyyy-MM-ddTHH:mm:ssZ")); + QByteArray passwordConcat = nonce + timestamp.toUtf8() + d->password.toUtf8(); + QByteArray passwordHash = QCryptographicHash::hash(passwordConcat, QCryptographicHash::Sha1); + + writer.writeStartElement(securityExtentionNS, QLatin1String("Security")); + writer.writeStartElement(securityExtentionNS, QLatin1String("UsernameToken")); + + writer.writeStartElement(securityExtentionNS, QLatin1String("Nonce")); + writer.writeCharacters(QString::fromLatin1(nonce.toBase64().constData())); + writer.writeEndElement(); + + writer.writeStartElement(securityUtilityNS, QLatin1String("Created")); + writer.writeCharacters(timestamp); + writer.writeEndElement(); + + writer.writeStartElement(securityExtentionNS, QLatin1String("Password")); + writer.writeAttribute(QLatin1String("Type"), QLatin1String("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest")); + writer.writeCharacters(QString::fromLatin1(passwordHash.toBase64().constData())); + writer.writeEndElement(); + + writer.writeStartElement(securityExtentionNS, QLatin1String("Username")); + writer.writeCharacters(d->user); + writer.writeEndElement(); + + writer.writeEndElement(); + writer.writeEndElement(); +} diff --git a/src/KDSoapClient/KDSoapAuthentication.h b/src/KDSoapClient/KDSoapAuthentication.h index b60994113..14a097874 100644 --- a/src/KDSoapClient/KDSoapAuthentication.h +++ b/src/KDSoapClient/KDSoapAuthentication.h @@ -1,5 +1,6 @@ /**************************************************************************** ** Copyright (C) 2010-2018 Klaralvdalens Datakonsult AB, a KDAB Group company, info@kdab.com. +** Copyright (C) 2019 Casper Meijn ** All rights reserved. ** ** This file is part of the KD Soap library. @@ -27,8 +28,11 @@ #include QT_BEGIN_NAMESPACE class QAuthenticator; +class QDateTime; class QNetworkReply; +class QXmlStreamWriter; QT_END_NAMESPACE +class KDSoapNamespacePrefixes; /** * KDSoapAuthentication provides an authentication object. @@ -40,6 +44,7 @@ QT_END_NAMESPACE class KDSOAP_EXPORT KDSoapAuthentication { public: + friend class KDSoapMessageWriter; friend class KDSoapClientInterfacePrivate; friend class KDSoapThreadTask; @@ -74,6 +79,42 @@ class KDSOAP_EXPORT KDSoapAuthentication */ QString password() const; + /** + * Sets whether WS-UsernameToken is used for authentication. When + * set, the WS-UsernameToken headers are included in each request. + * \since 1.8 + */ + void setUseWSUsernameToken(bool useWSUsernameToken); + /** + * \since 1.8 + * \return whether WS-UsernameToken is used for authentication + */ + bool useWSUsernameToken() const; + + /** + * Sets the created time used during WS-UsernameToken authentication + * This is useful for devices with an incorrect time and during testing + * \since 1.8 + */ + void setOverrideWSUsernameCreatedTime(QDateTime overrideWSUsernameCreatedTime); + /** + * \since 1.8 + * \return the created time used during WS-UsernameToken authentication + */ + QDateTime overrideWSUsernameCreatedTime() const; + + /** + * Sets the nonce used during WS-UsernameToken authentication + * This is useful during testing + * \since 1.8 + */ + void setOverrideWSUsernameNonce(QByteArray overrideWSUsernameNonce); + /** + * \since 1.8 + * \return the created time used during WS-UsernameToken authentication + */ + QByteArray overrideWSUsernameNonce() const; + /** * \return \c true if authentication was defined, or * \c false if this object is only a default-constructed KDSoapAuthentication(). @@ -91,6 +132,10 @@ class KDSOAP_EXPORT KDSoapAuthentication */ void handleAuthenticationRequired(QNetworkReply *reply, QAuthenticator *authenticator); + bool hasWSUsernameTokenHeader() const; + + void writeWSUsernameTokenHeader(KDSoapNamespacePrefixes &namespacePrefixes, QXmlStreamWriter &writer, const QString &messageNamespace, bool forceQualified) const; + private: class Private; Private *const d; diff --git a/src/KDSoapClient/KDSoapClientInterface.cpp b/src/KDSoapClient/KDSoapClientInterface.cpp index 2b8470aab..1c6aff6fc 100644 --- a/src/KDSoapClient/KDSoapClientInterface.cpp +++ b/src/KDSoapClient/KDSoapClientInterface.cpp @@ -147,7 +147,7 @@ QBuffer *KDSoapClientInterfacePrivate::prepareRequestBuffer(const QString &metho KDSoapMessageWriter msgWriter; msgWriter.setMessageNamespace(m_messageNamespace); msgWriter.setVersion(m_version); - const QByteArray data = msgWriter.messageToXml(message, (m_style == KDSoapClientInterface::RPCStyle) ? method : QString(), headers, m_persistentHeaders); + const QByteArray data = msgWriter.messageToXml(message, (m_style == KDSoapClientInterface::RPCStyle) ? method : QString(), headers, m_persistentHeaders, m_authentication); QBuffer *buffer = new QBuffer; buffer->setData(data); buffer->open(QIODevice::ReadOnly); diff --git a/src/KDSoapClient/KDSoapMessageWriter.cpp b/src/KDSoapClient/KDSoapMessageWriter.cpp index 59e210b64..895e78774 100644 --- a/src/KDSoapClient/KDSoapMessageWriter.cpp +++ b/src/KDSoapClient/KDSoapMessageWriter.cpp @@ -44,7 +44,8 @@ void KDSoapMessageWriter::setMessageNamespace(const QString &ns) } QByteArray KDSoapMessageWriter::messageToXml(const KDSoapMessage &message, const QString &method, - const KDSoapHeaders &headers, const QMap &persistentHeaders) const + const KDSoapHeaders &headers, const QMap &persistentHeaders, + const KDSoapAuthentication &authentication) const { QByteArray data; QXmlStreamWriter writer(&data); @@ -73,7 +74,7 @@ QByteArray KDSoapMessageWriter::messageToXml(const KDSoapMessage &message, const messageNamespace = message.namespaceUri(); } - if (!headers.isEmpty() || !persistentHeaders.isEmpty() || message.hasMessageAddressingProperties()) { + if (!headers.isEmpty() || !persistentHeaders.isEmpty() || message.hasMessageAddressingProperties() || authentication.hasWSUsernameTokenHeader()) { // This writeNamespace line adds the xmlns:n1 to , which looks ugly and unusual (and breaks all unittests) // However it's the best solution in case of headers, otherwise we get n1 in the header and n2 in the body, // and xsi:type attributes that refer to n1, which isn't defined in the body... @@ -88,6 +89,9 @@ QByteArray KDSoapMessageWriter::messageToXml(const KDSoapMessage &message, const if (message.hasMessageAddressingProperties()) { message.messageAddressingProperties().writeMessageAddressingProperties(namespacePrefixes, writer, messageNamespace, true); } + if (authentication.hasWSUsernameTokenHeader()) { + authentication.writeWSUsernameTokenHeader(namespacePrefixes, writer, messageNamespace, true); + } writer.writeEndElement(); // Header } else { // So in the standard case (no headers) we just rely on Qt calling it n1 and insert it into the map. diff --git a/src/KDSoapClient/KDSoapMessageWriter_p.h b/src/KDSoapClient/KDSoapMessageWriter_p.h index 6bf921889..37828ce88 100644 --- a/src/KDSoapClient/KDSoapMessageWriter_p.h +++ b/src/KDSoapClient/KDSoapMessageWriter_p.h @@ -24,6 +24,7 @@ #define KDSOAPMESSAGEWRITER_P_H #include "KDSoapMessage.h" +#include "KDSoapAuthentication.h" #include "KDSoapClientInterface.h" #include #include @@ -49,7 +50,8 @@ class KDSOAP_EXPORT KDSoapMessageWriter QByteArray messageToXml(const KDSoapMessage &message, const QString &method /*empty in document style*/, const KDSoapHeaders &headers, - const QMap &persistentHeaders) const; + const QMap &persistentHeaders, + const KDSoapAuthentication &authentication = KDSoapAuthentication()) const; private: QString m_messageNamespace; diff --git a/src/KDSoapClient/KDSoapNamespaceManager.cpp b/src/KDSoapClient/KDSoapNamespaceManager.cpp index 6b8b15594..2986a3587 100644 --- a/src/KDSoapClient/KDSoapNamespaceManager.cpp +++ b/src/KDSoapClient/KDSoapNamespaceManager.cpp @@ -70,3 +70,13 @@ QString KDSoapNamespaceManager::soapMessageAddressing() { return QString::fromLatin1("http://www.w3.org/2005/08/addressing"); } + +QString KDSoapNamespaceManager::soapSecurityExtention() +{ + return QString::fromLatin1("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"); +} + +QString KDSoapNamespaceManager::soapSecurityUtility() +{ + return QString::fromLatin1("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"); +} diff --git a/src/KDSoapClient/KDSoapNamespaceManager.h b/src/KDSoapClient/KDSoapNamespaceManager.h index eb8aca17b..a0817c94f 100644 --- a/src/KDSoapClient/KDSoapNamespaceManager.h +++ b/src/KDSoapClient/KDSoapNamespaceManager.h @@ -41,6 +41,8 @@ class KDSOAP_EXPORT KDSoapNamespaceManager //krazy:exclude=dpointer static QString soapEncoding(); static QString soapEncoding200305(); static QString soapMessageAddressing(); + static QString soapSecurityExtention(); + static QString soapSecurityUtility(); private: // TODO instantiate to handle custom namespaces per clientinterface KDSoapNamespaceManager(); diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt index 584409874..f059a721f 100644 --- a/unittests/CMakeLists.txt +++ b/unittests/CMakeLists.txt @@ -71,6 +71,7 @@ add_subdirectory(encapsecurity) add_subdirectory(prefix_wsdl) add_subdirectory(vidyo) add_subdirectory(ws_addressing_support) +add_subdirectory(ws_usernametoken_support) add_subdirectory(empty_element_wsdl) # These need internet access diff --git a/unittests/unittests.pro b/unittests/unittests.pro index 40c9a6a27..19eb996a7 100644 --- a/unittests/unittests.pro +++ b/unittests/unittests.pro @@ -45,7 +45,8 @@ SUBDIRS = \ date_example \ dv_terminalauth \ test_calc \ - ws_addressing_support + ws_addressing_support \ + ws_usernametoken_support # These need internet access SUBDIRS += webcalls webcalls_wsdl diff --git a/unittests/ws_usernametoken_support/CMakeLists.txt b/unittests/ws_usernametoken_support/CMakeLists.txt new file mode 100644 index 000000000..4eb1ba39c --- /dev/null +++ b/unittests/ws_usernametoken_support/CMakeLists.txt @@ -0,0 +1,8 @@ +project(ws_usernametoken_support) + +set(WSDL_FILES wsusernametoken.wsdl) +set(ws_usernametoken_support_SRCS wsusernametokentest.cpp ) + +set(EXTRA_LIBS ${QT_QTXML_LIBRARY}) + +add_unittest(${ws_usernametoken_support_SRCS} ) diff --git a/unittests/ws_usernametoken_support/ws_usernametoken_support.pro b/unittests/ws_usernametoken_support/ws_usernametoken_support.pro new file mode 100644 index 000000000..480de2c1b --- /dev/null +++ b/unittests/ws_usernametoken_support/ws_usernametoken_support.pro @@ -0,0 +1,9 @@ +include( $${TOP_SOURCE_DIR}/unittests/unittests.pri ) +QT += network xml +SOURCES = wsusernametokentest.cpp +test.target = test +test.commands = ./$(TARGET) +test.depends = $(TARGET) +QMAKE_EXTRA_TARGETS += test + +KDWSDL = wsusernametoken.wsdl diff --git a/unittests/ws_usernametoken_support/wsusernametoken.wsdl b/unittests/ws_usernametoken_support/wsusernametoken.wsdl new file mode 100644 index 000000000..fbb67b5da --- /dev/null +++ b/unittests/ws_usernametoken_support/wsusernametoken.wsdl @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + WSDL File for HelloService + + + + + + http://localhost:8081/hello + + example:Inventory + + + 123456789 + ABCDEFG + + + + + + diff --git a/unittests/ws_usernametoken_support/wsusernametokentest.cpp b/unittests/ws_usernametoken_support/wsusernametokentest.cpp new file mode 100644 index 000000000..a10e3272f --- /dev/null +++ b/unittests/ws_usernametoken_support/wsusernametokentest.cpp @@ -0,0 +1,101 @@ +/**************************************************************************** +** Copyright (C) 2010-2018 Klaralvdalens Datakonsult AB, a KDAB Group company, info@kdab.com. +** Copyright (C) 2019 Casper Meijn +** All rights reserved. +** +** This file is part of the KD Soap library. +** +** Licensees holding valid commercial KD Soap licenses may use this file in +** accordance with the KD Soap Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2.1 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL.txt included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#include "httpserver_p.h" + +#include +#include + +#include "KDSoapNamespaceManager.h" +#include "KDSoapAuthentication.h" +#include "wsdl_wsusernametoken.h" + +using namespace KDSoapUnitTestHelpers; + +class WSUsernameTokenTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + + void shouldWriteAProperSoapMessageWithRightUsernameToken() + { + // GIVEN + HttpServerThread server(emptyResponse(), HttpServerThread::Public); + KDSoapClientInterface client(server.endPoint(), "http://www.ecerami.com/wsdl/HelloService"); + + KDSoapAuthentication auth; + auth.setUser("admin"); + auth.setPassword("userpassword"); + auth.setUseWSUsernameToken(true); + + // Override the nonce and timestamp to make the test output consistent. + auth.setOverrideWSUsernameNonce(QByteArray::fromBase64("LKqI6G/AikKCQrN0zqZFlg==")); + auth.setOverrideWSUsernameCreatedTime(QDateTime(QDate(2010, 9, 16), QTime(7, 50, 45), Qt::UTC));//2010-09-16T07:50:45Z + + client.setAuthentication(auth); + + // make a request + KDSoapMessage message; + const QString action = QString::fromLatin1("sayHello"); + message.setUse(KDSoapMessage::EncodedUse); + message.addArgument(QString::fromLatin1("msg"), QVariant::fromValue(QString("HelloContentMessage")), KDSoapNamespaceManager::xmlSchema2001(), QString::fromLatin1("string")); + message.setNamespaceUri(QString::fromLatin1("http://www.ecerami.com/wsdl/HelloService.wsdl")); + + // WHEN + KDSoapMessage reply = client.call(QLatin1String("sayHello"), message, action); + + // THEN + QVERIFY(xmlBufferCompare(server.receivedData(), expectedSoapMessage())); + } + +private: + static QByteArray expectedSoapMessage() + { + return QByteArray(xmlEnvBegin11()) + + " xmlns:n1=\"http://www.ecerami.com/wsdl/HelloService.wsdl\">" + " " + " " + " " + " LKqI6G/AikKCQrN0zqZFlg== " + " 2010-09-16T07:50:45Z " + " tuOSpGlFlIXsozq4HFNeeGeFLEI= " + " admin " + " " + " " + " " + " " + " HelloContentMessage " + " " + xmlEnvEnd(); + } + + static QByteArray emptyResponse() + { + return QByteArray(xmlEnvBegin11()) + ">"; + } +}; + +QTEST_MAIN(WSUsernameTokenTest) + +#include "wsusernametokentest.moc" From cd831ccb223bd421feb436c78fa7274fe80e02fb Mon Sep 17 00:00:00 2001 From: Ryan van der Bijl Date: Fri, 1 Feb 2019 12:46:26 +0100 Subject: [PATCH 04/19] Fix if a referenced type name has an extra space in it. E.g. allow the type name "xs:string " to work. For when you can't fix the source WSDL. --- kdwsdl2cpp/schema/parser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kdwsdl2cpp/schema/parser.cpp b/kdwsdl2cpp/schema/parser.cpp index 687e03580..adb32d835 100644 --- a/kdwsdl2cpp/schema/parser.cpp +++ b/kdwsdl2cpp/schema/parser.cpp @@ -487,7 +487,7 @@ Element Parser::parseElement(ParserContext *context, newElement.setNillable(stringToBoolean(element.attribute(QLatin1String("nillable")))); if (element.hasAttribute(QLatin1String("type"))) { - QName typeName(element.attribute(QLatin1String("type"))); + QName typeName(element.attribute(QLatin1String("type")).trimmed()); typeName.setNameSpace(context->namespaceManager()->uri(typeName.prefix())); if (debugParsing()) { qDebug() << "typeName=" << typeName.qname() << "namespace=" << context->namespaceManager()->uri(typeName.prefix()); From 65cf2fe9f4fd09e0bf0420b2f9227d08611d667b Mon Sep 17 00:00:00 2001 From: Ryan van der Bijl Date: Fri, 1 Feb 2019 13:04:30 +0100 Subject: [PATCH 05/19] - Add support for setting request headers for KDSoapJob - Rename "KDSoapJob::returnHeaders" to "KDSoapJob::replyHeaders" and actually provide an implementation --- kdwsdl2cpp/src/converter_clientstub.cpp | 1 + src/KDSoapClient/KDSoapClientInterface.cpp | 2 +- src/KDSoapClient/KDSoapClientInterface.h | 2 +- src/KDSoapClient/KDSoapJob.cpp | 16 ++++++++++++++++ src/KDSoapClient/KDSoapJob.h | 14 +++++++++++++- 5 files changed, 32 insertions(+), 3 deletions(-) diff --git a/kdwsdl2cpp/src/converter_clientstub.cpp b/kdwsdl2cpp/src/converter_clientstub.cpp index fb5c6803a..577d35714 100644 --- a/kdwsdl2cpp/src/converter_clientstub.cpp +++ b/kdwsdl2cpp/src/converter_clientstub.cpp @@ -385,6 +385,7 @@ bool Converter::convertClientService() if (hasAction) { callLine += QLatin1String(", action"); } + callLine += QLatin1String(", requestHeaders()"); callLine += QLatin1String(");"); doStartCode += callLine; diff --git a/src/KDSoapClient/KDSoapClientInterface.cpp b/src/KDSoapClient/KDSoapClientInterface.cpp index 2b8470aab..2ede473f1 100644 --- a/src/KDSoapClient/KDSoapClientInterface.cpp +++ b/src/KDSoapClient/KDSoapClientInterface.cpp @@ -58,7 +58,7 @@ void KDSoapClientInterface::setSoapVersion(KDSoapClientInterface::SoapVersion ve d->m_version = static_cast(version); } -KDSoapClientInterface::SoapVersion KDSoapClientInterface::soapVersion() +KDSoapClientInterface::SoapVersion KDSoapClientInterface::soapVersion() const { return static_cast(d->m_version); } diff --git a/src/KDSoapClient/KDSoapClientInterface.h b/src/KDSoapClient/KDSoapClientInterface.h index 3b1039e02..d5c21803b 100644 --- a/src/KDSoapClient/KDSoapClientInterface.h +++ b/src/KDSoapClient/KDSoapClientInterface.h @@ -197,7 +197,7 @@ class KDSOAP_EXPORT KDSoapClientInterface /** * Returns the version of SOAP being used in this instance. */ - KDSoapClientInterface::SoapVersion soapVersion(); + KDSoapClientInterface::SoapVersion soapVersion() const; /** * Returns the end point of the SOAP service. diff --git a/src/KDSoapClient/KDSoapJob.cpp b/src/KDSoapClient/KDSoapJob.cpp index 87eb3b662..0793b4459 100644 --- a/src/KDSoapClient/KDSoapJob.cpp +++ b/src/KDSoapClient/KDSoapJob.cpp @@ -27,6 +27,7 @@ class KDSoapJob::Private { public: + KDSoapHeaders requestHeaders; KDSoapMessage reply; KDSoapHeaders replyHeaders; bool isAutoDelete; @@ -44,6 +45,16 @@ KDSoapJob::~KDSoapJob() delete d; } +KDSoapHeaders KDSoapJob::requestHeaders() const +{ + return d->requestHeaders; +} + +void KDSoapJob::setRequestHeaders(const KDSoapHeaders &headers) +{ + d->requestHeaders = headers; +} + void KDSoapJob::start() { QMetaObject::invokeMethod(this, "doStart", Qt::QueuedConnection); @@ -69,6 +80,11 @@ KDSoapMessage KDSoapJob::reply() const return d->reply; } +KDSoapHeaders KDSoapJob::replyHeaders() const +{ + return d->replyHeaders; +} + bool KDSoapJob::isFault() const { return d->reply.isFault(); diff --git a/src/KDSoapClient/KDSoapJob.h b/src/KDSoapClient/KDSoapJob.h index d3198515f..46fdbe2a4 100644 --- a/src/KDSoapClient/KDSoapJob.h +++ b/src/KDSoapClient/KDSoapJob.h @@ -78,6 +78,18 @@ class KDSOAP_EXPORT KDSoapJob : public QObject */ ~KDSoapJob(); + /** + * Returns the reply headers received from the SOAP server once the request was completed. + * Only valid once the request is completed and finished() was emitted. + */ + KDSoapHeaders requestHeaders() const; + + /** + * Sets request headers to be sent to the SOAP server. These are sent in addition + * to the persistent headers set via the client interface. + */ + void setRequestHeaders(const KDSoapHeaders &headers); + /** * Returns whether the reply message (see reply()) represents a fault. */ @@ -98,7 +110,7 @@ class KDSOAP_EXPORT KDSoapJob : public QObject * Returns the reply headers received from the SOAP server once the request was completed. * Only valid once the request is completed and finished() was emitted. */ - KDSoapHeaders returnHeaders() const; + KDSoapHeaders replyHeaders() const; /** * Starts the job. The job will emit finished() once done. From da6979ce3fb5d60dd346ea318f498f442bcd8822 Mon Sep 17 00:00:00 2001 From: David Faure Date: Fri, 1 Feb 2019 13:22:35 +0100 Subject: [PATCH 06/19] Add changelog entry for last merge --- doc/CHANGES_1_8.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/CHANGES_1_8.txt b/doc/CHANGES_1_8.txt index a39bbdd65..3c5dd7418 100644 --- a/doc/CHANGES_1_8.txt +++ b/doc/CHANGES_1_8.txt @@ -1,6 +1,7 @@ General: ======== * Fix internally-created faults lacking an XML element name (so e.g. toXml() would abort) +* KDSoapMessage::messageAddressingProperties() is now correctly filled in when receiving a message with WS-Addressing in the header Client-side: ============ From 4a76cc0898533d540770b3ea66fbb3c6227c91f8 Mon Sep 17 00:00:00 2001 From: Ryan van der Bijl Date: Fri, 1 Feb 2019 14:10:15 +0100 Subject: [PATCH 07/19] - Add ability to generate both .h and .cpp file in one run of kdwsdl2cpp - Add support for namespace-mapping to control class-name generation (e.g. to generate "FOO__MyClass" instead of "TNS__MyClass") - Add endpoint() and soapVersion() accessors in generated Wsdl Service classes - Fixes to prevent generate of some bad classes --- kdwsdl2cpp/libkode/style.cpp | 3 + kdwsdl2cpp/src/compiler.cpp | 15 ++- kdwsdl2cpp/src/converter_clientstub.cpp | 20 ++++ kdwsdl2cpp/src/converter_complextype.cpp | 4 +- kdwsdl2cpp/src/creator.cpp | 51 +++++----- kdwsdl2cpp/src/creator.h | 18 +++- kdwsdl2cpp/src/main.cpp | 105 +++++++++++++++++++-- kdwsdl2cpp/src/settings.cpp | 37 ++++++-- kdwsdl2cpp/src/settings.h | 19 ++-- src/KDSoapClient/KDSoapClientInterface.cpp | 2 +- src/KDSoapClient/KDSoapClientInterface.h | 2 +- 11 files changed, 223 insertions(+), 53 deletions(-) diff --git a/kdwsdl2cpp/libkode/style.cpp b/kdwsdl2cpp/libkode/style.cpp index e981cbede..42aff14e2 100644 --- a/kdwsdl2cpp/libkode/style.cpp +++ b/kdwsdl2cpp/libkode/style.cpp @@ -83,6 +83,9 @@ QString Style::lowerFirst( const QString &str ) QString Style::makeIdentifier( const QString &str ) { + if ( str.isEmpty() ) + return str; + QString identifier = str; identifier.replace( "-", "_" ); identifier.replace( ".", "_" ); diff --git a/kdwsdl2cpp/src/compiler.cpp b/kdwsdl2cpp/src/compiler.cpp index 1076faa5e..7075b77ec 100644 --- a/kdwsdl2cpp/src/compiler.cpp +++ b/kdwsdl2cpp/src/compiler.cpp @@ -103,7 +103,6 @@ void Compiler::parse(const QDomElement &element) definitions.fixUpDefinitions(/*&context, element*/); - KODE::Code::setDefaultIndentation(4); WSDL wsdl; wsdl.setDefinitions(definitions); @@ -116,7 +115,19 @@ void Compiler::parse(const QDomElement &element) QCoreApplication::exit(4); } else { KWSDL::Creator creator; - creator.create(converter.classes()); + creator.setOutputDirectory(Settings::self()->outputDirectory()); + creator.setSourceFile(Settings::self()->wsdlFileName()); + creator.setHeaderFileName(Settings::self()->headerFileName()); + creator.setImplementationFileName(Settings::self()->implementationFileName()); + + creator.setClasses(converter.classes()); + if (Settings::self()->generateHeader()) { + creator.createHeader(); + } + if (Settings::self()->generateImplementation()) { + creator.createImplementation(); + } + QCoreApplication::exit(0); } } else { diff --git a/kdwsdl2cpp/src/converter_clientstub.cpp b/kdwsdl2cpp/src/converter_clientstub.cpp index fb5c6803a..86acc62b0 100644 --- a/kdwsdl2cpp/src/converter_clientstub.cpp +++ b/kdwsdl2cpp/src/converter_clientstub.cpp @@ -164,6 +164,16 @@ bool Converter::convertClientService() setEndPoint.setDocs(QLatin1String("Overwrite the end point defined in the .wsdl file, with another http/https URL.")); newClass.addFunction(setEndPoint); } + // endPoint() accessor + { + KODE::Function getEndPoint(QLatin1String("endPoint"), QLatin1String("QString")); + getEndPoint.setConst(true); + KODE::Code code; + code += "return d_ptr->m_endPoint;"; + getEndPoint.setBody(code); + getEndPoint.setDocs(QLatin1String("Return the end point that will be used.")); + newClass.addFunction(getEndPoint); + } //setSoapVersion() method { KODE::Function setSoapVersion(QLatin1String("setSoapVersion"), QLatin1String("void")); @@ -175,6 +185,16 @@ bool Converter::convertClientService() "version can be KDSoapClientInterface::SOAP1_1 or KDSoapClientInterface::SOAP1_2")); newClass.addFunction(setSoapVersion); } + //soapVersion() method + { + KODE::Function getSoapVersion(QLatin1String("soapVersion"), QLatin1String("KDSoapClientInterface::SoapVersion")); + getSoapVersion.setConst(true); + KODE::Code code; + code += "return clientInterface()->soapVersion();"; + getSoapVersion.setBody(code); + getSoapVersion.setDocs(QLatin1String("Return the soap version used.n")); + newClass.addFunction(getSoapVersion); + } // lastErrorCode() method { KODE::Function lastError(QLatin1String("lastErrorCode"), QLatin1String("int")); diff --git a/kdwsdl2cpp/src/converter_complextype.cpp b/kdwsdl2cpp/src/converter_complextype.cpp index 97932e911..0ae9727ff 100644 --- a/kdwsdl2cpp/src/converter_complextype.cpp +++ b/kdwsdl2cpp/src/converter_complextype.cpp @@ -192,7 +192,8 @@ void Converter::convertComplexType(const XSD::ComplexType *type) typeName = mTypeMap.localType(attribute.type()); if (typeName.isEmpty()) { - qDebug() << "ERROR: attribute with unknown type:" << attribute.name() << attribute.type() << "in" << typeName; + qWarning() << "ERROR: attribute with unknown type:" << attribute.name() << attribute.type() << "in" << typeName; + continue; } inputTypeName = mTypeMap.localInputType(attribute.type(), QName()); //qDebug() << "Attribute" << attribute.name(); @@ -643,6 +644,7 @@ void Converter::createComplexTypeSerializer(KODE::Class &newClass, const XSD::Co bool first = true; Q_FOREACH (const XSD::Attribute &attribute, attributes) { const QString attrName = attribute.name(); + if (attrName.isEmpty()) { continue; } const QString variableName = QLatin1String("d_ptr->") + KODE::MemberVariable::memberVariableName(attrName); demarshalCode.addBlock(demarshalNameTest(attribute.type(), attrName, &first)); diff --git a/kdwsdl2cpp/src/creator.cpp b/kdwsdl2cpp/src/creator.cpp index 0ea3a1b43..e9b87e154 100644 --- a/kdwsdl2cpp/src/creator.cpp +++ b/kdwsdl2cpp/src/creator.cpp @@ -31,43 +31,44 @@ using namespace KWSDL; Creator::Creator() { -} - -void Creator::create(const KODE::Class::List &classes) -{ - KODE::Printer printer; - printer.setOutputDirectory(Settings::self()->outputDirectory()); + KODE::Code::setDefaultIndentation(4); // Set generated header details. - printer.setCreationWarning(true); - printer.setGenerator(QLatin1String("KDAB's kdwsdl2cpp")); - printer.setSourceFile(Settings::self()->wsdlFileName()); + setCreationWarning(true); + setGenerator(QLatin1String("KDAB's kdwsdl2cpp")); // Qt-like coding style - printer.setLabelsDefineIndent(false); - printer.setIndentLabels(false); + setLabelsDefineIndent(false); + setIndentLabels(false); - //qDebug() << "Create server=" << Settings::self()->generateServerCode() << "impl=" << Settings::self()->generateImplementation(); - KODE::File file; + _file.setLicense(KODE::License::GeneratedNoRestriction); +} - if (Settings::self()->generateImplementation()) { - file.setImplementationFilename(Settings::self()->outputFileName()); - file.setHeaderFilename(Settings::self()->headerFile()); - } else { - file.setHeaderFilename(Settings::self()->outputFileName()); +void Creator::setHeaderFileName(const QString &headerFileName) +{ + _file.setHeaderFilename(headerFileName); } - file.setLicense(KODE::License::GeneratedNoRestriction); +void Creator::setImplementationFileName(const QString &implementationFileName) +{ + _file.setImplementationFilename(implementationFileName); +} +void Creator::setClasses(const KODE::Class::List &list) +{ KODE::Class::List::ConstIterator it; - for (it = classes.constBegin(); it != classes.constEnd(); ++it) { - file.insertClass(*it); + for (it = list.constBegin(); it != list.constEnd(); ++it) { + _file.insertClass(*it); + } } - if (Settings::self()->generateImplementation()) { - printer.printImplementation(file); - } else { - printer.printHeader(file); +void Creator::createHeader() +{ + printHeader(_file); } + +void Creator::createImplementation() +{ + printImplementation(_file); } diff --git a/kdwsdl2cpp/src/creator.h b/kdwsdl2cpp/src/creator.h index ec891997d..b808e484e 100644 --- a/kdwsdl2cpp/src/creator.h +++ b/kdwsdl2cpp/src/creator.h @@ -21,16 +21,30 @@ #define KWSDL_CREATOR_H #include +#include +#include +#include namespace KWSDL { -class Creator +class Creator : private KODE::Printer { public: Creator(); - void create(const KODE::Class::List &list); + using KODE::Printer::setOutputDirectory; + using KODE::Printer::setSourceFile; + + void setHeaderFileName(const QString &headerFileName); + void setImplementationFileName(const QString &implementationFileName); + void setClasses(const KODE::Class::List &list); + + void createHeader(); + void createImplementation(); + +private: + KODE::File _file; }; } diff --git a/kdwsdl2cpp/src/main.cpp b/kdwsdl2cpp/src/main.cpp index 29b15f486..e50e51043 100644 --- a/kdwsdl2cpp/src/main.cpp +++ b/kdwsdl2cpp/src/main.cpp @@ -28,20 +28,32 @@ #include static const char *WSDL2CPP_DESCRIPTION = "KDAB's WSDL to C++ compiler"; -static const char *WSDL2CPP_VERSION_STR = "2.0"; +static const char *WSDL2CPP_VERSION_STR = "2.1"; static void showHelp(const char *appName) { fprintf(stderr, "%s %s\n", WSDL2CPP_DESCRIPTION, WSDL2CPP_VERSION_STR); - fprintf(stderr, "Usage: %s [options] [-impl ] \n\n" + fprintf(stderr, + "Usage:\n" + " Header file: %s [options] -o \n" + " Impl. file: %s [options] -o -impl \n" + " Both files : %s [options] -both \n" + "\n" + "Options:\n" " -h, -help display this help and exit\n" " -v, -version display version\n" " -s, -service name of the service to generate\n" - " -o generate the header file into \n" - " -impl generate the implementation file, and #include \n" + " -o output the generated file into \n" + " -impl generate the implementation(.cpp) file, and #include \n" + " -both generate both the header(.h) and the implementation(.cpp) file\n" " -server generate server-side base class, instead of client service\n" " -exportMacro set the export declaration to use for generated classes\n" " -namespace put all generated classes into the given C++ namespace\n" + " -namespaceMapping \n" + " add the uri=code mapping\n" + " if begins with '@', read from file instead\n" + " one entry per line\n" + " (affects the generated class names)\n" " -optional-element-type \n" " use as the getter return value for optional elements.\n" " can be either raw-pointer or boost-optional\n" @@ -55,7 +67,7 @@ static void showHelp(const char *appName) " use of the import-path option\n" " -help-on-missing When groups or basic types could not be found, display\n" " available types (helps with wrong namespaces)\n" - "\n", appName); + "\n", appName, appName, appName); } int main(int argc, char **argv) @@ -64,12 +76,15 @@ int main(int argc, char **argv) const char *fileName = 0; QFileInfo outputFile; + bool both = false; bool impl = false; bool server = false; + QString baseFile; QString headerFile; QString serviceName; QString exportMacro; QString nameSpace; + Settings::NSMapping nsmapping; // XML mappings from URL to short code Settings::OptionalElementType optionalElementType = Settings::ENone; bool keepUnusedTypes = false; QStringList importPathList; @@ -90,6 +105,15 @@ int main(int argc, char **argv) return 1; } headerFile = QFile::decodeName(argv[arg]); + } else if (opt == QLatin1String("-both")) { + both = true; + ++arg; + if (!argv[arg]) { + showHelp(argv[0]); + return 1; + } + baseFile = QFile::decodeName(argv[arg]); + outputFile.setFile(baseFile); } else if (opt == QLatin1String("-server")) { server = true; } else if (opt == QLatin1String("-v") || opt == QLatin1String("-version")) { @@ -123,6 +147,40 @@ int main(int argc, char **argv) return 1; } nameSpace = argv[arg]; + } else if (opt == QLatin1String("-namespaceMapping")) { + ++arg; + if (!argv[arg]) { + showHelp(argv[0]); + return 1; + } + QString mapping = argv[arg]; + if (mapping.startsWith('@')) { + QString mappingFileName = mapping.mid(1); + QFile file(mappingFileName); + if (!file.open(QIODevice::ReadOnly)) { + fprintf(stderr, "Error reading %s: %s\n", mappingFileName.toLatin1().data(), file.errorString().toLatin1().data()); + showHelp(argv[0]); + return 1; + } + + while(!file.atEnd()) { + QString mapping = file.readLine().trimmed(); + if (mapping.startsWith("#")) { continue; } + + QString uri = mapping.section("=", 0, -2); + QString target = mapping.section("=", -1, -1); + if (!uri.isEmpty() && !target.isEmpty()) { + nsmapping[uri] = target; + //fprintf(stderr, "%s = %s\n", uri.toLatin1().data(), target.toLatin1().data()); + } + } + + } else { + QString uri = mapping.section("=", 0, -2); + QString target = mapping.section("=", -1, -1); + nsmapping[uri] = target; + //fprintf(stderr, "%s = %s\n", uri.toLatin1().data(), target.toLatin1().data()); + } } else if (opt == QLatin1String("-optional-element-type")) { ++arg; if (!argv[arg]) { @@ -163,19 +221,52 @@ int main(int argc, char **argv) return 1; } + // if you're saying "just make the impl-file", you can't + // also say "make both the header and the impl" + if (both && impl) { + showHelp(argv[0]); + return 1; + } + + + if (both) { + Settings::self()->setGenerateHeader(true); + Settings::self()->setGenerateImplementation(true); + Settings::self()->setHeaderFileName(baseFile + ".h"); + Settings::self()->setImplementationFileName(baseFile + ".cpp"); + } + else if (impl) { + Settings::self()->setGenerateHeader(false); + Settings::self()->setGenerateImplementation(true); + Settings::self()->setHeaderFileName(headerFile); + Settings::self()->setImplementationFileName(outputFile.fileName()); + } + else { + Settings::self()->setGenerateHeader(true); + Settings::self()->setGenerateImplementation(false); + Settings::self()->setHeaderFileName(outputFile.fileName()); + Settings::self()->setImplementationFileName("UNUSED"); + } + + Settings::self()->setGenerateServerCode(server); - Settings::self()->setGenerateImplementation(impl, headerFile); - Settings::self()->setOutputFileName(outputFile.fileName()); Settings::self()->setOutputDirectory(outputFile.absolutePath()); Settings::self()->setWsdlFile(fileName); Settings::self()->setWantedService(serviceName); Settings::self()->setExportDeclaration(exportMacro); Settings::self()->setNameSpace(nameSpace); + Settings::self()->setNamespaceMapping(nsmapping); Settings::self()->setOptionalElementType(optionalElementType); Settings::self()->setKeepUnusedTypes(keepUnusedTypes); Settings::self()->setImportPathList(importPathList); Settings::self()->setUseLocalFilesOnly(useLocalFilesOnly); Settings::self()->setHelpOnMissing(helpOnMissing); + + //fprintf(stderr, "Output dir: %s\n", Settings::self()->outputDirectory().toLatin1().data()); + //fprintf(stderr, "HeaderFile: %s\n", Settings::self()->headerFileName().toLatin1().data()); + //fprintf(stderr, "Impl File: %s\n", Settings::self()->implementationFileName().toLatin1().data()); + //fprintf(stderr, "Generate: header? %d implementation? %d\n", Settings::self()->generateHeader(), Settings::self()->generateImplementation()); + KWSDL::Compiler compiler; // so that we have an event loop, for downloads diff --git a/kdwsdl2cpp/src/settings.cpp b/kdwsdl2cpp/src/settings.cpp index a83f3bfbc..c197bc437 100644 --- a/kdwsdl2cpp/src/settings.cpp +++ b/kdwsdl2cpp/src/settings.cpp @@ -39,7 +39,8 @@ Q_GLOBAL_STATIC(SettingsSingleton, s_settings) Settings::Settings() { mOutputDirectory = QDir::current().path(); - mOutputFileName = QString::fromLatin1("kwsdl_generated"); + mHeaderFileName = QString::fromLatin1("kwsdl_generated"); + mImplementationFileName = QString::fromLatin1("kwsdl_generated"); mImpl = false; mServer = false; mKeepUnusedTypes = false; @@ -101,11 +102,17 @@ QString Settings::wsdlFileName() const return strUrl.mid(strUrl.lastIndexOf(QLatin1Char('/')) + 1); } -void Settings::setOutputFileName(const QString &outputFileName) +void Settings::setHeaderFileName(const QString &headerFileName) { - mOutputFileName = outputFileName; + mHeaderFileName = headerFileName; } +void Settings::setImplementationFileName(const QString &implementationFileName) +{ + mImplementationFileName = implementationFileName; +} + +/* QString Settings::outputFileName() const { if (mOutputFileName.isEmpty()) { @@ -115,6 +122,7 @@ QString Settings::outputFileName() const return mOutputFileName; } +*/ void Settings::setOutputDirectory(const QString &outputDirectory) { @@ -160,10 +168,9 @@ Settings::NSMapping Settings::namespaceMapping() const return mNamespaceMapping; } -void Settings::setGenerateImplementation(bool b, const QString &headerFile) +void Settings::setGenerateImplementation(bool b) { mImpl = b; - mHeaderFile = headerFile; } bool Settings::generateImplementation() const @@ -171,11 +178,27 @@ bool Settings::generateImplementation() const return mImpl; } -QString Settings::headerFile() const +void Settings::setGenerateHeader(bool b) +{ + mHeader = b; +} + +bool Settings::generateHeader() const { - return mHeaderFile; + return mHeader; } +QString Settings::headerFileName() const +{ + return mHeaderFileName; +} + +QString Settings::implementationFileName() const +{ + return mImplementationFileName; +} + + void Settings::setWantedService(const QString &service) { mWantedService = service; diff --git a/kdwsdl2cpp/src/settings.h b/kdwsdl2cpp/src/settings.h index 1717e571e..17f6cb04e 100644 --- a/kdwsdl2cpp/src/settings.h +++ b/kdwsdl2cpp/src/settings.h @@ -35,9 +35,16 @@ class Settings static Settings *self(); - void setGenerateImplementation(bool b, const QString &headerFile); + void setImplementationFileName(const QString &implFileName); + void setHeaderFileName(const QString &implFileName); + QString headerFileName() const; + QString implementationFileName() const; + + void setGenerateImplementation(bool b); bool generateImplementation() const; - QString headerFile() const; + + void setGenerateHeader(bool b); + bool generateHeader() const; void setGenerateServerCode(bool b); bool generateServerCode() const; @@ -47,9 +54,6 @@ class Settings QString wsdlBaseUrl() const; QString wsdlFileName() const; - void setOutputFileName(const QString &outputFileName); - QString outputFileName() const; - void setOutputDirectory(const QString &outputDirectory); QString outputDirectory() const; @@ -86,14 +90,15 @@ class Settings Settings(); QUrl mWsdlUrl; - QString mOutputFileName; QString mOutputDirectory; - QString mHeaderFile; + QString mHeaderFileName; + QString mImplementationFileName; QString mWantedService; QString mExportDeclaration; QString mNameSpace; QStringList mImportPathList; NSMapping mNamespaceMapping; + bool mHeader; bool mImpl; bool mServer; OptionalElementType mOptionalElementType; diff --git a/src/KDSoapClient/KDSoapClientInterface.cpp b/src/KDSoapClient/KDSoapClientInterface.cpp index 2b8470aab..2ede473f1 100644 --- a/src/KDSoapClient/KDSoapClientInterface.cpp +++ b/src/KDSoapClient/KDSoapClientInterface.cpp @@ -58,7 +58,7 @@ void KDSoapClientInterface::setSoapVersion(KDSoapClientInterface::SoapVersion ve d->m_version = static_cast(version); } -KDSoapClientInterface::SoapVersion KDSoapClientInterface::soapVersion() +KDSoapClientInterface::SoapVersion KDSoapClientInterface::soapVersion() const { return static_cast(d->m_version); } diff --git a/src/KDSoapClient/KDSoapClientInterface.h b/src/KDSoapClient/KDSoapClientInterface.h index 3b1039e02..d5c21803b 100644 --- a/src/KDSoapClient/KDSoapClientInterface.h +++ b/src/KDSoapClient/KDSoapClientInterface.h @@ -197,7 +197,7 @@ class KDSOAP_EXPORT KDSoapClientInterface /** * Returns the version of SOAP being used in this instance. */ - KDSoapClientInterface::SoapVersion soapVersion(); + KDSoapClientInterface::SoapVersion soapVersion() const; /** * Returns the end point of the SOAP service. From 6f7263587d614e25543b6d450d1e4feffcb4eb91 Mon Sep 17 00:00:00 2001 From: David Faure Date: Fri, 1 Feb 2019 14:22:48 +0100 Subject: [PATCH 08/19] Fix compilation with Qt <= 5.9 --- .../wsaddressingtest.cpp | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/unittests/ws_addressing_support/wsaddressingtest.cpp b/unittests/ws_addressing_support/wsaddressingtest.cpp index 73ca7708c..c5dc9f655 100644 --- a/unittests/ws_addressing_support/wsaddressingtest.cpp +++ b/unittests/ws_addressing_support/wsaddressingtest.cpp @@ -90,26 +90,26 @@ private Q_SLOTS: // THEN QVERIFY(reply.hasMessageAddressingProperties()); KDSoapMessageAddressingProperties map = reply.messageAddressingProperties(); - QCOMPARE(map.action(), "sayHello"); - QCOMPARE(map.destination(), "http://www.ecerami.com/wsdl/HelloService"); - QCOMPARE(map.sourceEndpointAddress(), "http://www.ecerami.com/wsdl/source"); - QCOMPARE(map.faultEndpointAddress(), "http://www.ecerami.com/wsdl/fault"); - QCOMPARE(map.messageID(), "uuid:e197db59-0982-4c9c-9702-4234d204f7f4"); - QCOMPARE(map.replyEndpointAddress(), "http://www.w3.org/2005/08/addressing/anonymous"); - QCOMPARE(map.relationships().at(0).uri, "uuid:http://www.ecerami.com/wsdl/someUniqueString"); - QCOMPARE(map.relationships().at(0).relationshipType, "http://www.w3.org/2005/08/addressing/reply"); - QCOMPARE(map.relationships().at(1).uri, "uuid:http://www.ecerami.com/wsdl/someUniqueStringBis"); - QCOMPARE(map.relationships().at(1).relationshipType, "CustomTypeReply"); - QCOMPARE(map.referenceParameters().at(0).name(), "myReferenceParameter"); - QCOMPARE(map.referenceParameters().at(0).value().toString(), "ReferencParameterContent"); - QCOMPARE(map.referenceParameters().at(1).name(), "myReferenceParameterWithChildren"); + QCOMPARE(map.action(), QString("sayHello")); + QCOMPARE(map.destination(), QString("http://www.ecerami.com/wsdl/HelloService")); + QCOMPARE(map.sourceEndpointAddress(), QString("http://www.ecerami.com/wsdl/source")); + QCOMPARE(map.faultEndpointAddress(), QString("http://www.ecerami.com/wsdl/fault")); + QCOMPARE(map.messageID(), QString("uuid:e197db59-0982-4c9c-9702-4234d204f7f4")); + QCOMPARE(map.replyEndpointAddress(), QString("http://www.w3.org/2005/08/addressing/anonymous")); + QCOMPARE(map.relationships().at(0).uri, QString("uuid:http://www.ecerami.com/wsdl/someUniqueString")); + QCOMPARE(map.relationships().at(0).relationshipType, QString("http://www.w3.org/2005/08/addressing/reply")); + QCOMPARE(map.relationships().at(1).uri, QString("uuid:http://www.ecerami.com/wsdl/someUniqueStringBis")); + QCOMPARE(map.relationships().at(1).relationshipType, QString("CustomTypeReply")); + QCOMPARE(map.referenceParameters().at(0).name(), QString("myReferenceParameter")); + QCOMPARE(map.referenceParameters().at(0).value().toString(), QString("ReferencParameterContent")); + QCOMPARE(map.referenceParameters().at(1).name(), QString("myReferenceParameterWithChildren")); QCOMPARE(map.referenceParameters().at(1).childValues().size(), 2); - QCOMPARE(map.metadata().at(0).name(), "myMetadata"); - QCOMPARE(map.metadata().at(0).value().toString(), "MetadataContent"); - QCOMPARE(map.metadata().at(1).name(), "myMetadataBis"); + QCOMPARE(map.metadata().at(0).name(), QString("myMetadata")); + QCOMPARE(map.metadata().at(0).value().toString(), QString("MetadataContent")); + QCOMPARE(map.metadata().at(1).name(), QString("myMetadataBis")); QCOMPARE(map.metadata().at(1).childValues().size(), 1); - QCOMPARE(map.metadata().at(1).childValues().first().name(), "myMetadataBisChild"); - QCOMPARE(map.metadata().at(1).childValues().first().value().toString(), "MetadataBisChildContent"); + QCOMPARE(map.metadata().at(1).childValues().first().name(), QString("myMetadataBisChild")); + QCOMPARE(map.metadata().at(1).childValues().first().value().toString(), QString("MetadataBisChildContent")); } private: From 48ed0242d66ce996aae1c9f556efc6c06c887d78 Mon Sep 17 00:00:00 2001 From: Ryan van der Bijl Date: Fri, 1 Feb 2019 14:40:41 +0100 Subject: [PATCH 09/19] - Add \since for new functions --- src/KDSoapClient/KDSoapJob.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/KDSoapClient/KDSoapJob.h b/src/KDSoapClient/KDSoapJob.h index 46fdbe2a4..dde6d2d91 100644 --- a/src/KDSoapClient/KDSoapJob.h +++ b/src/KDSoapClient/KDSoapJob.h @@ -87,6 +87,8 @@ class KDSOAP_EXPORT KDSoapJob : public QObject /** * Sets request headers to be sent to the SOAP server. These are sent in addition * to the persistent headers set via the client interface. + * + * \since 1.8 */ void setRequestHeaders(const KDSoapHeaders &headers); @@ -109,6 +111,8 @@ class KDSOAP_EXPORT KDSoapJob : public QObject /** * Returns the reply headers received from the SOAP server once the request was completed. * Only valid once the request is completed and finished() was emitted. + * + * \since 1.8 */ KDSoapHeaders replyHeaders() const; From d4370fc29844dad894da4a39a15fc90c9a010173 Mon Sep 17 00:00:00 2001 From: Ryan van der Bijl Date: Fri, 1 Feb 2019 14:54:08 +0100 Subject: [PATCH 10/19] - Fix for coding style, as requested by David --- kdwsdl2cpp/src/converter_complextype.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kdwsdl2cpp/src/converter_complextype.cpp b/kdwsdl2cpp/src/converter_complextype.cpp index 0ae9727ff..2307a55ee 100644 --- a/kdwsdl2cpp/src/converter_complextype.cpp +++ b/kdwsdl2cpp/src/converter_complextype.cpp @@ -644,7 +644,9 @@ void Converter::createComplexTypeSerializer(KODE::Class &newClass, const XSD::Co bool first = true; Q_FOREACH (const XSD::Attribute &attribute, attributes) { const QString attrName = attribute.name(); - if (attrName.isEmpty()) { continue; } + if (attrName.isEmpty()) { + continue; + } const QString variableName = QLatin1String("d_ptr->") + KODE::MemberVariable::memberVariableName(attrName); demarshalCode.addBlock(demarshalNameTest(attribute.type(), attrName, &first)); From 9c37ab6a5ccb323447629cf5090f110b5190e65d Mon Sep 17 00:00:00 2001 From: Ryan van der Bijl Date: Fri, 1 Feb 2019 15:05:24 +0100 Subject: [PATCH 11/19] - Remove dead code --- kdwsdl2cpp/src/settings.cpp | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/kdwsdl2cpp/src/settings.cpp b/kdwsdl2cpp/src/settings.cpp index c197bc437..dbc01ef52 100644 --- a/kdwsdl2cpp/src/settings.cpp +++ b/kdwsdl2cpp/src/settings.cpp @@ -112,18 +112,6 @@ void Settings::setImplementationFileName(const QString &implementationFileName) mImplementationFileName = implementationFileName; } -/* -QString Settings::outputFileName() const -{ - if (mOutputFileName.isEmpty()) { - QFileInfo fi(wsdlFileName()); - return QLatin1String("wsdl_") + fi.completeBaseName() + QLatin1String(mImpl ? ".cpp" : ".h"); - } - - return mOutputFileName; -} -*/ - void Settings::setOutputDirectory(const QString &outputDirectory) { mOutputDirectory = outputDirectory; From b8622a3a31e57139425c90f1bb2bff4b0c680ee0 Mon Sep 17 00:00:00 2001 From: Ryan van der Bijl Date: Fri, 1 Feb 2019 15:13:19 +0100 Subject: [PATCH 12/19] - Add check that parameters (-o) and (-both) are not specified at the same time - Code style clean-up - Use QFile::decodeName/QFile::encodeName --- kdwsdl2cpp/src/main.cpp | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/kdwsdl2cpp/src/main.cpp b/kdwsdl2cpp/src/main.cpp index e50e51043..0f1055f7c 100644 --- a/kdwsdl2cpp/src/main.cpp +++ b/kdwsdl2cpp/src/main.cpp @@ -78,6 +78,7 @@ int main(int argc, char **argv) QFileInfo outputFile; bool both = false; bool impl = false; + bool outfileGiven = false; bool server = false; QString baseFile; QString headerFile; @@ -125,6 +126,7 @@ int main(int argc, char **argv) showHelp(argv[0]); return 1; } + outfileGiven = true; outputFile.setFile(QFile::decodeName(argv[arg])); } else if (opt == QLatin1String("-s") || opt == QLatin1String("-service")) { ++arg; @@ -155,15 +157,15 @@ int main(int argc, char **argv) } QString mapping = argv[arg]; if (mapping.startsWith('@')) { - QString mappingFileName = mapping.mid(1); + QString mappingFileName = QFile::decodeName(argv[arg] + 1); // +1 to skip the '@' QFile file(mappingFileName); if (!file.open(QIODevice::ReadOnly)) { - fprintf(stderr, "Error reading %s: %s\n", mappingFileName.toLatin1().data(), file.errorString().toLatin1().data()); + fprintf(stderr, "Error reading %s: %s\n", QFile::encodeName(mappingFileName).constData(), qPrintable(file.errorString())); showHelp(argv[0]); return 1; } - while(!file.atEnd()) { + while (!file.atEnd()) { QString mapping = file.readLine().trimmed(); if (mapping.startsWith("#")) { continue; } @@ -171,7 +173,6 @@ int main(int argc, char **argv) QString target = mapping.section("=", -1, -1); if (!uri.isEmpty() && !target.isEmpty()) { nsmapping[uri] = target; - //fprintf(stderr, "%s = %s\n", uri.toLatin1().data(), target.toLatin1().data()); } } @@ -179,7 +180,6 @@ int main(int argc, char **argv) QString uri = mapping.section("=", 0, -2); QString target = mapping.section("=", -1, -1); nsmapping[uri] = target; - //fprintf(stderr, "%s = %s\n", uri.toLatin1().data(), target.toLatin1().data()); } } else if (opt == QLatin1String("-optional-element-type")) { ++arg; @@ -223,7 +223,7 @@ int main(int argc, char **argv) // if you're saying "just make the impl-file", you can't // also say "make both the header and the impl" - if (both && impl) { + if (both && (outfileGiven || impl)) { showHelp(argv[0]); return 1; } @@ -234,14 +234,12 @@ int main(int argc, char **argv) Settings::self()->setGenerateImplementation(true); Settings::self()->setHeaderFileName(baseFile + ".h"); Settings::self()->setImplementationFileName(baseFile + ".cpp"); - } - else if (impl) { + } else if (impl) { Settings::self()->setGenerateHeader(false); Settings::self()->setGenerateImplementation(true); Settings::self()->setHeaderFileName(headerFile); Settings::self()->setImplementationFileName(outputFile.fileName()); - } - else { + } else { Settings::self()->setGenerateHeader(true); Settings::self()->setGenerateImplementation(false); Settings::self()->setHeaderFileName(outputFile.fileName()); @@ -262,11 +260,6 @@ int main(int argc, char **argv) Settings::self()->setUseLocalFilesOnly(useLocalFilesOnly); Settings::self()->setHelpOnMissing(helpOnMissing); - //fprintf(stderr, "Output dir: %s\n", Settings::self()->outputDirectory().toLatin1().data()); - //fprintf(stderr, "HeaderFile: %s\n", Settings::self()->headerFileName().toLatin1().data()); - //fprintf(stderr, "Impl File: %s\n", Settings::self()->implementationFileName().toLatin1().data()); - //fprintf(stderr, "Generate: header? %d implementation? %d\n", Settings::self()->generateHeader(), Settings::self()->generateImplementation()); - KWSDL::Compiler compiler; // so that we have an event loop, for downloads From 409aa8e81fa25646dda0c7572c2068fdc9ab8ab4 Mon Sep 17 00:00:00 2001 From: Ryan van der Bijl Date: Fri, 1 Feb 2019 15:16:11 +0100 Subject: [PATCH 13/19] - Remove "const" change from SoapClientInterface (it is added in a different branch) --- src/KDSoapClient/KDSoapClientInterface.cpp | 2 +- src/KDSoapClient/KDSoapClientInterface.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/KDSoapClient/KDSoapClientInterface.cpp b/src/KDSoapClient/KDSoapClientInterface.cpp index 2ede473f1..2b8470aab 100644 --- a/src/KDSoapClient/KDSoapClientInterface.cpp +++ b/src/KDSoapClient/KDSoapClientInterface.cpp @@ -58,7 +58,7 @@ void KDSoapClientInterface::setSoapVersion(KDSoapClientInterface::SoapVersion ve d->m_version = static_cast(version); } -KDSoapClientInterface::SoapVersion KDSoapClientInterface::soapVersion() const +KDSoapClientInterface::SoapVersion KDSoapClientInterface::soapVersion() { return static_cast(d->m_version); } diff --git a/src/KDSoapClient/KDSoapClientInterface.h b/src/KDSoapClient/KDSoapClientInterface.h index d5c21803b..3b1039e02 100644 --- a/src/KDSoapClient/KDSoapClientInterface.h +++ b/src/KDSoapClient/KDSoapClientInterface.h @@ -197,7 +197,7 @@ class KDSOAP_EXPORT KDSoapClientInterface /** * Returns the version of SOAP being used in this instance. */ - KDSoapClientInterface::SoapVersion soapVersion() const; + KDSoapClientInterface::SoapVersion soapVersion(); /** * Returns the end point of the SOAP service. From 5eeef8628a82055660703c4b9fdb1b352418639b Mon Sep 17 00:00:00 2001 From: Ryan van der Bijl Date: Fri, 1 Feb 2019 15:18:15 +0100 Subject: [PATCH 14/19] - Code style change, as requested by David --- kdwsdl2cpp/src/main.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kdwsdl2cpp/src/main.cpp b/kdwsdl2cpp/src/main.cpp index 0f1055f7c..e5dbb881c 100644 --- a/kdwsdl2cpp/src/main.cpp +++ b/kdwsdl2cpp/src/main.cpp @@ -167,7 +167,9 @@ int main(int argc, char **argv) while (!file.atEnd()) { QString mapping = file.readLine().trimmed(); - if (mapping.startsWith("#")) { continue; } + if (mapping.startsWith('#')) { + continue; + } QString uri = mapping.section("=", 0, -2); QString target = mapping.section("=", -1, -1); From 5106ed0b743e3a91d2adfb7df64ce36861fe0589 Mon Sep 17 00:00:00 2001 From: Ryan van der Bijl Date: Fri, 1 Feb 2019 15:25:56 +0100 Subject: [PATCH 15/19] - Make KODE::Printer a member variable instead of a parent class --- kdwsdl2cpp/src/creator.cpp | 29 +++++++++++++++++++---------- kdwsdl2cpp/src/creator.h | 7 ++++--- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/kdwsdl2cpp/src/creator.cpp b/kdwsdl2cpp/src/creator.cpp index e9b87e154..53f331983 100644 --- a/kdwsdl2cpp/src/creator.cpp +++ b/kdwsdl2cpp/src/creator.cpp @@ -34,21 +34,30 @@ Creator::Creator() KODE::Code::setDefaultIndentation(4); // Set generated header details. - setCreationWarning(true); - setGenerator(QLatin1String("KDAB's kdwsdl2cpp")); + _printer.setCreationWarning(true); + _printer.setGenerator(QLatin1String("KDAB's kdwsdl2cpp")); // Qt-like coding style - setLabelsDefineIndent(false); - setIndentLabels(false); - + _printer.setLabelsDefineIndent(false); + _printer.setIndentLabels(false); _file.setLicense(KODE::License::GeneratedNoRestriction); } +void Creator::setOutputDirectory(const QString &outputDirectory) +{ + _printer.setOutputDirectory(outputDirectory); +} + +void Creator::setSourceFile(const QString &sourceFile) +{ + _printer.setSourceFile(sourceFile); +} + void Creator::setHeaderFileName(const QString &headerFileName) { _file.setHeaderFilename(headerFileName); - } +} void Creator::setImplementationFileName(const QString &implementationFileName) { @@ -61,14 +70,14 @@ void Creator::setClasses(const KODE::Class::List &list) for (it = list.constBegin(); it != list.constEnd(); ++it) { _file.insertClass(*it); } - } +} void Creator::createHeader() { - printHeader(_file); - } + _printer.printHeader(_file); +} void Creator::createImplementation() { - printImplementation(_file); + _printer.printImplementation(_file); } diff --git a/kdwsdl2cpp/src/creator.h b/kdwsdl2cpp/src/creator.h index b808e484e..0f4a41474 100644 --- a/kdwsdl2cpp/src/creator.h +++ b/kdwsdl2cpp/src/creator.h @@ -28,13 +28,13 @@ namespace KWSDL { -class Creator : private KODE::Printer +class Creator { public: Creator(); - using KODE::Printer::setOutputDirectory; - using KODE::Printer::setSourceFile; + void setOutputDirectory(const QString &outputDirectory); + void setSourceFile(const QString &sourceFile); void setHeaderFileName(const QString &headerFileName); void setImplementationFileName(const QString &implementationFileName); @@ -45,6 +45,7 @@ class Creator : private KODE::Printer private: KODE::File _file; + KODE::Printer _printer; }; } From 87e8d82d6ec59fbb3e2579751dcaccde0614d8f4 Mon Sep 17 00:00:00 2001 From: Ryan van der Bijl Date: Fri, 1 Feb 2019 16:17:37 +0100 Subject: [PATCH 16/19] - Make a sanity check into a Q_ASSERT --- kdwsdl2cpp/libkode/style.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/kdwsdl2cpp/libkode/style.cpp b/kdwsdl2cpp/libkode/style.cpp index 42aff14e2..8cddf348b 100644 --- a/kdwsdl2cpp/libkode/style.cpp +++ b/kdwsdl2cpp/libkode/style.cpp @@ -83,8 +83,7 @@ QString Style::lowerFirst( const QString &str ) QString Style::makeIdentifier( const QString &str ) { - if ( str.isEmpty() ) - return str; + Q_ASSERT(!str.isEmpty()); QString identifier = str; identifier.replace( "-", "_" ); From c451cda4cc823713afa68344c2c67983f446c32b Mon Sep 17 00:00:00 2001 From: Ryan van der Bijl Date: Fri, 1 Feb 2019 17:00:08 +0100 Subject: [PATCH 17/19] - Fix memory leak --- src/KDSoapClient/KDSoapClientInterface.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/KDSoapClient/KDSoapClientInterface.cpp b/src/KDSoapClient/KDSoapClientInterface.cpp index 2b8470aab..d87169b43 100644 --- a/src/KDSoapClient/KDSoapClientInterface.cpp +++ b/src/KDSoapClient/KDSoapClientInterface.cpp @@ -192,6 +192,7 @@ void KDSoapClientInterface::callNoReply(const QString &method, const KDSoapMessa QNetworkReply *reply = d->accessManager()->post(request, buffer); d->setupReply(reply); QObject::connect(reply, SIGNAL(finished()), reply, SLOT(deleteLater())); + QObject::connect(reply, SIGNAL(finished()), buffer, SLOT(deleteLater())); } void KDSoapClientInterfacePrivate::_kd_slotAuthenticationRequired(QNetworkReply *reply, QAuthenticator *authenticator) From 6f96602ee119f085379b188d4280ad07730043e5 Mon Sep 17 00:00:00 2001 From: Ryan van der Bijl Date: Fri, 1 Feb 2019 17:01:38 +0100 Subject: [PATCH 18/19] - Update docs --- doc/CHANGES_1_8.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/CHANGES_1_8.txt b/doc/CHANGES_1_8.txt index a39bbdd65..939516e0a 100644 --- a/doc/CHANGES_1_8.txt +++ b/doc/CHANGES_1_8.txt @@ -12,6 +12,7 @@ Client-side: * Fix error code when authentication failed * Autodeletion of jobs is now configurable (github pull #125) * Add error details in faultAsString() - and the generated lastError() - coming from the SOAP 1.2 detail element. +* Fix memory leak in KDSoapClientInterface::callNoReply Server-side: ============ From b280e09b5d5cb15ea9fd735fa53e6da6d6053e49 Mon Sep 17 00:00:00 2001 From: Casper Meijn Date: Sat, 2 Feb 2019 16:55:33 +0100 Subject: [PATCH 19/19] KDSoapAuthentication: Added documentation link and simplified function signature --- src/KDSoapClient/KDSoapAuthentication.cpp | 6 +----- src/KDSoapClient/KDSoapAuthentication.h | 9 ++++++++- src/KDSoapClient/KDSoapMessageWriter.cpp | 2 +- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/KDSoapClient/KDSoapAuthentication.cpp b/src/KDSoapClient/KDSoapAuthentication.cpp index 78542a729..3ad595c60 100644 --- a/src/KDSoapClient/KDSoapAuthentication.cpp +++ b/src/KDSoapClient/KDSoapAuthentication.cpp @@ -139,12 +139,8 @@ bool KDSoapAuthentication::hasWSUsernameTokenHeader() const return hasAuth() && d->useWSUsernameToken; } -void KDSoapAuthentication::writeWSUsernameTokenHeader(KDSoapNamespacePrefixes &namespacePrefixes, QXmlStreamWriter &writer, const QString &messageNamespace, bool forceQualified) const +void KDSoapAuthentication::writeWSUsernameTokenHeader(QXmlStreamWriter &writer) const { - Q_UNUSED(namespacePrefixes); - Q_UNUSED(messageNamespace); - Q_UNUSED(forceQualified); - if (!hasAuth()) { return; } diff --git a/src/KDSoapClient/KDSoapAuthentication.h b/src/KDSoapClient/KDSoapAuthentication.h index 14a097874..0f7c29322 100644 --- a/src/KDSoapClient/KDSoapAuthentication.h +++ b/src/KDSoapClient/KDSoapAuthentication.h @@ -82,6 +82,7 @@ class KDSOAP_EXPORT KDSoapAuthentication /** * Sets whether WS-UsernameToken is used for authentication. When * set, the WS-UsernameToken headers are included in each request. + * See https://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0.pdf * \since 1.8 */ void setUseWSUsernameToken(bool useWSUsernameToken); @@ -132,9 +133,15 @@ class KDSOAP_EXPORT KDSoapAuthentication */ void handleAuthenticationRequired(QNetworkReply *reply, QAuthenticator *authenticator); + /** + * \internal + */ bool hasWSUsernameTokenHeader() const; - void writeWSUsernameTokenHeader(KDSoapNamespacePrefixes &namespacePrefixes, QXmlStreamWriter &writer, const QString &messageNamespace, bool forceQualified) const; + /** + * \internal + */ + void writeWSUsernameTokenHeader(QXmlStreamWriter &writer) const; private: class Private; diff --git a/src/KDSoapClient/KDSoapMessageWriter.cpp b/src/KDSoapClient/KDSoapMessageWriter.cpp index 895e78774..7d66ea0f3 100644 --- a/src/KDSoapClient/KDSoapMessageWriter.cpp +++ b/src/KDSoapClient/KDSoapMessageWriter.cpp @@ -90,7 +90,7 @@ QByteArray KDSoapMessageWriter::messageToXml(const KDSoapMessage &message, const message.messageAddressingProperties().writeMessageAddressingProperties(namespacePrefixes, writer, messageNamespace, true); } if (authentication.hasWSUsernameTokenHeader()) { - authentication.writeWSUsernameTokenHeader(namespacePrefixes, writer, messageNamespace, true); + authentication.writeWSUsernameTokenHeader(writer); } writer.writeEndElement(); // Header } else {