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 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 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)); }
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 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); } }