void KDSoapServerSocket::handleError(KDSoapMessage &replyMsg, const char *errorCode, const QString &error) { qWarning("%s", qPrintable(error)); replyMsg.setFault(true); replyMsg.addArgument(QString::fromLatin1("faultcode"), QString::fromLatin1(errorCode)); replyMsg.addArgument(QString::fromLatin1("faultstring"), error); }
void KDSoapServerObjectInterface::processRequest(const KDSoapMessage &request, KDSoapMessage &response, const QByteArray &soapAction) { const QString method = request.name(); qDebug() << "Slot not found:" << method << "[soapAction =" << soapAction << "]" /* << "in" << metaObject()->className()*/; const KDSoap::SoapVersion soapVersion = KDSoap::SOAP1_1; // TODO version selection on the server side response.createFaultMessage(QString::fromLatin1("Server.MethodNotFound"), QString::fromLatin1("%1 not found").arg(method), soapVersion); }
void KDSoapServerSocket::makeCall(KDSoapServerObjectInterface* serverObjectInterface, const KDSoapMessage &requestMsg, KDSoapMessage& replyMsg, const KDSoapHeaders& requestHeaders, const QByteArray& soapAction, const QString& path) { Q_ASSERT(serverObjectInterface); //const QString method = requestMsg.name(); if (requestMsg.isFault()) { // Can this happen? Getting a fault as a request !? Doesn't make sense... // reply with a fault, but we don't even know what main element name to use // Oh well, just use the incoming fault :-) replyMsg = requestMsg; handleError(replyMsg, "Client.Data", QString::fromLatin1("Request was a fault")); } else { // Call method on m_serverObject serverObjectInterface->setRequestHeaders(requestHeaders, soapAction); KDSoapServer* server = m_owner->server(); if (path != server->path()) { serverObjectInterface->processRequestWithPath(requestMsg, replyMsg, soapAction, path); } else { serverObjectInterface->processRequest(requestMsg, replyMsg, soapAction); } if (serverObjectInterface->hasFault()) { //qDebug() << "Got fault!"; replyMsg.setFault(true); serverObjectInterface->storeFaultAttributes(replyMsg); } } }
// Test parsing of complex replies, like with SugarCRM void testParseComplexReply() { HttpServerThread server(complexTypeResponse(), HttpServerThread::Public); KDSoapClientInterface client(server.endPoint(), countryMessageNamespace()); const KDSoapMessage response = client.call(QLatin1String("getEmployeeCountry"), countryMessage()); QVERIFY(!response.isFault()); QCOMPARE(response.arguments().count(), 1); const KDSoapValueList lst = response.arguments().first().childValues(); QCOMPARE(lst.count(), 3); const KDSoapValue id = lst.first(); QCOMPARE(id.name(), QString::fromLatin1("id")); QCOMPARE(id.value().toString(), QString::fromLatin1("12345")); const KDSoapValue error = lst.at(1); QCOMPARE(error.name(), QString::fromLatin1("error")); const KDSoapValueList errorList = error.childValues(); QCOMPARE(errorList.count(), 3); const KDSoapValue number = errorList.at(0); QCOMPARE(number.name(), QString::fromLatin1("number")); QCOMPARE(number.value().toString(), QString::fromLatin1("0")); const KDSoapValue name = errorList.at(1); QCOMPARE(name.name(), QString::fromLatin1("name")); QCOMPARE(name.value().toString(), QString::fromLatin1("No Error")); const KDSoapValue description = errorList.at(2); QCOMPARE(description.name(), QString::fromLatin1("description")); QCOMPARE(description.value().toString(), QString::fromLatin1("No Error")); const KDSoapValue array = lst.at(2); QCOMPARE(array.name(), QString::fromLatin1("testArray")); //qDebug() << array; // Code from documentation const QString sessionId = response.arguments()[0].value().toString(); Q_UNUSED(sessionId); }
void KDSoapServerObjectInterface::processRequest(const KDSoapMessage &request, KDSoapMessage& response, const QByteArray& soapAction) { const QString method = request.name(); qDebug() << "Slot not found:" << method << "[soapAction =" << soapAction << "]" /* << "in" << metaObject()->className()*/; response.setFault(true); response.addArgument(QString::fromLatin1("faultcode"), QString::fromLatin1("Server.MethodNotFound")); response.addArgument(QString::fromLatin1("faultstring"), QString::fromLatin1("%1 not found").arg(method)); }
void KDSoapServerObjectInterface::processRequestWithPath(const KDSoapMessage &request, KDSoapMessage &response, const QByteArray &soapAction, const QString &path) { Q_UNUSED(soapAction); const QString method = request.name(); qWarning("Invalid path: \"%s\"", qPrintable(path)); //qWarning() << "Invalid path:" << path << "[method =" << method << "; soapAction =" << soapAction << "]" /* << "in" << metaObject()->className()*/; const KDSoap::SoapVersion soapVersion = KDSoap::SOAP1_1; // TODO version selection on the server side response.createFaultMessage(QString::fromLatin1("Client.Data"), QString::fromLatin1("Method %1 not found in path %2").arg(method, path), soapVersion); }
void testInvalidUndefinedEntityXML() { HttpServerThread server(QByteArray(xmlEnvBegin11()) + "><soap:Body>&doesnotexist;</soap:Body>" + xmlEnvEnd() + '\n', HttpServerThread::Public); KDSoapClientInterface client(server.endPoint(), QString::fromLatin1("urn:msg")); KDSoapMessage message; KDSoapMessage ret = client.call(QLatin1String("Method1"), message); QVERIFY(ret.isFault()); QCOMPARE(ret.faultAsString(), QString::fromLatin1( "Fault code 3: XML error: [1:291] Entity 'doesnotexist' not declared.")); }
void testFault() // HTTP error, creates fault on client side { HttpServerThread server(QByteArray(), HttpServerThread::Public | HttpServerThread::Error404); KDSoapClientInterface client(server.endPoint(), QString::fromLatin1("urn:msg")); KDSoapMessage message; KDSoapMessage ret = client.call(QLatin1String("Method1"), message); QVERIFY(ret.isFault()); QCOMPARE(ret.faultAsString(), QString::fromLatin1( "Fault code 203: Error downloading %1 - server replied: Not Found").arg(server.endPoint())); }
void FetchEntryJob::Private::getEntryError(const KDSoapMessage &fault) { if (!q->handleLoginError(fault)) { kWarning() << "Fetch Entry Error:" << fault.faultAsString(); q->setError(SugarJob::SoapError); q->setErrorText(fault.faultAsString()); q->emitResult(); } }
void testInvalidXML() { HttpServerThread server(QByteArray(xmlEnvBegin11()) + "><soap:Body><broken></xml></soap:Body>", HttpServerThread::Public); KDSoapClientInterface client(server.endPoint(), QString::fromLatin1("urn:msg")); KDSoapMessage message; KDSoapMessage ret = client.call(QLatin1String("Method1"), message); QVERIFY(ret.isFault()); QCOMPARE(ret.faultAsString(), QString::fromLatin1( "Fault code 3: XML error: [1:354] Opening and ending tag mismatch.")); }
void KDSoapServerObjectInterface::processRequestWithPath(const KDSoapMessage &request, KDSoapMessage &response, const QByteArray &soapAction, const QString &path) { Q_UNUSED(soapAction); const QString method = request.name(); qWarning("Invalid path: \"%s\"", qPrintable(path)); //qWarning() << "Invalid path:" << path << "[method =" << method << "; soapAction =" << soapAction << "]" /* << "in" << metaObject()->className()*/; response.setFault(true); response.addArgument(QString::fromLatin1("faultcode"), QString::fromLatin1("Client.Data")); response.addArgument(QString::fromLatin1("faultstring"), QString::fromLatin1("Method %1 not found in path %2").arg(method, path)); }
// Test for refused auth, with sync call (i.e. in thread) void testCallRefusedAuth() { HttpServerThread server(countryResponse(), HttpServerThread::BasicAuth); KDSoapClientInterface client(server.endPoint(), countryMessageNamespace()); KDSoapAuthentication auth; auth.setUser(QLatin1String("kdab")); auth.setPassword(QLatin1String("invalid")); client.setAuthentication(auth); KDSoapMessage reply = client.call(QLatin1String("getEmployeeCountry"), countryMessage()); QVERIFY(reply.isFault()); }
void KDSoapServerSocket::sendReply(KDSoapServerObjectInterface* serverObjectInterface, const KDSoapMessage& replyMsg) { const bool isFault = replyMsg.isFault(); QByteArray xmlResponse; if (!replyMsg.isNull()) { KDSoapMessageWriter msgWriter; // Note that the kdsoap client parsing code doesn't care for the name (except if it's fault), even in // Document mode. Other implementations do, though. QString responseName = isFault ? QString::fromLatin1("Fault") : replyMsg.name(); if (responseName.isEmpty()) responseName = m_method; QString responseNamespace = m_messageNamespace; KDSoapHeaders responseHeaders; if (serverObjectInterface) { responseHeaders = serverObjectInterface->responseHeaders(); if (!serverObjectInterface->responseNamespace().isEmpty()) { responseNamespace = serverObjectInterface->responseNamespace(); } } msgWriter.setMessageNamespace(responseNamespace); xmlResponse = msgWriter.messageToXml(replyMsg, responseName, responseHeaders, QMap<QString, KDSoapMessage>()); } const QByteArray response = httpResponseHeaders(isFault, "text/xml", xmlResponse.size()); if (m_doDebug) { qDebug() << "KDSoapServerSocket: writing" << response << xmlResponse; } qint64 written = write(response); Q_ASSERT(written == response.size()); // Please report a bug if you hit this. written = write(xmlResponse); Q_ASSERT(written == xmlResponse.size()); // Please report a bug if you hit this. Q_UNUSED(written); // flush() ? // All done, check if we should log this KDSoapServer* server = m_owner->server(); const KDSoapServer::LogLevel logLevel = server->logLevel(); // we do this here in order to support dynamic settings changes (at the price of a mutex) if (logLevel != KDSoapServer::LogNothing) { if (logLevel == KDSoapServer::LogEveryCall || (logLevel == KDSoapServer::LogFaults && isFault)) { if (isFault) server->log("FAULT " + m_method.toLatin1() + " -- " + replyMsg.faultAsString().toUtf8() + '\n'); else server->log("CALL " + m_method.toLatin1() + '\n'); } } }
void KDSoapServerObjectInterface::storeFaultAttributes(KDSoapMessage& message) const { // SOAP 1.1 <faultcode>, <faultstring>, <faultfactor>, <detail> message.addArgument(QString::fromLatin1("faultcode"), d->m_faultCode); message.addArgument(QString::fromLatin1("faultstring"), d->m_faultString); message.addArgument(QString::fromLatin1("faultactor"), d->m_faultActor); if (d->m_detailValue.isNil() || d->m_detailValue.isNull()) message.addArgument(QString::fromLatin1("detail"), d->m_detail); else { KDSoapValueList detailAsList; detailAsList.append( d->m_detailValue ); message.addArgument(QString::fromLatin1("detail"), detailAsList); } // TODO : Answer SOAP 1.2 <Code> , <Reason> , <Node> , <Role> , <Detail> }
void testDocumentStyle() { HttpServerThread server(countryResponse(), HttpServerThread::Public); KDSoapClientInterface client(server.endPoint(), countryMessageNamespace()); client.setStyle(KDSoapClientInterface::DocumentStyle); QByteArray expectedRequestXml = expectedCountryRequest(); KDSoapMessage message; message = KDSoapValue(QLatin1String("getEmployeeCountry"), QVariant()); KDSoapValueList& args = message.childValues(); args.append(KDSoapValue(QLatin1String("employeeName"), QString::fromUtf8("David Ä Faure"))); { KDSoapMessage ret = client.call(QLatin1String("UNUSED"), message); // Check what we sent QVERIFY(xmlBufferCompare(server.receivedData(), expectedRequestXml)); QVERIFY(!ret.isFault()); QCOMPARE(ret.arguments().child(QLatin1String("employeeCountry")).value().toString(), QString::fromLatin1("France")); } }
QByteArray KDSoapMessageWriter::messageToXml(const KDSoapMessage &message, const QString &method, const KDSoapHeaders &headers, const QMap<QString, KDSoapMessage> &persistentHeaders) const { QByteArray data; QXmlStreamWriter writer(&data); writer.writeStartDocument(); KDSoapNamespacePrefixes namespacePrefixes; namespacePrefixes.writeStandardNamespaces(writer, m_version, message.hasMessageAddressingProperties()); QString soapEnvelope; QString soapEncoding; if (m_version == KDSoapClientInterface::SOAP1_1) { soapEnvelope = KDSoapNamespaceManager::soapEnvelope(); soapEncoding = KDSoapNamespaceManager::soapEncoding(); } else if (m_version == KDSoapClientInterface::SOAP1_2) { soapEnvelope = KDSoapNamespaceManager::soapEnvelope200305(); soapEncoding = KDSoapNamespaceManager::soapEncoding200305(); } writer.writeStartElement(soapEnvelope, QLatin1String("Envelope")); // This has been removed, see http://msdn.microsoft.com/en-us/library/ms995710.aspx for details //writer.writeAttribute(soapEnvelope, QLatin1String("encodingStyle"), soapEncoding); QString messageNamespace = m_messageNamespace; if (!message.namespaceUri().isEmpty() && messageNamespace != message.namespaceUri()) { messageNamespace = message.namespaceUri(); } if (!headers.isEmpty() || !persistentHeaders.isEmpty() || message.hasMessageAddressingProperties()) { // This writeNamespace line adds the xmlns:n1 to <Envelope>, 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... namespacePrefixes.writeNamespace(writer, messageNamespace, QLatin1String("n1") /*make configurable?*/); writer.writeStartElement(soapEnvelope, QLatin1String("Header")); Q_FOREACH (const KDSoapMessage &header, persistentHeaders) { header.writeChildren(namespacePrefixes, writer, header.use(), messageNamespace, true); }
// Using direct call(), check the xml we send, the response parsing. // Then test callNoReply, then various ways to use asyncCall. void testCallNoReply() { HttpServerThread server(countryResponse(), HttpServerThread::Public); // First, make the proper call KDSoapClientInterface client(server.endPoint(), countryMessageNamespace()); KDSoapAuthentication auth; auth.setUser(QLatin1String("kdab")); auth.setPassword(QLatin1String("unused")); client.setAuthentication(auth); // unused... QByteArray expectedRequestXml = expectedCountryRequest(); { KDSoapMessage ret = client.call(QLatin1String("getEmployeeCountry"), countryMessage()); // Check what we sent QVERIFY(xmlBufferCompare(server.receivedData(), expectedRequestXml)); QVERIFY(!ret.isFault()); QCOMPARE(ret.arguments().child(QLatin1String("employeeCountry")).value().toString(), QString::fromLatin1("France")); } // Now make the call again, but async, and don't wait for response. server.resetReceivedBuffers(); //qDebug() << "== now calling callNoReply =="; client.callNoReply(QLatin1String("getEmployeeCountry"), countryMessage()); QTest::qWait(200); QVERIFY(xmlBufferCompare(server.receivedData(), expectedRequestXml)); // What happens if we use asyncCall and discard the result? // The KDSoapPendingCall goes out of scope, and the network request is aborted. // // The whole reason KDSoapPendingCall is a value, is so that people don't forget // to delete it. But of course if they even forget to store it, nothing happens. server.resetReceivedBuffers(); { client.asyncCall(QLatin1String("getEmployeeCountry"), countryMessage()); QTest::qWait(200); } QVERIFY(server.receivedData().isEmpty()); }
void testCorrectHttpHeader() { HttpServerThread server(countryResponse(), HttpServerThread::Public); KDSoapClientInterface client(server.endPoint(), countryMessageNamespace()); KDSoapAuthentication auth; auth.setUser(QLatin1String("kdab")); auth.setPassword(QLatin1String("unused")); client.setAuthentication(auth); // unused... QNetworkCookieJar myJar; QList<QNetworkCookie> myCookies; myCookies.append(QNetworkCookie("biscuits", "are good")); myJar.setCookiesFromUrl(myCookies, QUrl(server.endPoint())); client.setCookieJar(&myJar); QByteArray expectedRequestXml = expectedCountryRequest(); client.setSoapVersion(KDSoapClientInterface::SOAP1_1); { KDSoapMessage ret = client.call(QLatin1String("getEmployeeCountry"), countryMessage()); // Check what we sent QVERIFY(xmlBufferCompare(server.receivedData(), expectedRequestXml)); QVERIFY(!ret.isFault()); QCOMPARE(server.header("Content-Type").constData(), "text/xml;charset=utf-8"); QCOMPARE(server.header("SoapAction").constData(), "\"http://www.kdab.com/xml/MyWsdl/getEmployeeCountry\""); #if QT_VERSION >= 0x040800 QCOMPARE(server.header("Cookie").constData(), "biscuits=are good"); #elif QT_VERSION >= 0x040700 QCOMPARE(server.header("Cookie").constData(), "biscuits=\"are good\""); #endif QCOMPARE(ret.arguments().child(QLatin1String("employeeCountry")).value().toString(), QString::fromLatin1("France")); } client.setSoapVersion(KDSoapClientInterface::SOAP1_2); { KDSoapMessage ret = client.call(QLatin1String("getEmployeeCountry"), countryMessage()); // Check what we sent QByteArray expectedRequestXml12 = expectedRequestXml; expectedRequestXml12.replace("http://schemas.xmlsoap.org/soap/envelope/", "http://www.w3.org/2003/05/soap-envelope"); expectedRequestXml12.replace("http://schemas.xmlsoap.org/soap/encoding/", "http://www.w3.org/2003/05/soap-encoding"); QVERIFY(xmlBufferCompare(server.receivedData(), expectedRequestXml12)); QVERIFY(!ret.isFault()); QCOMPARE(server.header("Content-Type").constData(), "application/soap+xml;charset=utf-8;action=http://www.kdab.com/xml/MyWsdl/getEmployeeCountry"); QCOMPARE(ret.arguments().child(QLatin1String("employeeCountry")).value().toString(), QString::fromLatin1("France")); #if QT_VERSION >= 0x040800 QCOMPARE(server.header("Cookie").constData(), "biscuits=are good"); #elif QT_VERSION >= 0x040700 QCOMPARE(server.header("Cookie").constData(), "biscuits=\"are good\""); #endif } }
int main(int argc, char **argv) { QCoreApplication app(argc, argv); const int year = 2009; const QString endPoint = QLatin1String("http://www.holidaywebservice.com/Holidays/US/Dates/USHolidayDates.asmx"); const QString messageNamespace = QLatin1String("http://www.27seconds.com/Holidays/US/Dates/"); KDSoapClientInterface client(endPoint, messageNamespace); KDSoapMessage message; message.setQualified(true); message.addArgument(QLatin1String("year"), year); qDebug("Looking up the date of Valentine's Day in %i...", year); KDSoapMessage response = client.call(QLatin1String("GetValentinesDay"), message); if (response.isFault()) printf("%s\n", qPrintable(response.faultAsString())); else printf("%s\n", qPrintable(response.arguments()[0].value().toString())); return 0; }
void shouldWriteAProperSoapMessageWithRightsAddressingProperties() { // GIVEN HttpServerThread server(emptyResponse(), HttpServerThread::Public); KDSoapClientInterface client(server.endPoint(), "http://www.ecerami.com/wsdl/HelloService"); KDSoapMessage message; KDSoapMessageAddressingProperties map; // with some message addressing properties map.setAction("sayHello"); map.setDestination("http://www.ecerami.com/wsdl/HelloService"); map.setSourceEndpointAddress("http://www.ecerami.com/wsdl/source"); map.setFaultEndpoint(KDSoapEndpointReference("http://www.ecerami.com/wsdl/fault")); map.setMessageID("uuid:e197db59-0982-4c9c-9702-4234d204f7f4"); map.setReplyEndpointAddress(KDSoapMessageAddressingProperties::predefinedAddressToString(KDSoapMessageAddressingProperties::Anonymous)); // two relationships related to previous message KDSoapMessageRelationship::Relationship relationship("uuid:http://www.ecerami.com/wsdl/someUniqueString"); // no type means implicit Reply KDSoapMessageRelationship::Relationship relationshipBis("uuid:http://www.ecerami.com/wsdl/someUniqueStringBis", "CustomTypeReply"); map.addRelationship(relationship); map.addRelationship(relationshipBis); // some reference parameters... // one with a value KDSoapValue refParam("myReferenceParameter", "ReferencParameterContent"); map.addReferenceParameter(refParam); // an other one, with children KDSoapValue childOne("myReferenceParameterChildOne", "ChildOneContent"); KDSoapValue childTwo("myReferenceParameterChildTwo", "ChildTwoContent"); KDSoapValueList childrenList; childrenList << childOne << childTwo; KDSoapValue refParamWithChildren("myReferenceParameterWithChildren", childrenList); map.addReferenceParameter(refParamWithChildren); // some metadata KDSoapValueList metadataContainer; KDSoapValue metadata("myMetadata", "MetadataContent"); metadataContainer << metadata; KDSoapValue child("myMetadataBisChild", "MetadataBisChildContent"); KDSoapValueList childList; childList << child; KDSoapValue metadataBis("myMetadataBis", childList); map.setMetadata(metadataContainer); map.addMetadata(metadataBis); // and some request content 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 message.setMessageAddressingProperties(map); KDSoapMessage reply = client.call(QLatin1String("sayHello"), message, action); // THEN QVERIFY(xmlBufferCompare(server.receivedData(), expectedSoapMessage())); }
void KDSoapServerSocket::slotReadyRead() { if (!m_socketEnabled) return; //qDebug() << this << QThread::currentThread() << "slotReadyRead!"; QByteArray buf(2048, ' '); qint64 nread = -1; while (nread != 0) { nread = read(buf.data(), buf.size()); if (nread < 0) { qDebug() << "Error reading from server socket:" << errorString(); return; } m_requestBuffer += buf.left(nread); } //qDebug() << "KDSoapServerSocket: request:" << m_requestBuffer; QByteArray receivedHttpHeaders, receivedData; const bool splitOK = splitHeadersAndData(m_requestBuffer, receivedHttpHeaders, receivedData); if (!splitOK) { //qDebug() << "Incomplete SOAP request, wait for more data"; //incomplete request, wait for more data return; } QMap<QByteArray, QByteArray> httpHeaders; httpHeaders = parseHeaders(receivedHttpHeaders); if (m_doDebug) { qDebug() << "headers received:" << receivedHttpHeaders; qDebug() << httpHeaders; qDebug() << "data received:" << receivedData; } const QByteArray contentLength = httpHeaders.value("content-length"); if (receivedData.size() < contentLength.toInt()) return; // incomplete request, wait for more data m_requestBuffer.clear(); const QByteArray requestType = httpHeaders.value("_requestType"); if (requestType != "GET" && requestType != "POST") { qWarning() << "Unknown HTTP request:" << requestType; //handleError(replyMsg, "Client.Data", QString::fromLatin1("Invalid request type '%1', should be GET or POST").arg(QString::fromLatin1(requestType.constData()))); //sendReply(0, replyMsg); const QByteArray methodNotAllowed = "HTTP/1.1 405 Method Not Allowed\r\nAllow: GET POST\r\nContent-Length: 0\r\n\r\n"; write(methodNotAllowed); return; } const QString path = QString::fromLatin1(httpHeaders.value("_path").constData()); KDSoapServerAuthInterface* serverAuthInterface = qobject_cast<KDSoapServerAuthInterface *>(m_serverObject); if (serverAuthInterface) { QByteArray authValue = httpHeaders.value("Authorization"); if (authValue.isEmpty()) authValue = httpHeaders.value("authorization"); // as sent by Qt-4.5 if (!serverAuthInterface->handleHttpAuth(authValue, path)) { // send auth request (Qt supports basic, ntlm and digest) const QByteArray unauthorized = "HTTP/1.1 401 Authorization Required\r\nWWW-Authenticate: Basic realm=\"example\"\r\nContent-Length: 0\r\n\r\n"; write(unauthorized); return; } } KDSoapServer* server = m_owner->server(); KDSoapMessage replyMsg; replyMsg.setUse(server->use()); KDSoapServerObjectInterface* serverObjectInterface = qobject_cast<KDSoapServerObjectInterface *>(m_serverObject); if (!serverObjectInterface) { const QString error = QString::fromLatin1("Server object %1 does not implement KDSoapServerObjectInterface!").arg(QString::fromLatin1(m_serverObject->metaObject()->className())); handleError(replyMsg, "Server.ImplementationError", error); sendReply(0, replyMsg); return; } else { serverObjectInterface->setServerSocket(this); } if (requestType == "GET") { if (path == server->wsdlPathInUrl() && handleWsdlDownload()) { return; } else if (handleFileDownload(serverObjectInterface, path)) { return; } // See http://www.ibm.com/developerworks/xml/library/x-tipgetr/ // We could implement it, but there's no SOAP request, just a query in the URL, // which we'd have to pass to a different virtual than processRequest. handleError(replyMsg, "Client.Data", QString::fromLatin1("Support for GET requests not implemented yet.")); sendReply(0, replyMsg); return; } //parse message KDSoapMessage requestMsg; KDSoapHeaders requestHeaders; KDSoapMessageReader reader; KDSoapMessageReader::XmlError err = reader.xmlToMessage(receivedData, &requestMsg, &m_messageNamespace, &requestHeaders); if (err == KDSoapMessageReader::PrematureEndOfDocumentError) { //qDebug() << "Incomplete SOAP message, wait for more data"; // This should never happen, since we check for content-size above. return; } //TODO handle parse errors? // check soap version and extract soapAction header QByteArray soapAction; const QByteArray contentType = httpHeaders.value("content-type"); if (contentType.startsWith("text/xml")) { // SOAP 1.1 soapAction = httpHeaders.value("soapaction"); // The SOAP standard allows quotation marks around the SoapAction, so we have to get rid of these. if (soapAction.startsWith('\"')) soapAction = soapAction.mid(1, soapAction.length() - 2); } else if (contentType.startsWith("application/soap+xml")) { // SOAP 1.2 // Example: application/soap+xml;charset=utf-8;action=ActionHex const QList<QByteArray> parts = contentType.split(';'); Q_FOREACH(const QByteArray& part, parts) { if (part.startsWith("action=")) { soapAction = part.mid(strlen("action=")); } } } m_method = requestMsg.name(); if (!replyMsg.isFault()) { makeCall(serverObjectInterface, requestMsg, replyMsg, requestHeaders, soapAction, path); } if (serverObjectInterface && m_delayedResponse) { // Delayed response. Disable the socket to make sure we don't handle another call at the same time. setSocketEnabled(false); } else { sendReply(serverObjectInterface, replyMsg); } }
Q_FOREACH (const KDSoapMessage &header, headers) { header.writeChildren(namespacePrefixes, writer, header.use(), messageNamespace, true); }
void testRequestXml() // this tests the serialization of KDSoapValue[List] in KDSoapClientInterface { HttpServerThread server(emptyResponse(), HttpServerThread::Public); KDSoapClientInterface client(server.endPoint(), countryMessageNamespace()); KDSoapMessage message; message.setUse(KDSoapMessage::EncodedUse); // write out types explicitely // Test simpletype element message.addArgument(QString::fromLatin1("testString"), QString::fromUtf8("Hello Klarälvdalens")); // Test simpletype extended to have an attribute KDSoapValue val(QString::fromLatin1("val"), 5, countryMessageNamespace(), QString::fromLatin1("MyVal")); val.childValues().attributes().append(KDSoapValue(QString::fromLatin1("attr"), QString::fromLatin1("attrValue"))); message.arguments().append(val); // Test complextype with child elements and attributes KDSoapValueList valueList; KDSoapValue orderperson(QString::fromLatin1("orderperson"), QString::fromLatin1("someone"), countryMessageNamespace(), QString::fromLatin1("Person")); valueList.append(orderperson); valueList.attributes().append(KDSoapValue(QString::fromLatin1("attr"), QString::fromLatin1("attrValue"))); message.addArgument(QString::fromLatin1("order"), valueList, countryMessageNamespace(), QString::fromLatin1("MyOrder")); // Code from documentation QRect rect(0, 0, 100, 200); KDSoapValueList rectArgument; rectArgument.addArgument(QLatin1String("x"), rect.x()); rectArgument.addArgument(QLatin1String("y"), rect.y()); rectArgument.addArgument(QLatin1String("width"), rect.width()); rectArgument.addArgument(QLatin1String("height"), rect.height()); message.addArgument(QLatin1String("rect"), rectArgument); // NOTE: type information is missing; setQualified() is missing too. const QString XMLSchemaNS = KDSoapNamespaceManager::xmlSchema2001(); // Test array KDSoapValueList arrayContents; arrayContents.setArrayType(XMLSchemaNS, QString::fromLatin1("string")); arrayContents.append(KDSoapValue(QString::fromLatin1("item"), QString::fromLatin1("kdab"), XMLSchemaNS, QString::fromLatin1("string"))); arrayContents.append(KDSoapValue(QString::fromLatin1("item"), QString::fromLatin1("rocks"), XMLSchemaNS, QString::fromLatin1("string"))); message.addArgument(QString::fromLatin1("testArray"), arrayContents, QString::fromLatin1("http://schemas.xmlsoap.org/soap/encoding/"), QString::fromLatin1("Array")); // Add a header KDSoapMessage header1; header1.setUse(KDSoapMessage::EncodedUse); header1.addArgument(QString::fromLatin1("header1"), QString::fromLatin1("headerValue")); KDSoapHeaders headers; headers << header1; client.call(QLatin1String("test"), message, QString::fromLatin1("MySoapAction"), headers); // Check what we sent QByteArray expectedRequestXml = QByteArray(xmlEnvBegin11()) + " xmlns:n1=\"http://www.kdab.com/xml/MyWsdl/\"" "><soap:Header>" "<n1:header1 xsi:type=\"xsd:string\">headerValue</n1:header1>" "</soap:Header>"; const QByteArray expectedRequestBody = QByteArray("<soap:Body>" "<n1:test>" "<testString xsi:type=\"xsd:string\">Hello Klarälvdalens</testString>" "<val xsi:type=\"n1:MyVal\" attr=\"attrValue\">5</val>" "<order xsi:type=\"n1:MyOrder\" attr=\"attrValue\"><orderperson xsi:type=\"n1:Person\">someone</orderperson></order>" "<rect><x xsi:type=\"xsd:int\">0</x><y xsi:type=\"xsd:int\">0</y><width xsi:type=\"xsd:int\">100</width><height xsi:type=\"xsd:int\">200</height></rect>" "<testArray xsi:type=\"soap-enc:Array\" soap-enc:arrayType=\"xsd:string[2]\">" "<item xsi:type=\"xsd:string\">kdab</item>" "<item xsi:type=\"xsd:string\">rocks</item>" "</testArray>" "</n1:test>" "</soap:Body>") + xmlEnvEnd() + '\n'; // added by QXmlStreamWriter::writeEndDocument QVERIFY(xmlBufferCompare(server.receivedData(), expectedRequestXml + expectedRequestBody)); // Now using persistent headers server.resetReceivedBuffers(); client.setHeader(QLatin1String("header1"), header1); client.call(QLatin1String("test"), message, QString::fromLatin1("MySoapAction")); QVERIFY(xmlBufferCompare(server.receivedData(), expectedRequestXml + expectedRequestBody)); // Now remove the persistent header (using setHeader + empty message) server.resetReceivedBuffers(); client.setHeader(QLatin1String("header1"), KDSoapMessage()); client.call(QLatin1String("test"), message, QString::fromLatin1("MySoapAction")); const QByteArray expectedRequestXmlNoHeader = QByteArray(xmlEnvBegin11()) + " xmlns:n1=\"http://www.kdab.com/xml/MyWsdl/\"" "><soap:Header/>"; // the empty element does not matter QVERIFY(xmlBufferCompare(server.receivedData(), expectedRequestXmlNoHeader + expectedRequestBody)); }