示例#1
0
QString SSDP::GetHeaderValue( const QStringMap &headers,
                              const QString    &sKey, const QString &sDefault )
{
    QStringMap::const_iterator it = headers.find( sKey.toLower() );

    if ( it == headers.end())
        return( sDefault );

    return *it;
}
示例#2
0
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;
}
示例#3
0
/** 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;
}
示例#4
0
QVariant MethodInfo::Invoke( Service *pService, const QStringMap &reqParams )
{
    HttpRedirectException exception;
    bool                  bExceptionThrown = false;
    QStringMap            lowerParams;

    if (!pService)
        throw;

     // Change params to lower case for case-insensitive comparison
    QStringMap::const_iterator it = reqParams.begin();
    for (; it != reqParams.end(); ++it)
    {
        lowerParams[it.key().toLower()] = *it;
    }

    // --------------------------------------------------------------
    // Provide actual parameters received to method
    // --------------------------------------------------------------

    pService->m_parsedParams = lowerParams.keys();


    QList<QByteArray> paramNames = m_oMethod.parameterNames();
    QList<QByteArray> paramTypes = m_oMethod.parameterTypes();

    // ----------------------------------------------------------------------
    // Create Parameter array (Can't have more than _MAX_PARAMS parameters)....
    // switched to static array for performance.
    // ----------------------------------------------------------------------

    void *param[ _MAX_PARAMS ];
    int   types[ _MAX_PARAMS ];

    memset( param, 0, _MAX_PARAMS * sizeof(void *));
    memset( types, 0, _MAX_PARAMS * sizeof(int));

    try
    {
        // --------------------------------------------------------------
        // Add a place for the Return value
        // --------------------------------------------------------------

        int nRetIdx = QMetaType::type( m_oMethod.typeName() ); 

        if (nRetIdx != 0)
        {
            param[ 0 ] = QMetaType::create( nRetIdx );
            types[ 0 ] = nRetIdx;
        }
        else
        {
            param[ 0 ] = nullptr;
            types[ 0 ] = 0;
        }

        // --------------------------------------------------------------
        // Fill in parameters from request values
        // --------------------------------------------------------------

        for( int nIdx = 0; nIdx < paramNames.length(); nIdx++ )
        {
            QString sValue     = lowerParams[ paramNames[ nIdx ].toLower() ];
            QString sParamType = paramTypes[ nIdx ];

            int     nId        = QMetaType::type( paramTypes[ nIdx ] );
            void   *pParam     = nullptr;

            if (nId != 0)
            {
                pParam = QMetaType::create( nId );
            }
            else
            {
                LOG(VB_GENERAL, LOG_ERR,
                    QString("MethodInfo::Invoke - Type unknown '%1'")
                        .arg(sParamType));
            }

            types[nIdx+1] = nId;
            param[nIdx+1] = pService->ConvertToParameterPtr( nId, sParamType,
                                                             pParam, sValue );
        }

#if 0
        QThread *currentThread = QThread::currentThread();
        QThread *objectThread  = pService->thread();

        if (currentThread == objectThread)
            LOG(VB_HTTP, LOG_DEBUG, "*** Threads are same ***");
        else
            LOG(VB_HTTP, LOG_DEBUG, "*** Threads are Different!!! ***");
#endif

        pService->qt_metacall( QMetaObject::InvokeMetaMethod, 
                               m_nMethodIndex, 
                               param );

        // --------------------------------------------------------------
        // Delete param array, skip return parameter since not dynamically
        // created.
        // --------------------------------------------------------------

        for (int nIdx=1; nIdx < paramNames.length()+1; nIdx++)
        {
            if ((types[ nIdx ] != 0) && (param[ nIdx ] != nullptr))
                QMetaType::destroy( types[ nIdx ], param[ nIdx ] );
        }
    }
    catch (QString &sMsg)
    {
        LOG(VB_GENERAL, LOG_ERR,
            QString("MethodInfo::Invoke - An Exception Occurred: %1")
                 .arg(sMsg));

        if  ((types[ 0 ] != 0) && (param[ 0 ] != nullptr ))
            QMetaType::destroy( types[ 0 ], param[ 0 ] );

        throw;
    }
    catch (HttpRedirectException &ex)
    {
        bExceptionThrown = true;
        exception = ex;
    }
    catch (...)
    {
        LOG(VB_GENERAL, LOG_INFO,
            "MethodInfo::Invoke - An Exception Occurred" );
    }

    // --------------------------------------------------------------
    // return the result after converting to a QVariant
    // --------------------------------------------------------------

    QVariant vReturn;
  
    if ( param[ 0 ] != nullptr)
    {
        vReturn = pService->ConvertToVariant( types[ 0 ], param[ 0 ] );

        if  (types[ 0 ] != 0)
            QMetaType::destroy( types[ 0 ], param[ 0 ] );
    }

    // --------------------------------------------------------------
    // Re-throw exception if needed.
    // --------------------------------------------------------------

    if (bExceptionThrown)
        throw exception;

    return vReturn;
}
示例#5
0
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;
}
示例#6
0
bool ServerSideScripting::EvaluatePage( QTextStream *pOutStream, const QString &sFileName,
                                        HTTPRequest *pRequest)
{
    try
    {

        ScriptInfo *pInfo = NULL;

        // ------------------------------------------------------------------
        // See if page has already been loaded
        // ------------------------------------------------------------------

        pInfo = GetLoadedScript( sFileName );

        // ------------------------------------------------------------------
        // Load Script File and Create Function
        // ------------------------------------------------------------------

        QFileInfo  fileInfo ( sFileName );
        QDateTime  dtLastModified = fileInfo.lastModified();

        Lock();
        if ((pInfo == NULL) || (pInfo->m_dtTimeStamp != dtLastModified ))
        {
            QString      sCode = CreateMethodFromFile( sFileName );

            QScriptValue func  = m_engine.evaluate( sCode, sFileName );

            if ( m_engine.hasUncaughtException() )
            {
                LOG(VB_GENERAL, LOG_ERR,
                    QString("Error Loading QSP File: %1 - (line %2) %3")
                        .arg(sFileName)
                        .arg(m_engine.uncaughtExceptionLineNumber())
                        .arg(m_engine.uncaughtException().toString()));

                Unlock();
                return false;
            }

            if (pInfo != NULL)
            {
                pInfo->m_oFunc       = func;
                pInfo->m_dtTimeStamp = dtLastModified;
            }
            else
            {
                pInfo = new ScriptInfo( func, dtLastModified );
                m_mapScripts[ sFileName ] = pInfo;
            }
        }

        // ------------------------------------------------------------------
        // Build array of arguments passed to script
        // ------------------------------------------------------------------

        QStringMap mapParams = pRequest->m_mapParams;

        // Valid characters for object property names must contain only
        // word characters and numbers, _ and $
        // They must not start with a number - to simplify the regexp, we
        // restrict the first character to the English alphabet
        QRegExp validChars = QRegExp("^([a-zA-Z]|_|\\$)(\\w|\\$)+$");

        QVariantMap params;
        QMap<QString, QString>::const_iterator it = mapParams.begin();
        QString prevArrayName = "";
        QVariantMap array;
        for (; it != mapParams.end(); ++it)
        {
            QString key = it.key();
            QVariant value = QVariant(it.value());

            // PHP Style parameter array
            if (key.contains("["))
            {
                QString arrayName = key.section('[',0,0);
                QString arrayKey = key.section('[',1,1);
                arrayKey.chop(1); // Remove trailing ]
                if (prevArrayName != arrayName) // New or different array
                {
                    if (!array.isEmpty())
                    {
                        params.insert(prevArrayName, QVariant(array));
                        array.clear();
                    }
                    prevArrayName = arrayName;
                }

                if (!validChars.exactMatch(arrayKey)) // Discard anything that isn't valid for now
                    continue;

                array.insert(arrayKey, value);

                if ((it + 1) != mapParams.end())
                    continue;
            }

            if (!array.isEmpty())
            {
                params.insert(prevArrayName, QVariant(array));
                array.clear();
            }
            // End Array handling

            if (!validChars.exactMatch(key)) // Discard anything that isn't valid for now
                continue;

            params.insert(key, value);

        }

        // ------------------------------------------------------------------
        // Build array of request headers
        // ------------------------------------------------------------------

        QStringMap mapHeaders = pRequest->m_mapHeaders;

        QVariantMap requestHeaders;
        for (it = mapHeaders.begin(); it != mapHeaders.end(); ++it)
        {
            QString key = it.key();
            key = key.replace('-', '_'); // May be other valid chars in a request header that we need to replace
            QVariant value = QVariant(it.value());

            if (!validChars.exactMatch(key)) // Discard anything that isn't valid for now
                continue;

            requestHeaders.insert(key, value);
        }

        // ------------------------------------------------------------------
        // Build array of information from the server e.g. client IP
        // See RFC 3875 - The Common Gateway Interface
        // ------------------------------------------------------------------

        QVariantMap serverVars;
        serverVars.insert("REMOTE_ADDR", QVariant(pRequest->GetPeerAddress()));
        serverVars.insert("SERVER_ADDR", QVariant(pRequest->GetHostAddress()));
        serverVars.insert("SERVER_PROTOCOL", QVariant(pRequest->GetRequestProtocol()));
        serverVars.insert("SERVER_SOFTWARE", QVariant(HttpServer::GetServerVersion()));

        QHostAddress clientIP = QHostAddress(pRequest->GetPeerAddress());
        QHostAddress serverIP = QHostAddress(pRequest->GetHostAddress());
        if (clientIP.protocol() == QAbstractSocket::IPv4Protocol)
        {
            serverVars.insert("IP_PROTOCOL", "IPv4");
        }
        else if (clientIP.protocol() == QAbstractSocket::IPv6Protocol)
        {
            serverVars.insert("IP_PROTOCOL", "IPv6");
        }

        if (((clientIP.protocol() == QAbstractSocket::IPv4Protocol) &&
             (clientIP.isInSubnet(QHostAddress("172.16.0.0"), 12) ||
              clientIP.isInSubnet(QHostAddress("192.168.0.0"), 16) ||
              clientIP.isInSubnet(QHostAddress("10.0.0.0"), 8))) ||
            ((clientIP.protocol() == QAbstractSocket::IPv6Protocol) &&
              clientIP.isInSubnet(serverIP, 64))) // default subnet size is assumed to be /64
        {
            serverVars.insert("CLIENT_NETWORK", "local");
        }
        else
        {
            serverVars.insert("CLIENT_NETWORK", "remote");
        }

        // ------------------------------------------------------------------
        // Add the arrays (objects) we've just created to the global scope
        // They may be accessed as 'Server.REMOTE_ADDR'
        // ------------------------------------------------------------------

        m_engine.globalObject().setProperty("Parameters",
                                            m_engine.toScriptValue(params));
        m_engine.globalObject().setProperty("RequestHeaders",
                                            m_engine.toScriptValue(requestHeaders));
        m_engine.globalObject().setProperty("Server",
                                            m_engine.toScriptValue(serverVars));

        // ------------------------------------------------------------------
        // Execute function to render output
        // ------------------------------------------------------------------

        OutputStream outStream( pOutStream );

        QScriptValueList args;
        args << m_engine.newQObject( &outStream );
        args << m_engine.toScriptValue(params);

        QScriptValue ret = pInfo->m_oFunc.call( QScriptValue(), args );

        if (ret.isError())
        {
            QScriptValue lineNo = ret.property( "lineNumber" );

            LOG(VB_GENERAL, LOG_ERR,
                QString("Error calling QSP File: %1(%2) - %3")
                    .arg(sFileName)
                    .arg( lineNo.toInt32 () )
                    .arg( ret   .toString() ));
            Unlock();
            return false;

        }

        if (m_engine.hasUncaughtException())
        {
            LOG(VB_GENERAL, LOG_ERR,
                QString("Error calling QSP File: %1(%2) - %3")
                    .arg(sFileName)
                    .arg(m_engine.uncaughtExceptionLineNumber() )
                    .arg(m_engine.uncaughtException().toString()));
            Unlock();
            return false;
        }
        Unlock();
    }
    catch(...)
    {
        LOG(VB_GENERAL, LOG_ERR,
            QString("Exception while evaluating QSP File: %1") .arg(sFileName));

        Unlock();
        return false;
    }

    return true;
}