KD SOAP API Documentation  2.2
KDSoapPendingCall.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 ****************************************************************************/
10 #include "KDSoapPendingCall.h"
11 #include "KDSoapMessageReader_p.h"
12 #include "KDSoapNamespaceManager.h"
13 #include "KDSoapPendingCall_p.h"
14 #include <QDebug>
15 #include <QNetworkReply>
16 
17 static void debugHelper(const QByteArray &data, const QList<QNetworkReply::RawHeaderPair> &headerList)
18 {
19  const QByteArray doDebug = qgetenv("KDSOAP_DEBUG");
20  const QList<QByteArray> options = doDebug.toLower().split(',');
21  const bool optEscape = options.contains("escape");
22  const bool optHttp = options.contains("http") || options.contains("https");
23  const bool optReformat = options.contains("reformat");
24  quint8 indentation = 4;
25  for (const QByteArray &opt : qAsConst(options)) {
26  if (opt.startsWith("indent=")) { // krazy:exclude=strings
27  indentation = opt.mid(7).toUShort();
28  }
29  }
30 
31  QByteArray toOutput;
32  if (optHttp) {
33  for (const QNetworkReply::RawHeaderPair &header : qAsConst(headerList)) {
34  if (!header.first.isEmpty()) {
35  toOutput += header.first + ": ";
36  }
37  toOutput += header.second + "\n";
38  }
39  toOutput += "\n";
40  }
41 
42  if (optReformat) {
43  QByteArray reformatted;
44  QXmlStreamReader reader(data);
45  QXmlStreamWriter writer(&reformatted);
46  writer.setAutoFormatting(true);
47  writer.setAutoFormattingIndent(indentation);
48 
49  while (!reader.atEnd()) {
50  reader.readNext();
51  if (!reader.hasError() && !reader.isWhitespace()) {
52  writer.writeCurrentToken(reader);
53  }
54  }
55 
56  toOutput += reader.hasError() ? data : reformatted;
57  } else {
58  toOutput += data;
59  }
60 
61  if (optEscape) {
62  qDebug() << toOutput;
63  } else {
64  qDebug().noquote() << toOutput;
65  }
66 }
67 
68 // Log the HTTP and XML of a response from the server.
69 static void maybeDebugResponse(const QByteArray &data, QNetworkReply *reply)
70 {
71  const QByteArray doDebug = qgetenv("KDSOAP_DEBUG");
72  if (doDebug.trimmed().isEmpty() || doDebug == "0") {
73  return;
74  }
75 
76  debugHelper(data, reply->rawHeaderPairs());
77 }
78 
79 // Log the HTTP and XML of a request.
80 // (not static, because this is used in KDSoapClientInterface)
81 void maybeDebugRequest(const QByteArray &data, const QNetworkRequest &request, QNetworkReply *reply)
82 {
83  const QByteArray doDebug = qgetenv("KDSOAP_DEBUG");
84  if (doDebug.trimmed().isEmpty() || doDebug == "0") {
85  return;
86  }
87 
88  QList<QNetworkReply::RawHeaderPair> headerList;
89  if (reply) {
90  QByteArray method;
91  switch (reply->operation()) {
92  default:
93  break; // don't try to mimic the basic HTTP command
94  case QNetworkAccessManager::GetOperation:
95  method = "GET";
96  break;
97  case QNetworkAccessManager::HeadOperation:
98  method = "HEAD";
99  break;
100  case QNetworkAccessManager::PutOperation:
101  method = "PUT";
102  break;
103  case QNetworkAccessManager::PostOperation:
104  method = "POST";
105  break;
106  case QNetworkAccessManager::DeleteOperation:
107  method = "DELETE";
108  break;
109  }
110  if (!method.isEmpty()) {
111  QByteArray output = method + " " + reply->url().toString().toUtf8();
112  headerList << QNetworkReply::RawHeaderPair {{}, std::move(output)};
113  }
114  }
115  const auto rawHeaders = request.rawHeaderList();
116  for (const QByteArray &h : rawHeaders) {
117  headerList << QNetworkReply::RawHeaderPair {h, request.rawHeader(h)};
118  }
119  debugHelper(data, headerList);
120 }
121 
123 {
124  if (reply) {
125  // Ensure the connection is closed, which QNetworkReply doesn't do in its destructor. This needs abort().
126  QObject::disconnect(reply.data(), &QNetworkReply::finished, nullptr, nullptr);
127  reply->abort();
128  }
129  delete reply.data();
130  delete buffer;
131 }
132 
133 KDSoapPendingCall::KDSoapPendingCall(QNetworkReply *reply, QBuffer *buffer)
134  : d(new Private(reply, buffer))
135 {
136 }
137 
139  : d(other.d)
140 {
141 }
142 
144 {
145 }
146 
148 {
149  d = other.d;
150  return *this;
151 }
152 
154 {
155  return d->reply.data()->isFinished();
156 }
157 
159 {
160  d->parseReply();
161  return d->replyMessage;
162 }
163 
165 {
166  d->parseReply();
167  return d->replyHeaders;
168 }
169 
171 {
172  d->parseReply();
173  if (!d->replyMessage.childValues().isEmpty()) {
174  return d->replyMessage.childValues().first().value();
175  }
176  return QVariant();
177 }
178 
180 {
181  if (parsed) {
182  return;
183  }
184  QNetworkReply *reply = this->reply.data();
185  if (!reply->isFinished()) {
186  qWarning("KDSoap: Parsing reply before it finished!");
187  return;
188  }
189  parsed = true;
190 
191  // Don't try to read from an aborted (closed) reply
192  const QByteArray data = reply->isOpen() ? reply->readAll() : QByteArray();
193  maybeDebugResponse(data, reply);
194 
195  if (!data.isEmpty()) {
196  KDSoapMessageReader reader;
197  reader.xmlToMessage(data, &replyMessage, nullptr, &replyHeaders, this->soapVersion);
198  }
199 
200  if (reply->error()) {
201  if (!replyMessage.isFault()) {
202  replyHeaders.clear();
203  if (reply->error() == QNetworkReply::OperationCanceledError
204  && reply->property("kdsoap_reply_timed_out").toBool()) { // see KDSoapClientInterface.cpp
205  replyMessage.createFaultMessage(QString::number(QNetworkReply::TimeoutError), QLatin1String("Operation timed out"), soapVersion);
206  } else {
207  replyMessage.createFaultMessage(QString::number(reply->error()), reply->errorString(), soapVersion);
208  }
209  }
210  }
211 }
static void debugHelper(const QByteArray &data, const QList< QNetworkReply::RawHeaderPair > &headerList)
void maybeDebugRequest(const QByteArray &data, const QNetworkRequest &request, QNetworkReply *reply)
static void maybeDebugResponse(const QByteArray &data, QNetworkReply *reply)
XmlError xmlToMessage(const QByteArray &data, KDSoapMessage *pParsedMessage, QString *pMessageNamespace, KDSoapHeaders *pRequestHeaders, KDSoap::SoapVersion soapVersion) const
void createFaultMessage(const QString &faultCode, const QString &faultText, KDSoap::SoapVersion soapVersion)
bool isFault() const
QPointer< QNetworkReply > reply
KDSoap::SoapVersion soapVersion
KDSoapPendingCall(const KDSoapPendingCall &other)
KDSoapHeaders returnHeaders() const
QVariant returnValue() const
KDSoapPendingCall & operator=(const KDSoapPendingCall &other)
KDSoapMessage returnMessage() const

© 2010-2024 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 by doxygen 1.9.1