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);
        }
    }
}
Exemple #4
0
    // 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);
}
Exemple #7
0
 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."));
 }
Exemple #8
0
 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()));
 }
Exemple #9
0
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();
    }
}
Exemple #10
0
 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));
}
Exemple #12
0
 // 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());
 }
Exemple #13
0
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>
}
Exemple #15
0
    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);
        }
Exemple #17
0
    // 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());
    }
Exemple #18
0
    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
        }
    }
Exemple #19
0
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()));
    }
Exemple #21
0
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);
 }
Exemple #23
0
    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));
    }