KD SOAP API Documentation 2.2
Loading...
Searching...
No Matches
KDSoapClientInterface.cpp
Go to the documentation of this file.
1/****************************************************************************
2**
3** This file is part of the KD Soap project.
4**
5** SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
6**
7** SPDX-License-Identifier: MIT
8**
9****************************************************************************/
14#ifndef QT_NO_SSL
16#include "KDSoapSslHandler.h"
17#endif
18#include "KDSoapPendingCall_p.h"
19#include <QAuthenticator>
20#include <QBuffer>
21#include <QDebug>
22#include <QNetworkProxy>
23#include <QNetworkReply>
24#include <QNetworkRequest>
25#include <QSslConfiguration>
26#include <QTimer>
27
28KDSoapClientInterface::KDSoapClientInterface(const QString &endPoint, const QString &messageNamespace)
30{
32 d->m_messageNamespace = messageNamespace;
34}
35
42
47
52
54 : m_accessManager(nullptr)
55 , m_authentication()
56 , m_version(KDSoap::SOAP1_1)
57 , m_style(KDSoapClientInterface::RPCStyle)
58{
59#ifndef QT_NO_SSL
60 m_sslHandler = nullptr;
61#endif
62}
63
65{
66#ifndef QT_NO_SSL
67 delete m_sslHandler;
68#endif
69}
70
72{
73 if (!m_accessManager) {
75 connect(m_accessManager, &QNetworkAccessManager::authenticationRequired, this, &KDSoapClientInterfacePrivate::_kd_slotAuthenticationRequired);
76 }
77 return m_accessManager;
78}
79
81{
82 QNetworkRequest request(QUrl(this->m_endPoint));
83
84#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
85 // HTTP/2 (on by default since Qt 6) creates trouble, disable it for now (https://github.com/KDAB/KDSoap/issues/246)
87#endif
88
89 QString soapAction = action;
90
91 if (soapAction.isNull()) {
92 // The automatic generation of SoapAction done in this block is a mistake going back to KDSoap 1.0.
93 // The spec says "there is no default value for SoapAction" (https://www.w3.org/TR/wsdl#_soap:operation)
94 // but we keep this for compatibility, when nothing was passed as argument (see the webcalls unittest)
95 soapAction = this->m_messageNamespace;
96 if (!soapAction.endsWith(QLatin1Char('/'))) {
97 soapAction += QLatin1Char('/');
98 }
99 soapAction += method;
100 }
101 // qDebug() << "soapAction=" << soapAction;
102
103 QString soapHeader;
104 if (m_version == KDSoap::SOAP1_1) {
105 soapHeader += QString::fromLatin1("text/xml;charset=utf-8");
106 request.setRawHeader("SoapAction", '\"' + soapAction.toUtf8() + '\"');
107 } else if (m_version == KDSoap::SOAP1_2) {
108 soapHeader += QString::fromLatin1("application/soap+xml;charset=utf-8");
110 soapHeader += QString::fromLatin1(";action=") + soapAction;
111 }
112
114
115 // FIXME need to find out which version of Qt this is no longer necessary
116 // without that the server might respond with gzip compressed data and
117 // Qt 4.6.2 fails to decode that properly
118 //
119 // happens with retrieval calls in against SugarCRM 5.5.1 running on Apache 2.2.15
120 // when the response seems to reach a certain size threshold
121 request.setRawHeader("Accept-Encoding", "compress");
122
124 request.setRawHeader(it.key(), it.value());
125 }
126
127#ifndef QT_NO_SSL
128 if (!m_sslConfiguration.isNull()) {
130 }
131#endif
132
133 return request;
134}
135
136QBuffer *KDSoapClientInterfacePrivate::prepareRequestBuffer(const QString &method, const KDSoapMessage &message, const QString &soapAction, const KDSoapHeaders &headers)
137{
138 KDSoapMessageWriter msgWriter;
140 msgWriter.setVersion(m_version);
141 QBuffer *buffer = new QBuffer;
142 auto setBufferData = [&](const KDSoapMessage &msg) {
143 buffer->setData(msgWriter.messageToXml(msg,
145 headers, m_persistentHeaders,
147 };
148
150 KDSoapMessage messageCopy = message;
153 }
156 if (!prop.action().isEmpty())
157 qWarning("Overwriting the action addressing parameter (%s) with the SOAP action (%s)",
158 prop.action().toLocal8Bit().constData(), soapAction.toLocal8Bit().constData());
159 prop.setAction(soapAction);
160 messageCopy.setMessageAddressingProperties(prop);
161 }
162 setBufferData(messageCopy);
163 } else {
164 setBufferData(message);
165 }
166 buffer->open(QIODevice::ReadOnly);
167 return buffer;
168}
169
170KDSoapPendingCall KDSoapClientInterface::asyncCall(const QString &method, const KDSoapMessage &message, const QString &soapAction,
171 const KDSoapHeaders &headers)
172{
173 QBuffer *buffer = d->prepareRequestBuffer(method, message, soapAction, headers);
174 QNetworkRequest request = d->prepareRequest(method, soapAction);
175 QNetworkReply *reply = d->accessManager()->post(request, buffer);
176 d->setupReply(reply);
177 maybeDebugRequest(buffer->data(), reply->request(), reply);
178 KDSoapPendingCall call(reply, buffer);
179 call.d->soapVersion = d->m_version;
180 return call;
181}
182
183KDSoapMessage KDSoapClientInterface::call(const QString &method, const KDSoapMessage &message, const QString &soapAction,
184 const KDSoapHeaders &headers)
185{
186 d->accessManager()->cookieJar(); // create it in the right thread, the secondary thread will use it
187 // Problem is: I don't want a nested event loop here. Too dangerous for GUI programs.
188 // I wanted a socket->waitFor... but we don't have access to the actual socket in QNetworkAccess.
189 // So the only option that remains is a thread and acquiring a semaphore...
190 KDSoapThreadTaskData *task = new KDSoapThreadTaskData(this, method, message, soapAction, headers);
192 d->m_thread.enqueue(task);
193 if (!d->m_thread.isRunning()) {
194 d->m_thread.start();
195 }
196 task->waitForCompletion();
197 KDSoapMessage ret = task->response();
199 delete task;
200 return ret;
201}
202
204 const QString &soapAction, const KDSoapHeaders &headers)
205{
206 QBuffer *buffer = d->prepareRequestBuffer(method, message, soapAction, headers);
207 QNetworkRequest request = d->prepareRequest(method, soapAction);
208 QNetworkReply *reply = d->accessManager()->post(request, buffer);
209 d->setupReply(reply);
210 maybeDebugRequest(buffer->data(), reply->request(), reply);
213}
214
215void KDSoapClientInterfacePrivate::_kd_slotAuthenticationRequired(QNetworkReply *reply, QAuthenticator *authenticator)
216{
217 m_authentication.handleAuthenticationRequired(reply, authenticator);
218}
219
221{
222 d->m_authentication = authentication;
223}
224
226{
227 return d->m_endPoint;
228}
229
231{
232 d->m_endPoint = endPoint;
233}
234
236{
237 d->m_persistentHeaders[name] = header;
238 d->m_persistentHeaders[name].setQualified(true);
239}
240
245
246#ifndef QT_NO_SSL
251#endif
252
253// Workaround for lack of connect-to-lambdas in Qt4
254// The pure Qt5 code could read like
255/*
256 QTimer *timeoutTimer = new QTimer(reply);
257 timeoutTimer->setSingleShot(true);
258 connect(timeoutTimer, &QTimer::timeout, reply, [reply]() { contents_of_the_slot });
259*/
260class TimeoutHandler : public QTimer // this way a single QObject is needed
261{
263public:
264 TimeoutHandler(QNetworkReply *reply)
265 : QTimer(reply)
266 {
267 setSingleShot(true);
268 }
269public Q_SLOTS:
270 void replyTimeout()
271 {
273 Q_ASSERT(reply);
274
275 // contents_of_the_slot:
276 reply->setProperty("kdsoap_reply_timed_out", true); // see KDSoapPendingCall.cpp
277 reply->abort();
278 }
279};
280
282{
283#ifndef QT_NO_SSL
284 if (m_ignoreSslErrors) {
286 } else {
288 if (m_sslHandler) {
289 // create a child object of the reply, which will forward to m_sslHandler.
290 // this is a workaround for the lack of the reply pointer in the signal,
291 // and sender() doesn't work for sync calls (from another thread) (SOAP-79/issue29)
293 }
294 }
295#endif
296 if (m_timeout >= 0) {
297 TimeoutHandler *timeoutHandler = new TimeoutHandler(reply);
298 connect(timeoutHandler, &TimeoutHandler::timeout, timeoutHandler, &TimeoutHandler::replyTimeout);
300 }
301}
302
307
312
317
322
324{
325 QObject *oldParent = jar->parent();
326 d->accessManager()->setCookieJar(jar);
327 jar->setParent(oldParent); // see comment in QNAM::setCookieJar...
328}
329
334
336{
337 return d->accessManager()->proxy();
338}
339
344
346{
347 return d->m_timeout;
348}
349
351{
352 d->m_timeout = msecs;
353}
354
360
365
367{
368 d->m_sendSoapActionInHttpHeader = sendInHttpHeader;
369}
370
375
377{
378 d->m_sendSoapActionInWsAddressingHeader = sendInWsAddressingHeader;
379}
380
381#ifndef QT_NO_OPENSSL
386
391
393{
394 if (!d->m_sslHandler) {
396 }
397 return d->m_sslHandler;
398}
399#endif
400
401#include "KDSoapClientInterface.moc"
402#include "moc_KDSoapClientInterface_p.cpp"
void maybeDebugRequest(const QByteArray &data, const QNetworkRequest &request, QNetworkReply *reply)
QNetworkAccessManager * m_accessManager
KDSoapClientInterface::Style m_style
QMap< QString, KDSoapMessage > m_persistentHeaders
void setupReply(QNetworkReply *reply)
QNetworkRequest prepareRequest(const QString &method, const QString &action)
QNetworkAccessManager * accessManager()
QMap< QByteArray, QByteArray > m_httpHeaders
KDSoapMessageAddressingProperties m_messageAddressingProperties
QBuffer * prepareRequestBuffer(const QString &method, const KDSoapMessage &message, const QString &soapAction, const KDSoapHeaders &headers)
void setMessageAddressingProperties(const KDSoapMessageAddressingProperties &map)
void setSoapVersion(KDSoapClientInterface::SoapVersion version)
void callNoReply(const QString &method, const KDSoapMessage &message, const QString &soapAction=QString(), const KDSoapHeaders &headers=KDSoapHeaders())
void setProxy(const QNetworkProxy &proxy)
QSslConfiguration sslConfiguration() const
KDSoapPendingCall asyncCall(const QString &method, const KDSoapMessage &message, const QString &soapAction=QString(), const KDSoapHeaders &headers=KDSoapHeaders())
KDSoapSslHandler * sslHandler() const
void setRawHTTPHeaders(const QMap< QByteArray, QByteArray > &headers)
QNetworkProxy proxy() const
bool sendSoapActionInHttpHeader() const
sendActionInHTTP_Header
bool sendSoapActionInWsAddressingHeader() const
sendSoapActionInWsAddressingHeader
void setCookieJar(QNetworkCookieJar *jar)
QNetworkCookieJar * cookieJar() const
KDSoapClientInterface(const QString &endPoint, const QString &messageNamespace)
void setSslConfiguration(const QSslConfiguration &config)
KDSoapHeaders lastResponseHeaders() const
@ RPCStyle
the method name is sent as an xml element wrapping the message parameters
void setEndPoint(const QString &endPoint)
KDSoapMessage call(const QString &method, const KDSoapMessage &message, const QString &soapAction=QString(), const KDSoapHeaders &headers=KDSoapHeaders())
void setSendSoapActionInHttpHeader(bool sendInHttpHeader)
setSendSoapActionInHttpHeader
void setSendSoapActionInWsAddressingHeader(bool sendInWsAddressingHeader)
setSendSoapActionInWsAddressingHeader
void setAuthentication(const KDSoapAuthentication &authentication)
void setHeader(const QString &name, const KDSoapMessage &header)
KDSoapClientInterface::SoapVersion soapVersion() const
void enqueue(KDSoapThreadTaskData *taskData)
QByteArray messageToXml(const KDSoapMessage &message, const QString &method, const KDSoapHeaders &headers, const QMap< QString, KDSoapMessage > &persistentHeaders, const KDSoapAuthentication &authentication=KDSoapAuthentication()) const
void setMessageNamespace(const QString &ns)
void setVersion(KDSoap::SoapVersion version)
void setMessageAddressingProperties(const KDSoapMessageAddressingProperties &map)
KDSoapMessageAddressingProperties messageAddressingProperties() const
A class for handling SSL errors during SOAP calls.
KDSoapAuthentication m_authentication
KDSoapMessage response() const
KDSoapHeaders responseHeaders() const
const QByteArray & data() const const
virtual bool open(QIODevice::OpenMode flags) override
void setData(const QByteArray &data)
const char * constData() const const
QMap::const_iterator constBegin() const const
QMap::const_iterator constEnd() const const
void authenticationRequired(QNetworkReply *reply, QAuthenticator *authenticator)
QNetworkCookieJar * cookieJar() const const
QNetworkReply * post(const QNetworkRequest &request, QIODevice *data)
QNetworkProxy proxy() const const
void setCookieJar(QNetworkCookieJar *cookieJar)
void setProxy(const QNetworkProxy &proxy)
virtual void abort()=0
virtual void ignoreSslErrors()
void ignoreSslErrors(const QList< QSslError > &errors)
QNetworkRequest request() const const
void sslErrors(const QList< QSslError > &errors)
void setAttribute(QNetworkRequest::Attribute code, const QVariant &value)
void setHeader(QNetworkRequest::KnownHeaders header, const QVariant &value)
void setRawHeader(const QByteArray &headerName, const QByteArray &headerValue)
void setSslConfiguration(const QSslConfiguration &config)
Q_OBJECTQ_OBJECT
Q_SLOTSQ_SLOTS
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void deleteLater()
QObject * parent() const const
T qobject_cast(QObject *object)
void setParent(QObject *parent)
bool setProperty(const char *name, const QVariant &value)
bool isNull() const const
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const const
QString fromLatin1(const char *str, int size)
bool isEmpty() const const
bool isNull() const const
QByteArray toLocal8Bit() const const
QByteArray toUtf8() const const
bool isRunning() const const
void start(QThread::Priority priority)
bool wait(QDeadlineTimer deadline)
void setSingleShot(bool singleShot)
void timeout()

© Klarälvdalens Datakonsult AB (KDAB)
"The Qt, C++ and OpenGL Experts"
https://www.kdab.com/
https://www.kdab.com/development-resources/qt-tools/kd-soap/
Generated on Sat Apr 20 2024 00:04:25 for KD SOAP API Documentation by doxygen 1.9.8