//! A simple loop for synchronizing controls with the list of string values //! contained in a Job object. This routine takes advantage of the Update //! functions that are bind'ed in the initializeControl functions. These Updates //! allow a QControl widget to have its value changed based on a string, //! irrespective of its type. void InputDialog::setControls(Job* job) { typedef QMap<QString, QString> QStringMap; QStringMap::iterator iter; QStringMap opts(job->getOptions()); for (iter = opts.begin(); iter != opts.end(); ++iter) { if (m_setUpdates.count(iter.key())) { m_setUpdates[iter.key()]->operator()(iter.value()); }else { qDebug() << "Warning: Update not initialised for" << iter.key() << "in InputDialog::setControls"; } } }
QDomDocument SOAPClient::SendSOAPRequest(const QString &sMethod, QStringMap &list, int &nErrCode, QString &sErrDesc) { QUrl url(m_url); url.setPath(m_sControlPath); nErrCode = UPnPResult_Success; sErrDesc = ""; QDomDocument xmlResult; if (m_sNamespace.isEmpty()) { nErrCode = UPnPResult_MythTV_NoNamespaceGiven; sErrDesc = "No namespace given"; return xmlResult; } // -------------------------------------------------------------- // Add appropriate headers // -------------------------------------------------------------- QHash<QByteArray, QByteArray> headers; headers.insert("Content-Type", "text/xml; charset=\"utf-8\""); QString soapHeader = QString("\"%1#%2\"").arg(m_sNamespace).arg(sMethod); headers.insert("SOAPACTION", soapHeader.toUtf8()); headers.insert("User-Agent", "Mozilla/9.876 (X11; U; Linux 2.2.12-20 i686, en) " "Gecko/25250101 Netscape/5.432b1"); // -------------------------------------------------------------- // Build request payload // -------------------------------------------------------------- QByteArray aBuffer; QTextStream os( &aBuffer ); os.setCodec("UTF-8"); os << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n"; os << "<s:Envelope " " s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"" " xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">\r\n"; os << " <s:Body>\r\n"; os << " <u:" << sMethod << " xmlns:u=\"" << m_sNamespace << "\">\r\n"; // -------------------------------------------------------------- // Add parameters from list // -------------------------------------------------------------- for (QStringMap::iterator it = list.begin(); it != list.end(); ++it) { os << " <" << it.key() << ">"; os << HTTPRequest::Encode( *it ); os << "</" << it.key() << ">\r\n"; } os << " </u:" << sMethod << ">\r\n"; os << " </s:Body>\r\n"; os << "</s:Envelope>\r\n"; os.flush(); // -------------------------------------------------------------- // Perform Request // -------------------------------------------------------------- LOG(VB_UPNP, LOG_DEBUG, QString("SOAPClient(%1) sending:\n %2").arg(url.toString()).arg(aBuffer.constData())); QString sXml; if (!GetMythDownloadManager()->postAuth(url.toString(), &aBuffer, NULL, NULL, &headers)) { LOG(VB_GENERAL, LOG_ERR, QString("SOAPClient::SendSOAPRequest: request failed: %1") .arg(url.toString())); } else sXml = QString(aBuffer); // -------------------------------------------------------------- // Parse response // -------------------------------------------------------------- LOG(VB_UPNP, LOG_DEBUG, "SOAPClient response:\n" + QString("%1\n").arg(sXml)); // TODO handle timeout without response correctly. list.clear(); QDomDocument doc; if (!doc.setContent(sXml, true, &sErrDesc, &nErrCode)) { LOG(VB_UPNP, LOG_ERR, QString("SendSOAPRequest( %1 ) - Invalid response from %2") .arg(sMethod).arg(url.toString()) + QString("%1: %2").arg(nErrCode).arg(sErrDesc)); return xmlResult; } // -------------------------------------------------------------- // Is this a valid response? // -------------------------------------------------------------- QString sResponseName = sMethod + "Response"; QDomNodeList oNodeList = doc.elementsByTagNameNS(m_sNamespace, sResponseName); if (oNodeList.count() == 0) { // -------------------------------------------------------------- // Must be a fault... parse it to return reason // -------------------------------------------------------------- nErrCode = GetNodeValue( doc, "Envelope/Body/Fault/detail/UPnPError/errorCode", 500); sErrDesc = GetNodeValue( doc, "Envelope/Body/Fault/detail/UPnPError/errorDescription", ""); if (sErrDesc.isEmpty()) sErrDesc = QString("Unknown #%1").arg(nErrCode); QDomNode oNode = FindNode( "Envelope/Body/Fault", doc ); oNode = xmlResult.importNode( oNode, true ); xmlResult.appendChild( oNode ); return xmlResult; } QDomNode oMethod = oNodeList.item(0); if (oMethod.isNull()) return xmlResult; QDomNode oNode = oMethod.firstChild(); for (; !oNode.isNull(); oNode = oNode.nextSibling()) { QDomElement e = oNode.toElement(); if (e.isNull()) continue; QString sName = e.tagName(); QString sValue = ""; QDomText oText = oNode.firstChild().toText(); if (!oText.isNull()) sValue = oText.nodeValue(); list.insert(QUrl::fromPercentEncoding(sName.toUtf8()), QUrl::fromPercentEncoding(sValue.toUtf8())); } // Create copy of oMethod that can be used with xmlResult. oMethod = xmlResult.importNode( oMethod.firstChild(), true ); // importNode does not attach the new nodes to the document, // do it here. xmlResult.appendChild( oMethod ); return xmlResult; }
void HttpWorker::run(void) { #if 0 LOG(VB_UPNP, LOG_DEBUG, QString("HttpWorker::run() socket=%1 -- begin").arg(m_socket)); #endif bool bTimeout = false; bool bKeepAlive = true; BufferedSocketDevice *pSocket = NULL; HTTPRequest *pRequest = NULL; try { if ((pSocket = new BufferedSocketDevice( m_socket )) == NULL) { LOG(VB_GENERAL, LOG_ERR, "Error Creating BufferedSocketDevice"); return; } pSocket->SocketDevice()->setBlocking( true ); while (m_httpServer.IsRunning() && bKeepAlive && pSocket->IsValid()) { bTimeout = false; int64_t nBytes = pSocket->WaitForMore(m_socketTimeout, &bTimeout); if (!m_httpServer.IsRunning()) break; if ( nBytes > 0) { // ---------------------------------------------------------- // See if this is a valid request // ---------------------------------------------------------- pRequest = new BufferedSocketDeviceRequest( pSocket ); if (pRequest != NULL) { if ( pRequest->ParseRequest() ) { bKeepAlive = pRequest->GetKeepAlive(); // ------------------------------------------------------ // Request Parsed... Pass on to Main HttpServer class to // delegate processing to HttpServerExtensions. // ------------------------------------------------------ if (pRequest->m_nResponseStatus != 401) m_httpServer.DelegateRequest(pRequest); } else { LOG(VB_UPNP, LOG_ERR, "ParseRequest Failed."); pRequest->m_nResponseStatus = 501; bKeepAlive = false; } #if 0 // Dump Request Header if (!bKeepAlive ) { for ( QStringMap::iterator it = pRequest->m_mapHeaders.begin(); it != pRequest->m_mapHeaders.end(); ++it ) { LOG(VB_GENERAL, LOG_DEBUG, QString("%1: %2") .arg(it.key()) .arg(it.data())); } } #endif // ------------------------------------------------------- // Always MUST send a response. // ------------------------------------------------------- if (pRequest->SendResponse() < 0) { bKeepAlive = false; LOG(VB_UPNP, LOG_ERR, QString("socket(%1) - Error returned from " "SendResponse... Closing connection") .arg(m_socket)); } // ------------------------------------------------------- // Check to see if a PostProcess was registered // ------------------------------------------------------- if ( pRequest->m_pPostProcess != NULL ) pRequest->m_pPostProcess->ExecutePostProcess(); delete pRequest; pRequest = NULL; } else { LOG(VB_GENERAL, LOG_ERR, "Error Creating BufferedSocketDeviceRequest"); bKeepAlive = false; } } else { bKeepAlive = false; } } } catch(...) { LOG(VB_GENERAL, LOG_ERR, "HttpWorkerThread::ProcessWork - Unexpected Exception."); } if (pRequest != NULL) delete pRequest; pSocket->Close(); delete pSocket; m_socket = 0; #if 0 LOG(VB_UPNP, LOG_DEBUG, "HttpWorkerThread::run() -- end"); #endif }
void HttpWorkerThread::ProcessWork() { // VERBOSE( VB_UPNP, QString( "HttpWorkerThread::ProcessWork:Begin( %1 ) socket=%2" ) // .arg( (long)QThread::currentThread() ) // .arg( m_nSocket )); bool bTimeout = false; bool bKeepAlive = true; BufferedSocketDevice *pSocket = NULL; HTTPRequest *pRequest = NULL; try { if ((pSocket = new BufferedSocketDevice( m_nSocket )) == NULL) { VERBOSE( VB_IMPORTANT, QString( "HttpWorkerThread::ProcessWork - Error Creating BufferedSocketDevice" )); return; } pSocket->SocketDevice()->setBlocking( true ); while( !m_bTermRequested && bKeepAlive && pSocket->IsValid()) { bTimeout = 0; int64_t nBytes = pSocket->WaitForMore(m_nSocketTimeout, &bTimeout); if ( nBytes > 0) { // ---------------------------------------------------------- // See if this is a valid request // ---------------------------------------------------------- if ((pRequest = new BufferedSocketDeviceRequest( pSocket )) != NULL) { if ( pRequest->ParseRequest() ) { bKeepAlive = pRequest->GetKeepAlive(); // ------------------------------------------------------ // Request Parsed... Pass on to Main HttpServer class to // delegate processing to HttpServerExtensions. // ------------------------------------------------------ if (pRequest->m_nResponseStatus != 401) m_pHttpServer->DelegateRequest( this, pRequest ); } else { VERBOSE( VB_UPNP, QString( "HttpWorkerThread::ProcessWork - ParseRequest Failed." )); pRequest->m_nResponseStatus = 501; bKeepAlive = false; } #if 0 // Dump Request Header if (!bKeepAlive ) { for ( QStringMap::iterator it = pRequest->m_mapHeaders.begin(); it != pRequest->m_mapHeaders.end(); ++it ) { VERBOSE(VB_IMPORTANT, QString("%1: %2") .arg(it.key()) .arg(it.data())); } } #endif // ------------------------------------------------------- // Always MUST send a response. // ------------------------------------------------------- if (pRequest->SendResponse() < 0) { bKeepAlive = false; VERBOSE( VB_UPNP, QString( "HttpWorkerThread::ProcessWork socket(%1) - Error returned from SendResponse... Closing connection" ) .arg( m_nSocket )); } // ---------------------------------------------------------- // Check to see if a PostProcess was registered // ---------------------------------------------------------- if ( pRequest->m_pPostProcess != NULL ) pRequest->m_pPostProcess->ExecutePostProcess(); delete pRequest; pRequest = NULL; } else { VERBOSE( VB_IMPORTANT, QString( "HttpWorkerThread::ProcessWork - Error Creating BufferedSocketDeviceRequest" )); bKeepAlive = false; } } else { bKeepAlive = false; } } } catch( ... ) { VERBOSE( VB_IMPORTANT, QString( "HttpWorkerThread::ProcessWork - Unexpected Exception." )); } if (pRequest != NULL) delete pRequest; pSocket->Close(); delete pSocket; m_nSocket = 0; // VERBOSE( VB_UPNP, QString( "HttpWorkerThread::ProcessWork:End( %1 )") // .arg( (long)QThread::currentThread() )); }
/** Actually sends the sMethod action to the command URL specified * in the constructor (url+[/]+sControlPath). * * \param sMethod method to be invoked. e.g. "SetChannel", * "GetConnectionInfoResult" * * \param list Parsed as a series of key value pairs for the input params * and then cleared and used for the output params. * * \param nErrCode set to zero on success, non-zero in case of error. * * \param sErrCode returns error description from device, when applicable. * * \param bInQtThread May be set to true if this is run from within * a QThread with a running an event loop. * * \return Returns a QDomDocument containing output parameters on success. */ QDomDocument SOAPClient::SendSOAPRequest(const QString &sMethod, QStringMap &list, int &nErrCode, QString &sErrDesc, bool bInQtThread) { QUrl url(m_url); url.setPath(m_sControlPath); nErrCode = UPnPResult_Success; sErrDesc = ""; QDomDocument xmlResult; if (m_sNamespace.isEmpty()) { nErrCode = UPnPResult_MythTV_NoNamespaceGiven; sErrDesc = "No namespace given"; return xmlResult; } // -------------------------------------------------------------- // Add appropriate headers // -------------------------------------------------------------- QHttpRequestHeader header("POST", sMethod, 1, 0); header.setValue("CONTENT-TYPE", "text/xml; charset=\"utf-8\"" ); header.setValue("SOAPACTION", QString("\"%1#%2\"").arg(m_sNamespace).arg(sMethod)); // -------------------------------------------------------------- // Build request payload // -------------------------------------------------------------- QByteArray aBuffer; QTextStream os( &aBuffer ); os.setCodec("UTF-8"); os << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n"; os << "<s:Envelope " " s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"" " xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">\r\n"; os << " <s:Body>\r\n"; os << " <u:" << sMethod << " xmlns:u=\"" << m_sNamespace << "\">\r\n"; // -------------------------------------------------------------- // Add parameters from list // -------------------------------------------------------------- for (QStringMap::iterator it = list.begin(); it != list.end(); ++it) { os << " <" << it.key() << ">"; os << HTTPRequest::Encode( *it ); os << "</" << it.key() << ">\r\n"; } os << " </u:" << sMethod << ">\r\n"; os << " </s:Body>\r\n"; os << "</s:Envelope>\r\n"; os.flush(); // -------------------------------------------------------------- // Perform Request // -------------------------------------------------------------- QBuffer buff(&aBuffer); LOG(VB_UPNP, LOG_DEBUG, QString("SOAPClient(%1) sending:\n").arg(url.toString()) + header.toString() + QString("\n%1\n").arg(aBuffer.constData())); QString sXml = HttpComms::postHttp(url, &header, &buff, // QIODevice* 10000, // ms -- Technically should be 30ms per spec 3, // retries 0, // redirects false, // allow gzip NULL, // login bInQtThread, QString() // userAgent, UPnP/1.0 very strict on // format if set ); // -------------------------------------------------------------- // Parse response // -------------------------------------------------------------- LOG(VB_UPNP, LOG_DEBUG, "SOAPClient response:\n" + QString("%1\n").arg(sXml)); // TODO handle timeout without response correctly. list.clear(); QDomDocument doc; if (!doc.setContent(sXml, true, &sErrDesc, &nErrCode)) { LOG(VB_UPNP, LOG_ERR, QString("SendSOAPRequest( %1 ) - Invalid response from %2") .arg(sMethod).arg(url.toString()) + QString("%1: %2").arg(nErrCode).arg(sErrDesc)); return xmlResult; } // -------------------------------------------------------------- // Is this a valid response? // -------------------------------------------------------------- QString sResponseName = sMethod + "Response"; QDomNodeList oNodeList = doc.elementsByTagNameNS(m_sNamespace, sResponseName); if (oNodeList.count() == 0) { // -------------------------------------------------------------- // Must be a fault... parse it to return reason // -------------------------------------------------------------- nErrCode = GetNodeValue( doc, "Envelope/Body/Fault/detail/UPnPError/errorCode", 500); sErrDesc = GetNodeValue( doc, "Envelope/Body/Fault/detail/UPnPError/errorDescription", ""); if (sErrDesc.isEmpty()) sErrDesc = QString("Unknown #%1").arg(nErrCode); QDomNode oNode = FindNode( "Envelope/Body/Fault", doc ); oNode = xmlResult.importNode( oNode, true ); xmlResult.appendChild( oNode ); return xmlResult; } QDomNode oMethod = oNodeList.item(0); if (oMethod.isNull()) return xmlResult; QDomNode oNode = oMethod.firstChild(); for (; !oNode.isNull(); oNode = oNode.nextSibling()) { QDomElement e = oNode.toElement(); if (e.isNull()) continue; QString sName = e.tagName(); QString sValue = ""; QDomText oText = oNode.firstChild().toText(); if (!oText.isNull()) sValue = oText.nodeValue(); list.insert(QUrl::fromPercentEncoding(sName.toUtf8()), QUrl::fromPercentEncoding(sValue.toUtf8())); } // Create copy of oMethod that can be used with xmlResult. oMethod = xmlResult.importNode( oMethod.firstChild(), true ); // importNode does not attach the new nodes to the document, // do it here. xmlResult.appendChild( oMethod ); return xmlResult; }
bool SOAPClient::SendSOAPRequest( const QString &sMethod, QStringMap &list, int &nErrCode, QString &sErrDesc, bool bInQtThread ) { QUrl url( m_url ); url.setPath( m_sControlPath ); // -------------------------------------------------------------- // Add appropriate headers // -------------------------------------------------------------- QHttpRequestHeader header; header.setValue("CONTENT-TYPE", "text/xml; charset=\"utf-8\"" ); header.setValue("SOAPACTION" , QString( "\"%1#GetConnectionInfo\"" ) .arg( m_sNamespace )); // -------------------------------------------------------------- // Build request payload // -------------------------------------------------------------- QByteArray aBuffer; QTextStream os( &aBuffer ); os << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n"; os << "<s:Envelope s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">\r\n"; os << " <s:Body>\r\n"; os << " <u:" << sMethod << " xmlns:u=\"" << m_sNamespace << "\">\r\n"; // -------------------------------------------------------------- // Add parameters from list // -------------------------------------------------------------- for ( QStringMap::iterator it = list.begin(); it != list.end(); ++it ) { os << " <" << it.key() << ">"; os << HTTPRequest::Encode( *it ); os << "</" << it.key() << ">\r\n"; } os << " </u:" << sMethod << ">\r\n"; os << " </s:Body>\r\n"; os << "</s:Envelope>\r\n"; os.flush(); // -------------------------------------------------------------- // Perform Request // -------------------------------------------------------------- QBuffer buff( &aBuffer ); QString sXml = HttpComms::postHttp( url, &header, (QIODevice *)&buff, 10000, // ms 3, // retries 0, // redirects false, // allow gzip NULL, // login bInQtThread ); // -------------------------------------------------------------- // Parse response // -------------------------------------------------------------- list.clear(); QDomDocument doc; if ( !doc.setContent( sXml, true, &sErrDesc, &nErrCode )) { VERBOSE( VB_UPNP, QString( "MythXMLClient::SendSOAPRequest( %1 ) - Invalid response from %2" ) .arg( sMethod ) .arg( url.toString() )); return false; } // -------------------------------------------------------------- // Is this a valid response? // -------------------------------------------------------------- QString sResponseName = sMethod + "Response"; QDomNodeList oNodeList = doc.elementsByTagNameNS( m_sNamespace, sResponseName ); if (oNodeList.count() > 0) { QDomNode oMethod = oNodeList.item(0); if (!oMethod.isNull()) { for ( QDomNode oNode = oMethod.firstChild(); !oNode.isNull(); oNode = oNode.nextSibling() ) { QDomElement e = oNode.toElement(); if (!e.isNull()) { QString sName = e.tagName(); QString sValue = ""; QDomText oText = oNode.firstChild().toText(); if (!oText.isNull()) sValue = oText.nodeValue(); list.insert(QUrl::fromPercentEncoding(sName.toUtf8()), QUrl::fromPercentEncoding(sValue.toUtf8())); } } } return true; } // -------------------------------------------------------------- // Must be a fault... parse it to return reason // -------------------------------------------------------------- nErrCode = GetNodeValue( doc, "Envelope/Body/Fault/detail/UPnPResult/errorCode" , 500 ); sErrDesc = GetNodeValue( doc, "Envelope/Body/Fault/detail/UPnPResult/errorDescription", QString( "Unknown" )); return false; }