KD SOAP API Documentation: KDSoapMessageReader.cpp Source File

| KD SOAP API Documentation 2.2

Loading...
Searching...
No Matches
KDSoapMessageReader.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
11#include "KDDateTime.h"
12#include "KDSoapMessageReader_p.h"
13#include "KDSoapNamespaceManager.h"
14#include "KDSoapNamespacePrefixes_p.h"
15
16#include <QDebug>
17#include <QXmlStreamReader>
18
19#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
20#define QStringView QStringRef
21#endif
22
23 static QStringView namespaceForPrefix(const QXmlStreamNamespaceDeclarations &decls, const QString &prefix)
24{
25 for (const QXmlStreamNamespaceDeclaration &decl : qAsConst(decls)) {
26 if (decl.prefix() == prefix) {
27 return decl.namespaceUri();
28 }
29 }
30 return QStringView();
31}
32
33 static int xmlTypeToMetaType(const QString &xmlType)
34{
35 // Reverse operation from variantToXmlType in KDSoapClientInterface, keep in sync
36 static const struct
37 {
38 const char *xml; // xsd: prefix assumed
39 const int metaTypeId;
40 } s_types[] = {{"string", QVariant::String}, // or QUrl
41 {"base64Binary", QVariant::ByteArray},
42 {"int", QVariant::Int}, // or long, or uint, or longlong
43 {"unsignedInt", QVariant::ULongLong},
44 {"boolean", QVariant::Bool},
45 {"float", QMetaType::Float},
46 {"double", QVariant::Double},
47 {"time", QVariant::Time},
48 {"date", QVariant::Date}};
49 // Speed: could be sorted and then we could use qBinaryFind
50 for (const auto &type : s_types) {
51 if (xmlType == QLatin1String(type.xml)) {
52 return type.metaTypeId;
53 }
54 }
55 if (xmlType == QLatin1String("dateTime")) {
56 return qMetaTypeId<KDDateTime>();
57 }
58 // This will happen with any custom type, don't bother the user
59 // qDebug() << QString::fromLatin1("xmlTypeToMetaType: XML type %1 is not supported in "
60 // "KDSoap, see the documentation").arg(xmlType);
61 return -1;
62}
63
64 static KDSoapValue parseElement(QXmlStreamReader &reader, const QXmlStreamNamespaceDeclarations &envNsDecls)
65{
66 const QXmlStreamNamespaceDeclarations combinedNamespaceDeclarations = envNsDecls + reader.namespaceDeclarations();
67 const QString name = reader.name().toString();
68 KDSoapValue val(name, QVariant());
69 val.setNamespaceUri(reader.namespaceUri().toString());
70 val.setNamespaceDeclarations(reader.namespaceDeclarations());
71 val.setEnvironmentNamespaceDeclarations(combinedNamespaceDeclarations);
72 // qDebug() << "parsing" << name;
73#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
74 QVariant::Type metaTypeId = QVariant::Invalid;
75#else
76 QMetaType::Type metaTypeId = QMetaType::UnknownType;
77#endif
78 const auto invalidType = metaTypeId;
79
80 const QXmlStreamAttributes attributes = reader.attributes();
81 for (const QXmlStreamAttribute &attribute : attributes) {
82 const QStringView name = attribute.name();
83 const QStringView ns = attribute.namespaceUri();
84 const QStringView attrValue = attribute.value();
85 // Parse xsi:type and soap-enc:arrayType
86 // and ignore anything else from the xsi or soap-enc namespaces until someone needs it...
87 if (ns == KDSoapNamespaceManager::xmlSchemaInstance1999() || ns == KDSoapNamespaceManager::xmlSchemaInstance2001()) {
88 if (name == QLatin1String("type")) {
89 // The type can be like xsd:float, resolve that
90 const QString type = attrValue.toString();
91 const int pos = type.indexOf(QLatin1Char(':'));
92 const QString dataType = type.mid(pos + 1);
93 val.setType(namespaceForPrefix(combinedNamespaceDeclarations, type.left(pos)).toString(), dataType);
94 metaTypeId = static_cast<decltype(metaTypeId)>(xmlTypeToMetaType(dataType));
95 }
96 continue;
97 } else if (ns == KDSoapNamespaceManager::soapEncoding() || ns == KDSoapNamespaceManager::soapEncoding200305()
98 || ns == KDSoapNamespaceManager::soapEnvelope() || ns == KDSoapNamespaceManager::soapEnvelope200305()) {
99 continue;
100 }
101 // qDebug() << "Got attribute:" << name << ns << "=" << attrValue;
102 val.childValues().attributes().append(KDSoapValue(name.toString(), attrValue.toString()));
103 }
104 QString text;
105 while (reader.readNext() != QXmlStreamReader::Invalid) {
106 if (reader.isEndElement()) {
107 break;
108 }
109 if (reader.isCharacters()) {
110 text = reader.text().toString();
111 // qDebug() << "text=" << text;
112 } else if (reader.isStartElement()) {
113 const KDSoapValue subVal = parseElement(reader, combinedNamespaceDeclarations); // recurse
114 val.childValues().append(subVal);
115 }
116 }
117
118 if (!text.isEmpty()) {
119 QVariant variant(text);
120 // qDebug() << text << variant << metaTypeId;
121 // With use=encoded, we have type info, we can convert the variant here
122 // Otherwise, for servers, we do it later, once we know the method's parameter types.
123 if (metaTypeId != invalidType) {
124 QVariant copy = variant;
125#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
126 if (!variant.convert(metaTypeId)) {
127#else
128 if (!variant.convert(QMetaType(metaTypeId))) {
129#endif
130 variant = std::move(copy);
131 }
132 }
133 val.setValue(variant);
134 }
135 return val;
136}
137
138KDSoapMessageReader::KDSoapMessageReader()
139{
140}
141
142 static bool isInvalidCharRef(const QByteArray &charRef)
143{
144 bool ok = true;
145 int symbol = charRef.indexOf('x');
146 int end = charRef.indexOf(';');
147
148 if (symbol == -1 || end == -1) {
149 return false;
150 }
151
152 uint val = charRef.mid(symbol + 1, end - symbol - 1).toInt(&ok, 16);
153
154 if (!ok) {
155 return false;
156 }
157
158 if (val != 0x9 && val != 0xa && val != 0xd && (val <= 0x20)) {
159 return true;
160 }
161
162 return false;
163}
164
165 static QByteArray handleNotWellFormedError(const QByteArray &data, qint64 offset)
166{
167 qint64 i = offset - 1; // offset is the char following the failing one
168 QByteArray dataCleanedUp;
169 QByteArray originalSequence;
170
171 while (i >= 0 && data.at(i) != '&') {
172 if (data.at(i) == '<') { // InvalidXML but not invalid characters related
173 return dataCleanedUp;
174 }
175
176 originalSequence.prepend(data.at(i));
177 i--;
178 }
179
180 if (isInvalidCharRef(originalSequence)) {
181 qWarning() << "found an invalid character sequence to remove:" << QLatin1String(originalSequence.prepend('&').constData());
182 dataCleanedUp = data;
183 dataCleanedUp = dataCleanedUp.replace(originalSequence, "?");
184 }
185 return dataCleanedUp;
186}
187
188 KDSoapMessageReader::XmlError KDSoapMessageReader::xmlToMessage(const QByteArray &data, KDSoapMessage *pMsg, QString *pMessageNamespace,
189 KDSoapHeaders *pRequestHeaders, KDSoap::SoapVersion soapVersion) const
190{
191 Q_ASSERT(pMsg);
192 QXmlStreamReader reader(data);
193 if (reader.readNextStartElement()) {
194 if (reader.name() == QLatin1String("Envelope")
195 && (reader.namespaceUri() == KDSoapNamespaceManager::soapEnvelope()
196 || reader.namespaceUri() == KDSoapNamespaceManager::soapEnvelope200305())) {
197 const QXmlStreamNamespaceDeclarations envNsDecls = reader.namespaceDeclarations();
198 if (reader.readNextStartElement()) {
199 if (reader.name() == QLatin1String("Header")
200 && (reader.namespaceUri() == KDSoapNamespaceManager::soapEnvelope()
201 || reader.namespaceUri() == KDSoapNamespaceManager::soapEnvelope200305())) {
202 KDSoapMessageAddressingProperties messageAddressingProperties;
203 while (reader.readNextStartElement()) {
204 if (KDSoapMessageAddressingProperties::isWSAddressingNamespace(reader.namespaceUri().toString())) {
205 KDSoapValue value = parseElement(reader, envNsDecls);
206 messageAddressingProperties.readMessageAddressingProperty(value);
207 } else {
208 KDSoapMessage header;
209 static_cast<KDSoapValue &>(header) = parseElement(reader, envNsDecls);
210 pRequestHeaders->append(header);
211 }
212 }
213 pMsg->setMessageAddressingProperties(messageAddressingProperties);
214 reader.readNextStartElement(); // read <Body>
215 }
216 if (reader.name() == QLatin1String("Body")
217 && (reader.namespaceUri() == KDSoapNamespaceManager::soapEnvelope()
218 || reader.namespaceUri() == KDSoapNamespaceManager::soapEnvelope200305())) {
219 if (reader.readNextStartElement()) {
220 *pMsg = parseElement(reader, envNsDecls);
221 if (pMessageNamespace) {
222 *pMessageNamespace = pMsg->namespaceUri();
223 }
224 if (pMsg->name() == QLatin1String("Fault")
225 && (reader.namespaceUri() == KDSoapNamespaceManager::soapEnvelope()
226 || reader.namespaceUri() == KDSoapNamespaceManager::soapEnvelope200305())) {
227 pMsg->setFault(true);
228 }
229 }
230
231 } else {
232 reader.raiseError(QObject::tr("Invalid SOAP Message, Body expected"));
233 }
234 } else {
235 reader.raiseError(QObject::tr("Invalid SOAP Message, empty Envelope"));
236 }
237 } else {
238 reader.raiseError(QObject::tr("Invalid SOAP Message, Envelope expected"));
239 }
240 }
241 if (reader.hasError()) {
242 if (reader.error() == QXmlStreamReader::NotWellFormedError) {
243 qWarning() << "Handling a Not well Formed Error";
244 QByteArray dataCleanedUp = handleNotWellFormedError(data, reader.characterOffset());
245 if (!dataCleanedUp.isEmpty()) {
246 return xmlToMessage(dataCleanedUp, pMsg, pMessageNamespace, pRequestHeaders, soapVersion);
247 }
248 }
249 QString faultText = QString::fromLatin1("XML error: [%1:%2] %3")
250 .arg(QString::number(reader.lineNumber()), QString::number(reader.columnNumber()), reader.errorString());
251 pMsg->createFaultMessage(QString::number(reader.error()), faultText, soapVersion);
252 return reader.error() == QXmlStreamReader::PrematureEndOfDocumentError ? PrematureEndOfDocumentError : ParseError;
253 }
254
255 return NoError;
256}
KDDateTime.h
namespaceForPrefix
static QStringView namespaceForPrefix(const QXmlStreamNamespaceDeclarations &decls, const QString &prefix)
Definition KDSoapMessageReader.cpp:23
handleNotWellFormedError
static QByteArray handleNotWellFormedError(const QByteArray &data, qint64 offset)
Definition KDSoapMessageReader.cpp:165
parseElement
static KDSoapValue parseElement(QXmlStreamReader &reader, const QXmlStreamNamespaceDeclarations &envNsDecls)
Definition KDSoapMessageReader.cpp:64
xmlTypeToMetaType
static int xmlTypeToMetaType(const QString &xmlType)
Definition KDSoapMessageReader.cpp:33
isInvalidCharRef
static bool isInvalidCharRef(const QByteArray &charRef)
Definition KDSoapMessageReader.cpp:142
KDSoapMessageReader_p.h
KDSoapNamespaceManager.h
KDSoapNamespacePrefixes_p.h
KDSoapHeaders
Definition KDSoapMessage.h:185
KDSoapMessageAddressingProperties
Definition KDSoapMessageAddressingProperties.h:76
KDSoapMessageAddressingProperties::isWSAddressingNamespace
static bool isWSAddressingNamespace(const QString &namespaceUri)
Definition KDSoapMessageAddressingProperties.cpp:247
KDSoapMessageReader::xmlToMessage
XmlError xmlToMessage(const QByteArray &data, KDSoapMessage *pParsedMessage, QString *pMessageNamespace, KDSoapHeaders *pRequestHeaders, KDSoap::SoapVersion soapVersion) const
Definition KDSoapMessageReader.cpp:188
KDSoapMessageReader::KDSoapMessageReader
KDSoapMessageReader()
Definition KDSoapMessageReader.cpp:138
KDSoapMessageReader::XmlError
XmlError
Definition KDSoapMessageReader_p.h:21
KDSoapMessageReader::NoError
@ NoError
Definition KDSoapMessageReader_p.h:22
KDSoapMessageReader::PrematureEndOfDocumentError
@ PrematureEndOfDocumentError
Definition KDSoapMessageReader_p.h:24
KDSoapMessageReader::ParseError
@ ParseError
Definition KDSoapMessageReader_p.h:23
KDSoapMessage
Definition KDSoapMessage.h:29
KDSoapMessage::setMessageAddressingProperties
void setMessageAddressingProperties(const KDSoapMessageAddressingProperties &map)
Definition KDSoapMessage.cpp:179
KDSoapMessage::createFaultMessage
void createFaultMessage(const QString &faultCode, const QString &faultText, KDSoap::SoapVersion soapVersion)
Definition KDSoapMessage.cpp:154
KDSoapMessage::setFault
void setFault(bool fault)
Definition KDSoapMessage.cpp:149
KDSoapNamespaceManager::soapEncoding
static QString soapEncoding()
Definition KDSoapNamespaceManager.cpp:46
KDSoapNamespaceManager::soapEnvelope
static QString soapEnvelope()
Definition KDSoapNamespaceManager.cpp:36
KDSoapNamespaceManager::xmlSchemaInstance1999
static QString xmlSchemaInstance1999()
Definition KDSoapNamespaceManager.cpp:26
KDSoapNamespaceManager::xmlSchemaInstance2001
static QString xmlSchemaInstance2001()
Definition KDSoapNamespaceManager.cpp:31
KDSoapNamespaceManager::soapEnvelope200305
static QString soapEnvelope200305()
Definition KDSoapNamespaceManager.cpp:41
KDSoapNamespaceManager::soapEncoding200305
static QString soapEncoding200305()
Definition KDSoapNamespaceManager.cpp:51
KDSoapValueList::attributes
QList< KDSoapValue > & attributes()
Definition KDSoapValue.h:375
KDSoapValue
Definition KDSoapValue.h:60
KDSoapValue::childValues
KDSoapValueList & childValues() const
Definition KDSoapValue.cpp:149
KDSoapValue::setNamespaceUri
void setNamespaceUri(const QString &ns)
Definition KDSoapValue.cpp:462
KDSoapValue::namespaceUri
QString namespaceUri() const
Definition KDSoapValue.cpp:457
KDSoapValue::setType
void setType(const QString &nameSpace, const QString &type)
Definition KDSoapValue.cpp:394
KDSoapValue::setNamespaceDeclarations
void setNamespaceDeclarations(const QXmlStreamNamespaceDeclarations &namespaceDeclarations)
Definition KDSoapValue.cpp:124
KDSoapValue::name
QString name() const
Definition KDSoapValue.cpp:94
KDSoapValue::setValue
void setValue(const QVariant &value)
Definition KDSoapValue.cpp:109
KDSoapValue::setEnvironmentNamespaceDeclarations
void setEnvironmentNamespaceDeclarations(const QXmlStreamNamespaceDeclarations &environmentNamespaceDeclarations)
Definition KDSoapValue.cpp:139
KDSoap::SoapVersion
SoapVersion
Definition KDSoapValue.h:40
QByteArray
QByteArray::at
char at(int i) const const
QByteArray::constData
const char * constData() const const
QByteArray::indexOf
int indexOf(char ch, int from) const const
QByteArray::isEmpty
bool isEmpty() const const
QByteArray::mid
QByteArray mid(int pos, int len) const const
QByteArray::prepend
QByteArray & prepend(char ch)
QByteArray::replace
QByteArray & replace(int pos, int len, const char *after)
QByteArray::toInt
int toInt(bool *ok, int base) const const
QLatin1Char
QLatin1String
QList::append
void append(const T &value)
QMetaType
QMetaType::Float
Float
QObject::tr
QString tr(const char *sourceText, const char *disambiguation, int n)
QString
QString::arg
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
QString::fromLatin1
QString fromLatin1(const char *str, int size)
QString::indexOf
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const const
QString::isEmpty
bool isEmpty() const const
QString::left
QString left(int n) const const
QString::mid
QString mid(int position, int n) const const
QString::number
QString number(int n, int base)
QStringRef::toString
QString toString() const const
QStringView
QStringView::toString
QString toString() const const
QVariant::String
String
QVariant
QVariant::convert
bool convert(int targetTypeId)
QXmlStreamAttribute
QXmlStreamAttributes
QXmlStreamNamespaceDeclaration
QXmlStreamReader
QXmlStreamReader::NotWellFormedError
NotWellFormedError
QXmlStreamReader::Invalid
Invalid
QXmlStreamReader::attributes
QXmlStreamAttributes attributes() const const
QXmlStreamReader::characterOffset
qint64 characterOffset() const const
QXmlStreamReader::columnNumber
qint64 columnNumber() const const
QXmlStreamReader::error
QXmlStreamReader::Error error() const const
QXmlStreamReader::errorString
QString errorString() const const
QXmlStreamReader::hasError
bool hasError() const const
QXmlStreamReader::isCharacters
bool isCharacters() const const
QXmlStreamReader::isEndElement
bool isEndElement() const const
QXmlStreamReader::isStartElement
bool isStartElement() const const
QXmlStreamReader::lineNumber
qint64 lineNumber() const const
QXmlStreamReader::name
QStringRef name() const const
QXmlStreamReader::namespaceDeclarations
QXmlStreamNamespaceDeclarations namespaceDeclarations() const const
QXmlStreamReader::namespaceUri
QStringRef namespaceUri() const const
QXmlStreamReader::raiseError
void raiseError(const QString &message)
QXmlStreamReader::readNext
QXmlStreamReader::TokenType readNext()
QXmlStreamReader::readNextStartElement
bool readNextStartElement()
QXmlStreamReader::text
QStringRef text() const 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 on Sun Jan 7 2024 11:47:36 for KD SOAP API Documentation by doxygen 1.9.8