File indexing completed on 2024-05-05 13:11:51
0001 /* 0002 SPDX-FileCopyrightText: 2015 (c) Matthieu Gallien <matthieu_gallien@yahoo.fr> 0003 0004 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0005 */ 0006 0007 #include "upnpdevicesoapserverobject.h" 0008 0009 #include "upnplogging.h" 0010 0011 #include "upnpabstractdevice.h" 0012 #include "upnpabstractservice.h" 0013 #include "upnpbasictypes.h" 0014 #include "upnpeventsubscriber.h" 0015 0016 #include "upnpactiondescription.h" 0017 #include "upnpdevicedescription.h" 0018 #include "upnpservicedescription.h" 0019 0020 #include "KDSoapClient/KDSoapValue.h" 0021 0022 #include <QDateTime> 0023 #include <QList> 0024 #include <QLoggingCategory> 0025 #include <QPair> 0026 #include <QString> 0027 #include <QSysInfo> 0028 #include <QVariant> 0029 0030 class UpnpDeviceSoapServerObjectPrivate 0031 { 0032 public: 0033 explicit UpnpDeviceSoapServerObjectPrivate(QList<UpnpAbstractDevice *> &devices) 0034 : mDevices(devices) 0035 { 0036 } 0037 0038 QList<UpnpAbstractDevice *> &mDevices; 0039 }; 0040 0041 UpnpDeviceSoapServerObject::UpnpDeviceSoapServerObject(QList<UpnpAbstractDevice *> &devices, QObject *parent) 0042 : QObject(parent) 0043 , KDSoapServerObjectInterface() 0044 , d(std::make_unique<UpnpDeviceSoapServerObjectPrivate>(devices)) 0045 { 0046 } 0047 0048 UpnpDeviceSoapServerObject::~UpnpDeviceSoapServerObject() = default; 0049 0050 void UpnpDeviceSoapServerObject::processRequest(const KDSoapMessage &request, KDSoapMessage &response, const QByteArray &soapAction) 0051 { 0052 Q_UNUSED(request) 0053 Q_UNUSED(response) 0054 Q_UNUSED(request) 0055 Q_UNUSED(soapAction) 0056 0057 qCDebug(orgKdeUpnpLibQtUpnp()) << "UpnpDeviceSoapServerObject::processRequest" << request.name(); 0058 } 0059 0060 QIODevice *UpnpDeviceSoapServerObject::processFileRequest(const QString &path, QByteArray &contentType) 0061 { 0062 const QList<QString> &pathParts = path.split(QStringLiteral("/")); 0063 if (pathParts.count() == 3 && pathParts.last() == QStringLiteral("device.xml")) { 0064 const int deviceIndex = pathParts[1].toInt(); 0065 if (deviceIndex >= 0 && deviceIndex < d->mDevices.count()) { 0066 return downloadDeviceXmlDescription(d->mDevices[deviceIndex], contentType).release(); 0067 } 0068 } else if (pathParts.count() == 4 && pathParts.last() == QStringLiteral("service.xml")) { 0069 const int deviceIndex = pathParts[1].toInt(); 0070 const int serviceIndex = pathParts[2].toInt(); 0071 if (deviceIndex >= 0 && deviceIndex < d->mDevices.count()) { 0072 return downloadServiceXmlDescription(d->mDevices[deviceIndex], serviceIndex, contentType).release(); 0073 } 0074 } 0075 0076 return nullptr; 0077 } 0078 0079 void UpnpDeviceSoapServerObject::processRequestWithPath(const KDSoapMessage &request, KDSoapMessage &response, const QByteArray &soapAction, const QString &path) 0080 { 0081 Q_UNUSED(request) 0082 Q_UNUSED(response) 0083 Q_UNUSED(soapAction) 0084 0085 qCDebug(orgKdeUpnpLibQtUpnp()) << "UpnpDeviceSoapServerObject::processRequestWithPath" << path << request.name(); 0086 0087 const QList<QString> &pathParts = path.split(QStringLiteral("/")); 0088 if (pathParts.count() != 4 || pathParts.last() != QStringLiteral("control")) { 0089 response.setFault(true); 0090 return; 0091 } 0092 0093 const int deviceIndex = pathParts[1].toInt(); 0094 const int serviceIndex = pathParts[2].toInt(); 0095 0096 if (deviceIndex < 0 || deviceIndex >= d->mDevices.count()) { 0097 response.setFault(true); 0098 return; 0099 } 0100 UpnpAbstractDevice *currentDevice = d->mDevices[deviceIndex]; 0101 0102 if (serviceIndex < 0 || serviceIndex >= currentDevice->services().count()) { 0103 response.setFault(true); 0104 return; 0105 } 0106 auto currentService = currentDevice->serviceDescriptionByIndex(serviceIndex); 0107 0108 const QList<QByteArray> &soapActionParts = soapAction.split('#'); 0109 if (soapActionParts.size() != 2 || soapActionParts.first() != currentService.serviceType().toLatin1()) { 0110 response.setFault(true); 0111 return; 0112 } 0113 0114 const QByteArray &actionName = soapActionParts.last(); 0115 const QString &actionNameString = QString::fromLatin1(actionName); 0116 0117 response = KDSoapValue(actionNameString + QStringLiteral("Response"), QVariant(), currentService.serviceType()); 0118 0119 const KDSoapValueList &allArguments(request.arguments()); 0120 const UpnpActionDescription ¤tAction = currentService.action(actionNameString); 0121 qCDebug(orgKdeUpnpLibQtUpnp()) << "allArguments" << allArguments << "action arguments" << currentAction.mNumberInArgument; 0122 0123 QVector<QVariant> checkedArguments; 0124 bool argumentError = false; 0125 0126 for (int argumentIndexMessage = 0, actionArgumentIndex = 0; !argumentError;) { 0127 if (actionArgumentIndex >= currentAction.mArguments.size()) { 0128 break; 0129 } 0130 if (currentAction.mArguments[actionArgumentIndex].mDirection == UpnpArgumentDirection::Out) { 0131 ++actionArgumentIndex; 0132 continue; 0133 } 0134 if (argumentIndexMessage < allArguments.size() && argumentIndexMessage < currentAction.mNumberInArgument) { 0135 if (allArguments[argumentIndexMessage].name() == currentAction.mArguments[argumentIndexMessage].mName) { 0136 checkedArguments.push_back(allArguments[argumentIndexMessage].value()); 0137 } else { 0138 qCDebug(orgKdeUpnpLibQtUpnp()) << "invalid argument"; 0139 argumentError = true; 0140 } 0141 } else { 0142 if (argumentIndexMessage == currentAction.mNumberInArgument && argumentIndexMessage == allArguments.size()) { 0143 break; 0144 } 0145 0146 if (argumentIndexMessage < currentAction.mNumberInArgument) { 0147 qCDebug(orgKdeUpnpLibQtUpnp()) << "missing arguments"; 0148 } 0149 argumentError = true; 0150 } 0151 ++argumentIndexMessage; 0152 ++actionArgumentIndex; 0153 } 0154 0155 if (argumentError) { 0156 qCDebug(orgKdeUpnpLibQtUpnp()) << "error about arguments"; 0157 response.setFault(true); 0158 return; 0159 } else { 0160 bool actionCallIsInError = false; 0161 0162 //const QList<QPair<QString, QVariant> > &returnedValues(currentService.invokeAction(actionNameString, checkedArguments, actionCallIsInError)); 0163 0164 if (actionCallIsInError) { 0165 response.setFault(true); 0166 return; 0167 } else { 0168 response.setFault(false); 0169 } 0170 0171 response.setType(currentService.serviceType(), actionNameString + QStringLiteral("Response")); 0172 /*for (const QPair<QString, QVariant> &oneValue : returnedValues) { 0173 response.addArgument(oneValue.first, oneValue.second); 0174 }*/ 0175 } 0176 } 0177 0178 bool UpnpDeviceSoapServerObject::processCustomVerbRequest(const QByteArray &requestType, const QByteArray &requestData, 0179 const QMap<QByteArray, QByteArray> &httpHeaders, QByteArray &customAnswer) 0180 { 0181 if (requestType == "SUBSCRIBE") { 0182 const QString &path = QString::fromLatin1(httpHeaders.value("_path")); 0183 const QList<QString> &pathParts = path.split(QStringLiteral("/")); 0184 if (pathParts.count() == 4 && pathParts.last() == QStringLiteral("event")) { 0185 const int deviceIndex = pathParts[1].toInt(); 0186 const int serviceIndex = pathParts[2].toInt(); 0187 if (deviceIndex >= 0 && deviceIndex < d->mDevices.count()) { 0188 UpnpAbstractDevice *currentDevice = d->mDevices[deviceIndex]; 0189 if (serviceIndex >= 0 && serviceIndex < currentDevice->services().count()) { 0190 //QPointer<UpnpEventSubscriber> newSubscriber = currentDevice->serviceByIndex(serviceIndex)->subscribeToEvents(requestData, httpHeaders); 0191 0192 customAnswer = "HTTP/1.1 200 OK\r\n"; 0193 customAnswer += "DATE: " + QDateTime::currentDateTime().toString(QStringLiteral("ddd, d MMM yyyy HH:mm:ss t")).toLatin1() + "\r\n"; 0194 //customAnswer += "SID: uuid:" + newSubscriber->uuid().toLatin1() + "\r\n"; 0195 customAnswer += "SERVER: " + QSysInfo::kernelType().toLatin1() + " " + QSysInfo::kernelVersion().toLatin1() + " UPnP/1.0 test/1.0\r\n"; 0196 //customAnswer += "TIMEOUT:Second-" + QByteArray::number(newSubscriber->secondTimeout()) + "\r\n"; 0197 customAnswer += "\r\n"; 0198 0199 return true; 0200 } 0201 } 0202 } 0203 } else if (requestType == "UNSUBSCRIBE") { 0204 const QString &path = QString::fromLatin1(httpHeaders.value("_path")); 0205 const QList<QString> &pathParts = path.split(QStringLiteral("/")); 0206 if (pathParts.count() == 4 && pathParts.last() == QStringLiteral("event")) { 0207 const int deviceIndex = pathParts[1].toInt(); 0208 const int serviceIndex = pathParts[2].toInt(); 0209 if (deviceIndex >= 0 && deviceIndex < d->mDevices.count()) { 0210 UpnpAbstractDevice *currentDevice = d->mDevices[deviceIndex]; 0211 if (serviceIndex >= 0 && serviceIndex < currentDevice->services().count()) { 0212 //currentDevice->serviceByIndex(serviceIndex)->unsubscribeToEvents(requestData, httpHeaders); 0213 0214 customAnswer = "HTTP/1.1 200 OK\r\n"; 0215 customAnswer += "DATE: " + QDateTime::currentDateTime().toString(QStringLiteral("ddd, d MMM yyyy HH:mm:ss t")).toLatin1() + "\r\n"; 0216 //customAnswer += "SID: uuid:" + newSubscriber->uuid().toLatin1() + "\r\n"; 0217 customAnswer += "SERVER: " + QSysInfo::kernelType().toLatin1() + " " + QSysInfo::kernelVersion().toLatin1() + " UPnP/1.0 test/1.0\r\n"; 0218 //customAnswer += "TIMEOUT:Second-" + QByteArray::number(newSubscriber->secondTimeout()) + "\r\n"; 0219 customAnswer += "\r\n"; 0220 0221 return true; 0222 } 0223 } 0224 } 0225 } else { 0226 qCDebug(orgKdeUpnpLibQtUpnp()) << "UpnpDeviceSoapServerObject::processCustomVerbRequest" << requestData << httpHeaders; 0227 } 0228 0229 return false; 0230 } 0231 0232 std::unique_ptr<QIODevice> UpnpDeviceSoapServerObject::downloadDeviceXmlDescription(UpnpAbstractDevice *device, QByteArray &contentType) 0233 { 0234 qCDebug(orgKdeUpnpLibQtUpnp()) << "UpnpDeviceSoapServerObject::downloadDeviceXmlDescription" << device->description().UDN(); 0235 0236 contentType = "text/xml"; 0237 0238 return device->buildAndGetXmlDescription(); 0239 } 0240 0241 std::unique_ptr<QIODevice> UpnpDeviceSoapServerObject::downloadServiceXmlDescription(UpnpAbstractDevice *device, const int serviceIndex, QByteArray &contentType) 0242 { 0243 qCDebug(orgKdeUpnpLibQtUpnp()) << "UpnpDeviceSoapServerObject::downloadServiceXmlDescription" << device->description().UDN() << serviceIndex; 0244 0245 contentType = "text/xml"; 0246 0247 return {}/*device->serviceByIndex(serviceIndex)->buildAndGetXmlDescription()*/; 0248 } 0249 0250 #include "moc_upnpdevicesoapserverobject.cpp"