From c601b5a27f74b16158adafe429faefbe573e64a2 Mon Sep 17 00:00:00 2001 From: Szymon Tomasz Stefanek Date: Sat, 1 Jan 2011 20:19:56 +0000 Subject: The big rename for modules. Still some details remaining. git-svn-id: https://svn.kvirc.de/svn/trunk/kvirc@5284 17fca916-40b9-46aa-a4ea-0a15b648b75c --- src/modules/objects/KvsObject_http.cpp | 561 +++++++++++++++++++++++++++++++++ 1 file changed, 561 insertions(+) create mode 100644 src/modules/objects/KvsObject_http.cpp (limited to 'src/modules/objects/KvsObject_http.cpp') diff --git a/src/modules/objects/KvsObject_http.cpp b/src/modules/objects/KvsObject_http.cpp new file mode 100644 index 000000000..c0adda535 --- /dev/null +++ b/src/modules/objects/KvsObject_http.cpp @@ -0,0 +1,561 @@ +//============================================================================= +// +// File : KvsObject_http.cpp +// Creation date : Fry Sep 5 18:13:45 2008 GMT by Carbone Alesssandro +// +// This file is part of the KVIrc irc client distribution +// Copyright (C) 2009 Alessandro Carbone (elfonol at gmail dot com) +// +// This program is FREE software. You can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "KvsObject_http.h" + +#include "kvi_debug.h" +#include "KviError.h" +#include "KviLocale.h" + +#include +#include +#include + +#ifndef QT_NO_OPENSSL + #include + + const char * const ssl_errors_tbl[] = { + "NoError", + "UnableToGetIssuerCertificate", + "UnableToDecryptCertificateSignature", + "UnableToDecodeIssuerPublicKey", + "CertificateSignatureFailed", + "CertificateNotYetValid", + "CertificateExpired", + "InvalidNotBeforeField", + "InvalidNotAfterField", + "SelfSignedCertificate", + "SelfSignedCertificateInChain", + "UnableToGetLocalIssuerCertificate", + "UnableToVerifyFirstCertificate", + "CertificateRevoked", + "InvalidCaCertificate", + "PathLengthExceeded", + "InvalidPurpose", + "CertificateUntrusted", + "CertificateRejected", + "SubjectIssuerMismatch", + "AuthorityIssuerSerialNumberMismatch", + "NoPeerCertificate", + "HostNameMismatch", + "UnspecifiedError", + "NoSslSupport" + }; +#endif + +/* + @doc: http + @keyterms: + http object class + @title: + http class + @type: + class + @short: + An implementation of the client side of HTTP protocol. + @inherits: + [class]object[/class] + @description: + This class provides a standard HTTP functionality.[br] + @functions: + !fn: $get(,[]) + Sends a get request for path to the server set by [classfnc]$setHost[/classfnc]. + If local_file is not specified readyRead() signal is emitted every time new content data is available to read. + !fn: $post(,, + Sends a post request for path to the server set by [classfnc]$setHost[/classfnc]. + If local_file is not specified readyRead() signal is emitted every time new content data is available to read. + !fn: $abort() + Aborts the current request and deletes all scheduled requests. + !fn: $setHost(,) + Sets the HTTP server that is used for requests to hostName on port port. + The function does not block: the request is scheduled, and its execution is performed asynchronously. + The function returns a unique identifier which is passed by [classfnc]requestStartedEvent()[/classfnc] and [classfnc]requestFinishedEvent()[/classfnc]. + When the request is started the requestStarted() signal is emitted. When it is finished the requestFinished() signal is emitted. + !fn: $currentId() + Returns the identifier of the HTTP request being executed or 0 if there is no request being executed. + !fn: $setProxy(,,[,]) + Enables HTTP proxy support, using the proxy server host on port port. + Optionals parameters user and password can be provided if the proxy server requires authentication. + !fn: $setUser(,) + This function sets the user name userName and password password for web pages that require authentication. + !fn: $readAll() + Reads all the bytes from the response content and returns them as string. + !fn: $errorString() + Returns a human-readable description of the last error that occurred. + !fn: $ignoreSslErrors() + !fn: $requestFinishedEvent(,) + This event is triggered by KVIrc when the request identified by has finished. + !fn: $requestStartedEvent(,) + This event is triggered by KVIrc when the request identified by has started. + !fn: $responseHeaderReceivedEvent() + This event is triggered by KVIrc when he HTTP header of a server response is available. + The response is passed ad string. + !fn: $doneEvent() + This event is triggered when the last pending request has finished; (it is emitted after the last request's requestFinished() signal). + !fn: $dataReadProgressEvent(,) + This event is triggered when reads data from a HTTP server. + is the amount of data has already arrived and is the total amount of data. + !fn: $dataSendProgressEvent(,) + This event is triggered when sends data to a HTTP server. + is the amount of data has already arrived and is the total amount of data. + !fn: $stateChangedEvent() + This event is triggered by the framework when the state of the connection changes. + !fn: $readyReadEvent() + This event is triggered by the framework when there is new data read and there is not file specified in [classfnc]get[/classfunc] or [classfnc]post[/classfunc]. + You can call [classfnc]readAll[/classfnc] to reads all the bytes from the response data. + !fn: $sslErrorsEvent() + Returns the list of errors that occurred during the SSL handshake. + Unless you call ignoreSslErrors() from within a slot connected to the signal emited by this event, + the framwork will tear down the connection immediately after emitting the signal. + @signals: + !sg: $requestStarted() + This signal is emitted by the default implementation of [classfnc]$requestStartedEvent[/classfnc]. + !sg: $requestFinished() + This signal is emitted by the default implementation of [classfnc]$requestFinishedEvent[/classfnc]. + !sg: $dataSendProgress() + This signal is emitted by the default implementation of [classfnc]$dataSendProgressEvent[/classfnc]. + !sg: $dataReadProgress() + This signal is emitted by the default implementation of [classfnc]$dataReadProgressEvent[/classfnc]. + !sg: $done() + This signal is emitted by the default implementation of [classfnc]$doneEvent[/classfnc]. + !sg: $readyRead() + This signal is emitted by the default implementation of [classfnc]$readyReadEvent[/classfnc]. + !sg: $sslErrors() + This signal is emitted by the default implementation of [classfnc]$sslErrorsEvent[/classfnc]. + !sg: $stateChanged() + This signal is emitted by the default implementation of [classfnc]$stateChangedEvent[/classfnc]. + !sg: $responseHeaderReceived() + This signal is emitted by the default implementation of [classfnc]$responseHeaderReceivedEvent[/classfnc]. +*/ + +KVSO_BEGIN_REGISTERCLASS(KvsObject_http,"http","object") + KVSO_REGISTER_HANDLER(KvsObject_http,"get",functionGet) + KVSO_REGISTER_HANDLER(KvsObject_http,"post",functionPost) + KVSO_REGISTER_HANDLER(KvsObject_http,"abort",functionAbort) + KVSO_REGISTER_HANDLER(KvsObject_http,"setHost",functionSetHost) + KVSO_REGISTER_HANDLER(KvsObject_http,"setProxy",functionSetProxy) + KVSO_REGISTER_HANDLER(KvsObject_http,"currentId",functionCurrentId) + KVSO_REGISTER_HANDLER(KvsObject_http,"setUser",functionSetUser) + KVSO_REGISTER_HANDLER(KvsObject_http,"readAll",functionReadAll) + KVSO_REGISTER_HANDLER(KvsObject_http,"errorString",functionErrorString) + KVSO_REGISTER_HANDLER(KvsObject_http,"setFollowRedirect",functionFollowRedirect) + + // events + KVSO_REGISTER_HANDLER(KvsObject_http,"doneEvent",functionDoneEvent) + KVSO_REGISTER_HANDLER(KvsObject_http,"requestFinishedEvent",functionRequestFinishedEvent) + KVSO_REGISTER_HANDLER(KvsObject_http,"requestStartedEvent",functionRequestStartedEvent) + KVSO_REGISTER_HANDLER(KvsObject_http,"responseHeaderReceivedEvent",functionResponseHeaderReceivedEvent) + KVSO_REGISTER_HANDLER(KvsObject_http,"dataReadProgressEvent",functionDataReadProgressEvent) + KVSO_REGISTER_HANDLER(KvsObject_http,"dataSendProgressEvent",functionDataSendProgressEvent) + KVSO_REGISTER_HANDLER(KvsObject_http,"stateChangedEvent",functionStateChangedEvent) + KVSO_REGISTER_HANDLER(KvsObject_http,"readyReadEvent",functionReadyReadEvent) + #ifndef QT_NO_OPENSSL + KVSO_REGISTER_HANDLER(KvsObject_http,"sslErrorsEvent",functionSslErrorsEvent) + KVSO_REGISTER_HANDLER(KvsObject_http,"ignoreSSlErrors",functionIgnoreSslErrors) + #endif +KVSO_END_REGISTERCLASS(KvsObject_http) + + +KVSO_BEGIN_CONSTRUCTOR(KvsObject_http,KviKvsObject) + m_pHttp = new QHttp(); + m_bAbort=false; + m_bEnableForceRedirect=false; + connect(m_pHttp,SIGNAL(requestFinished(int,bool)),this,SLOT(slotRequestFinished(int,bool))); + connect(m_pHttp,SIGNAL(done(bool)),this,SLOT(slotDone(bool))); + + connect(m_pHttp,SIGNAL(requestStarted(int)),this,SLOT(slotRequestStarted(int))); + connect(m_pHttp,SIGNAL(dataSendProgress(int,int)),this,SLOT(slotDataSendProgress(int,int))); + connect(m_pHttp,SIGNAL(dataReadProgress(int,int)),this,SLOT(slotDataReadProgress(int,int))); + connect(m_pHttp,SIGNAL(responseHeaderReceived ( const QHttpResponseHeader & )),this,SLOT(slotResponseHeaderReceived(const QHttpResponseHeader &))); + connect(m_pHttp,SIGNAL(readyRead ( const QHttpResponseHeader & )),this,SLOT(slotReadyRead(const QHttpResponseHeader &))); + #ifndef QT_NO_OPENSSL + connect(m_pHttp,SIGNAL(sslErrors ( const QList & )),this,SLOT(slotSslErrors(const QList & ))); + #endif + connect(m_pHttp,SIGNAL(stateChanged(int)),this,SLOT(slotStateChanged(int))); + +KVSO_END_CONSTRUCTOR(KvsObject_http) + +KVSO_BEGIN_DESTRUCTOR(KvsObject_http) + QHashIterator t(getDict); + while (t.hasNext()) + { + t.next(); + int key=t.key(); + QFile *pFile=getDict.value(key); + pFile->close(); + delete pFile; + } + getDict.clear(); + delete m_pHttp; + +KVSO_END_DESTRUCTOR(KvsObject_http) +//---------------------- + + +bool KvsObject_http::functionSetHost(KviKvsObjectFunctionCall *c) +{ + CHECK_INTERNAL_POINTER(m_pHttp) + QString szHost; + QString szConnectionType; + kvs_uint_t uRemotePort; + KVSO_PARAMETERS_BEGIN(c) + KVSO_PARAMETER("host",KVS_PT_STRING,0,szHost) + KVSO_PARAMETER("remote_port",KVS_PT_UNSIGNEDINTEGER,KVS_PF_OPTIONAL,uRemotePort) + KVSO_PARAMETERS_END(c) + QUrl url(szHost); + if (!url.isValid()) + { + c->warning(__tr2qs_ctx("Host '%Q' is not a valid url","objects"),&szHost); + return true; + } + if (!szHost.isEmpty() && url.host().isEmpty()) url.setHost(szHost); + if (!uRemotePort) uRemotePort=80; + kvs_uint_t id=0; + QHttp::ConnectionMode mode; + if(url.scheme().toLower()=="https") mode=QHttp::ConnectionModeHttps; + else {mode=QHttp::ConnectionModeHttp;url.setScheme("http");} + if (mode==QHttp::ConnectionModeHttps) uRemotePort=443; + id=m_pHttp->setHost(url.host(), mode, uRemotePort); + c->returnValue()->setInteger(id); + return true; +} +bool KvsObject_http::functionCurrentId(KviKvsObjectFunctionCall *c) +{ + CHECK_INTERNAL_POINTER(m_pHttp) + c->returnValue()->setInteger(m_pHttp->currentId()); + return true; +} +bool KvsObject_http::functionSetUser(KviKvsObjectFunctionCall *c) +{ + CHECK_INTERNAL_POINTER(m_pHttp) + QString szUser; + QString szPass; + KVSO_PARAMETERS_BEGIN(c) + KVSO_PARAMETER("user",KVS_PT_STRING,0,szUser) + KVSO_PARAMETER("password",KVS_PT_STRING,0,szPass) + KVSO_PARAMETERS_END(c) + kvs_int_t id; + id=m_pHttp->setUser(szUser,szPass); + return true; +} +bool KvsObject_http::functionSetProxy(KviKvsObjectFunctionCall *c) +{ + CHECK_INTERNAL_POINTER(m_pHttp) + QString szHost; + QString szUser,szPass; + kvs_uint_t uRemotePort; + KVSO_PARAMETERS_BEGIN(c) + KVSO_PARAMETER("host",KVS_PT_STRING,0,szHost) + KVSO_PARAMETER("remote_port",KVS_PT_UNSIGNEDINTEGER,KVS_PF_OPTIONAL,uRemotePort) + KVSO_PARAMETER("user",KVS_PT_STRING,KVS_PF_OPTIONAL,szUser) + KVSO_PARAMETER("pass",KVS_PT_STRING,KVS_PF_OPTIONAL,szPass) + KVSO_PARAMETERS_END(c) + m_pHttp->setProxy(szHost,uRemotePort,szUser,szPass); + return true; +} + +bool KvsObject_http::functionGet(KviKvsObjectFunctionCall *c) +{ + CHECK_INTERNAL_POINTER(m_pHttp) + QString szPath,szDest; + KVSO_PARAMETERS_BEGIN(c) + KVSO_PARAMETER("remote_path",KVS_PT_STRING,0,szPath) + KVSO_PARAMETER("local_filename",KVS_PT_STRING,KVS_PF_OPTIONAL,szDest) + KVSO_PARAMETERS_END(c) + + QFile * pFile=0; + if (!szDest.isEmpty()) + { + pFile=new QFile(szDest); + if (pFile) + { + pFile->open(QIODevice::WriteOnly); + } else { + c->warning(__tr2qs_ctx("'%Q' is not a valid file path","objects"),&szDest); + c->returnValue()->setInteger(-1); + return true; + } + } + + if (szPath.isEmpty()) szPath="/"; + int id=m_pHttp->get(szPath,pFile); + if (pFile) getDict[id]=pFile; + c->returnValue()->setInteger(id); + return true; +} +bool KvsObject_http::functionPost(KviKvsObjectFunctionCall *c) +{ + CHECK_INTERNAL_POINTER(m_pHttp) + QString szPath,szDest,szData; + KVSO_PARAMETERS_BEGIN(c) + KVSO_PARAMETER("remote_path",KVS_PT_STRING,0,szPath) + KVSO_PARAMETER("post_data",KVS_PT_STRING,0,szData) + KVSO_PARAMETER("local_filename",KVS_PT_STRING,0,szDest) + KVSO_PARAMETERS_END(c) + QFile *pFile=0; + if (!szDest.isEmpty()){ + pFile=new QFile(szDest); + if (pFile){ + pFile->open(QIODevice::WriteOnly); + } + } + if (szPath.isEmpty()) szPath="/"; + int id=m_pHttp->post(szPath,szDest.toAscii(),pFile); + if (pFile) getDict[id]=pFile; + c->returnValue()->setInteger(id); + return true; +} +bool KvsObject_http::functionAbort(KviKvsObjectFunctionCall *c) +{ + CHECK_INTERNAL_POINTER(m_pHttp) + m_bAbort=true; + m_pHttp->abort(); + return true; +} +bool KvsObject_http::functionReadAll(KviKvsObjectFunctionCall *c) +{ + CHECK_INTERNAL_POINTER(m_pHttp) + c->returnValue()->setString(m_pHttp->readAll()); + return true; +} +bool KvsObject_http::functionErrorString(KviKvsObjectFunctionCall *c) +{ + CHECK_INTERNAL_POINTER(m_pHttp) + c->returnValue()->setString(m_pHttp->errorString()); + return true; +} +bool KvsObject_http::functionFollowRedirect(KviKvsObjectFunctionCall *c) +{ + bool bEnabled; + KVSO_PARAMETERS_BEGIN(c) + KVSO_PARAMETER("enable",KVS_PT_BOOLEAN,0,bEnabled) + KVSO_PARAMETERS_END(c) + m_bEnableForceRedirect=bEnabled; + return true; +} +//signals & slots + +bool KvsObject_http::functionRequestFinishedEvent(KviKvsObjectFunctionCall *c) +{ + emitSignal("requestFinished",c,c->params()); + return true; +} + +void KvsObject_http::slotRequestFinished ( int id, bool error ) +{ + + if (m_bAbort) + { + m_bAbort=false; + QHashIterator t(getDict); + while (t.hasNext()) + { + t.next(); + int key=t.key(); + QFile *pFile=getDict.value(key); + pFile->close(); + delete pFile; + } + getDict.clear(); + return; + } + QFile *pFile=getDict.value(id); + if (pFile) + { + QString name=pFile->fileName(); + pFile->close(); + getDict.remove(id); + int res=m_pHttp->lastResponse().statusCode(); + if ((res==301 || res==302 || res==307) && m_bEnableForceRedirect) + redirect(name,m_pHttp->lastResponse()); + delete pFile; + } + KviKvsVariantList lParams; + lParams.append(new KviKvsVariant((kvs_int_t) id)); + lParams.append(new KviKvsVariant(error)); + callFunction(this,"requestFinishedEvent",0,&lParams); +} + +bool KvsObject_http::functionRequestStartedEvent(KviKvsObjectFunctionCall *c) +{ + emitSignal("requestStarted",c,c->params()); + return true; +} +void KvsObject_http::slotRequestStarted ( int id ) +{ + KviKvsVariantList lParams; + lParams.append(new KviKvsVariant((kvs_int_t) id)); + callFunction(this,"requestStartedEvent",0,&lParams); +} + +void KvsObject_http::slotDataReadProgress ( int done,int total ) +{ + KviKvsVariantList lParams; + lParams.append(new KviKvsVariant((kvs_int_t) done)); + lParams.append(new KviKvsVariant((kvs_int_t) total)); + callFunction(this,"dataReadProgressEvent",0,&lParams); +} +bool KvsObject_http::functionDataReadProgressEvent(KviKvsObjectFunctionCall *c) +{ + emitSignal("dataReadProgress",c,c->params()); + return true; +} +void KvsObject_http::slotDataSendProgress ( int done,int total ) +{ + KviKvsVariantList lParams; + lParams.append(new KviKvsVariant((kvs_int_t) done)); + lParams.append(new KviKvsVariant((kvs_int_t) total)); + callFunction(this,"dataSendProgressEvent",0,&lParams); +} +bool KvsObject_http::functionDataSendProgressEvent(KviKvsObjectFunctionCall *c) +{ + emitSignal("dataSendProgress",c,c->params()); + return true; +} +bool KvsObject_http::functionDoneEvent(KviKvsObjectFunctionCall *c) +{ + emitSignal("done",c,c->params()); + return true; +} +void KvsObject_http::slotDone ( bool error ) +{ + KviKvsVariantList lParams; + lParams.append(new KviKvsVariant(error)); + callFunction(this,"doneEvent",0,&lParams); +} + +bool KvsObject_http::functionResponseHeaderReceivedEvent(KviKvsObjectFunctionCall *c) +{ + emitSignal("responseHeaderReceived",c,c->params()); + return true; +} +bool KvsObject_http::functionReadyReadEvent(KviKvsObjectFunctionCall *c) +{ + emitSignal("readyRead",c,c->params()); + return true; +} +void KvsObject_http::redirect(QString &file,const QHttpResponseHeader &r) +{ + QUrl url(r.value("location")); + m_pHttp->setHost(url.host()); + QFile *pFile=0; + pFile=new QFile(file); + pFile->open(QIODevice::WriteOnly); + int id=m_pHttp->get(url.path(),pFile); + getDict[id]=pFile; +} + +void KvsObject_http::slotResponseHeaderReceived(const QHttpResponseHeader &r) +{ + QString szResponse; + switch (r.statusCode()) { + case 200: szResponse="Ok" ;break; + case 301: szResponse="Moved Permanently" ;break; + case 302: szResponse="Found" ;break; + case 303: szResponse="See Other" ;break; + case 307: szResponse="Temporary Redirect" ;break; + default: szResponse=r.reasonPhrase(); + m_bAbort=true; + } + if (r.statusCode()==400) + { + m_bAbort=true; + m_pHttp->abort(); + } + KviKvsVariantList lParams; + lParams.append(new KviKvsVariant(szResponse)); + callFunction(this,"responseHeaderReceivedEvent",0,&lParams); + +} +void KvsObject_http::slotReadyRead(const QHttpResponseHeader &r) +{ + QString szResponse; + switch (r.statusCode()) { + case 200: szResponse="Ok" ;break; + case 301: szResponse="Moved Permanently" ;break; + case 302: szResponse="Found" ;break; + case 303: szResponse="See Other" ;break; + case 307: szResponse="Temporary Redirect" ;break; + default: szResponse=r.reasonPhrase(); + m_bAbort=true; + } + KviKvsVariantList lParams; + lParams.append(new KviKvsVariant(szResponse)); + callFunction(this,"readyreadEvent",0,&lParams); +} + + + + +void KvsObject_http::slotStateChanged ( int state) +{ + QString szState=""; + if (state==QHttp::Unconnected) szState="Unconnected"; + else if (state==QHttp::HostLookup) szState="HostLookup"; + else if (state==QHttp::Connecting) szState="Connecting"; + else if (state==QHttp::Connected) szState="Connected"; + else if (state==QHttp::Sending) szState="Sending"; + else if (state==QHttp::Reading) szState="Reading"; + + else if (state==QHttp::Closing) szState="Closing"; + KviKvsVariantList lParams; + lParams.append(new KviKvsVariant(szState)); + callFunction(this,"stateChangedEvent",0,&lParams); +} +bool KvsObject_http::functionStateChangedEvent(KviKvsObjectFunctionCall *c) +{ + emitSignal("stateChanged",c,c->params()); + return true; +} + +#ifndef QT_NO_OPENSSL + +bool KvsObject_http::functionIgnoreSslErrors(KviKvsObjectFunctionCall *) +{ + if (m_pHttp) m_pHttp->ignoreSslErrors(); + return true; +} +void KvsObject_http::slotSslErrors(QList sslerrors) +{ + KviKvsArray *pArray=0; + pArray=new KviKvsArray(); + for(int i=0;iset(i,new KviKvsVariant(ssl_errors_tbl[sslerrors.at(i).error()])); + } + KviKvsVariantList lParams; + lParams.append(new KviKvsVariant(pArray)); + callFunction(this,"sslErrorEvent",0,&lParams); + } + +bool KvsObject_http::functionSslErrorsEvent(KviKvsObjectFunctionCall *c) +{ + + emitSignal("sslErrors",c,c->params()); + return true; +} +#endif +#ifndef COMPILE_USE_STANDALONE_MOC_SOURCES +#include "m_KvsObject_http.moc" +#endif //!COMPILE_USE_STANDALONE_MOC_SOURCES -- cgit v1.3.1-10-gc9f91