From d703e48f497a2ae17205373a8345586c693808aa Mon Sep 17 00:00:00 2001 From: Szymon Tomasz Stefanek Date: Thu, 30 Dec 2010 02:45:58 +0000 Subject: The http request now uses Qt sockets. git-svn-id: https://svn.kvirc.de/svn/trunk/kvirc@5269 17fca916-40b9-46aa-a4ea-0a15b648b75c --- src/kvilib/net/KviHttpRequestThread.cpp | 619 -------------------------------- 1 file changed, 619 deletions(-) delete mode 100644 src/kvilib/net/KviHttpRequestThread.cpp (limited to 'src/kvilib/net/KviHttpRequestThread.cpp') diff --git a/src/kvilib/net/KviHttpRequestThread.cpp b/src/kvilib/net/KviHttpRequestThread.cpp deleted file mode 100644 index 88258dde5..000000000 --- a/src/kvilib/net/KviHttpRequestThread.cpp +++ /dev/null @@ -1,619 +0,0 @@ -//============================================================================= -// -// File : KviHttpRequestThread.cpp -// Creation date : Sat Aug 17 13:43:32 2002 GMT by Szymon Stefanek -// -// This file is part of the KVIrc irc client distribution -// Copyright (C) 2002-2010 Szymon Stefanek (pragma at kvirc dot net) -// -// 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 "KviHttpRequestThread.h" -#include "KviHttpRequest.h" - -#include "KviLocale.h" -#include "KviNetUtils.h" -#include "KviError.h" -#include "KviTimeUtils.h" -#include "KviDataBuffer.h" - -#include "kvi_debug.h" -#include "kvi_socket.h" - -#ifdef COMPILE_SSL_SUPPORT - #include "KviSSL.h" -#endif - -//#include - - -KviHttpRequestThread::KviHttpRequestThread( - KviHttpRequest * r, - const QString &szHost, - const QString &szIp, - unsigned short uPort, - const QString & szPath, - unsigned int uContentOffset, - RequestMethod m, - const QString &szPostData, - bool bUseSSL - ) : KviSensitiveThread() -{ - m_pRequest = r; - m_szHost = szHost; - m_szIp = szIp; - m_szPath = szPath; - m_uPort = uPort > 0 ? uPort : 80; - m_uContentOffset = uContentOffset; - m_eRequestMethod = m; - m_szPostData = szPostData; - m_sock = KVI_INVALID_SOCKET; - m_bUseSSL = bUseSSL; - m_uConnectionTimeout = 60; -#ifdef COMPILE_SSL_SUPPORT - m_pSSL = 0; -#endif -} - -KviHttpRequestThread::~KviHttpRequestThread() -{ -} - -bool KviHttpRequestThread::processInternalEvents() -{ - while(KviThreadEvent *e = dequeueEvent()) - { - switch(e->id()) - { - case KVI_THREAD_EVENT_TERMINATE: - { - delete e; - return false; - } - break; - default: - qDebug("Unrecognized event in http thread"); - delete e; - return false; - break; - } - } - - return true; -} - -bool KviHttpRequestThread::failure(const char *error) -{ - if(error) - { - postEvent(m_pRequest,new KviThreadDataEvent(KVI_THREAD_EVENT_ERROR,new KviCString(error))); - } /*else { - postEvent(m_pRequest,new KviThreadDataEvent(KVI_THREAD_EVENT_ERROR,new KviCString(__tr2qs("Aborted")))); - }*/ - return false; -} - -bool KviHttpRequestThread::selectForWrite(int iTimeoutInSecs) -{ - - kvi_time_t startTime = kvi_unixTime(); - - for(;;) - { - if(!processInternalEvents()) - { - return failure(0); - } - - fd_set writeSet; - - FD_ZERO(&writeSet); - - FD_SET(m_sock,&writeSet); - - struct timeval tmv; - tmv.tv_sec = 0; - tmv.tv_usec = 1000; // we wait 1000 usecs for an event - - - int nRet = kvi_socket_select(m_sock + 1,0,&writeSet,0,&tmv); - - if(nRet > 0) - { - if(FD_ISSET(m_sock,&writeSet)) - { - // connected! - return true; - } - } else { - if(nRet < 0) - { - int err = kvi_socket_error(); -#if defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW) - if((err != EAGAIN) && (err != EINTR) && (err != WSAEWOULDBLOCK)) -#else - if((err != EAGAIN) && (err != EINTR)) -#endif - { - return failure(KviError::getUntranslatedDescription(KviError::translateSystemError(err))); - } - } - } - - - if((time(0) - startTime) > iTimeoutInSecs) - return failure(__tr_no_lookup("Operation timed out")); - - usleep(100000); // 1/10 sec - } - - return false; -} - -bool KviHttpRequestThread::sslFailure() -{ -#ifdef COMPILE_SSL_SUPPORT - KviCString buffer; - if(m_pSSL->getLastErrorString(buffer)) - { - failure(buffer.ptr()); - } else { - failure(__tr_no_lookup("Unexpected SSL error")); - } -#endif - return false; -} - -bool KviHttpRequestThread::connectToRemoteHost() -{ - m_sock = kvi_socket_create(KVI_SOCKET_PF_INET,KVI_SOCKET_TYPE_STREAM,0); //tcp - if(m_sock == KVI_INVALID_SOCKET) - return failure(__tr_no_lookup("Failed to create the socket")); - - if(!kvi_socket_setNonBlocking(m_sock)) - return failure(__tr_no_lookup("Failed to enter non blocking mode")); - - sockaddr_in saddr; - - if(!KviNetUtils::stringIpToBinaryIp(m_szIp,&(saddr.sin_addr))) - return failure(__tr_no_lookup("Invalid target address")); - - saddr.sin_port = htons(m_uPort); - saddr.sin_family = AF_INET; - - if(!kvi_socket_connect(m_sock,(struct sockaddr *)&saddr,sizeof(saddr))) - { - int err = kvi_socket_error(); - if(!kvi_socket_recoverableConnectError(err)) - { - return failure(KviError::getUntranslatedDescription(KviError::translateSystemError(err))); - } - } - - // now loop selecting for write - - if(!selectForWrite(m_uConnectionTimeout)) - return false; - - int sockError; - int iSize = sizeof(sockError); - if(!kvi_socket_getsockopt(m_sock,SOL_SOCKET,SO_ERROR,(void *)&sockError,&iSize))sockError = -1; - if(sockError != 0) - { - //failed - KviError::Code eError; - if(sockError > 0) - eError = KviError::translateSystemError(sockError); - else - eError = KviError::UnknownError; - return failure(KviError::getUntranslatedDescription(eError)); - } - -#ifdef COMPILE_SSL_SUPPORT - if(m_bUseSSL) - { - m_pSSL = new KviSSL(); - if(!m_pSSL->initContext(KviSSL::Client)) - return failure(__tr_no_lookup("Failed to initialize the SSL context")); - if(!m_pSSL->initSocket(m_sock)) - return failure(__tr_no_lookup("Failed to initialize the SSL connection")); - - for(;;) - { - switch(m_pSSL->connect()) - { - case KviSSL::Success: - // done: connected. - return true; - break; - case KviSSL::WantRead: - if(!selectForRead(m_uConnectionTimeout)) - return false; - break; - case KviSSL::WantWrite: - if(!selectForWrite(m_uConnectionTimeout)) - return false; - break; - case KviSSL::RemoteEndClosedConnection: - return failure(__tr_no_lookup("Remote end has closed the connection")); - break; - case KviSSL::SSLError: - return sslFailure(); - break; - case KviSSL::SyscallError: - { - // syscall problem - int err = kvi_socket_error(); - if(!kvi_socket_recoverableError(err)) - { - // Declare problems :) - return failure(__tr_no_lookup("Unrecoverable SSL error during handshake")); - } // else can recover ? (EAGAIN, EINTR ?) ... should select for read or for write - } - break; - default: - return sslFailure(); - break; - } - } - - // never here - return true; - } -#endif - - return true; -} - - -bool KviHttpRequestThread::sendBuffer(const char * buffer,int bufLen,int iTimeoutInSecs) -{ - const char * ptr = buffer; - int curLen = bufLen; - - time_t startTime = time(0); - - for(;;) - { - if(!processInternalEvents()) - return failure(); - - int wrtn; -#ifdef COMPILE_SSL_SUPPORT - if(m_pSSL) - { - wrtn = m_pSSL->write((char *)ptr,curLen); - } else { -#endif - wrtn = kvi_socket_send(m_sock,ptr,curLen); -#ifdef COMPILE_SSL_SUPPORT - } -#endif - - if(wrtn > 0) - { - curLen -= wrtn; - - if(curLen <= 0) - break; - - ptr += wrtn; - } else { - if(wrtn < 0) - { -#ifdef COMPILE_SSL_SUPPORT - if(m_pSSL) - { - // ops...might be an SSL error - switch(m_pSSL->getProtocolError(wrtn)) - { - case KviSSL::WantWrite: - if(!selectForWrite(m_uConnectionTimeout)) - return false; - break; - case KviSSL::WantRead: - if(!selectForRead(m_uConnectionTimeout)) - return false; - break; - case KviSSL::SyscallError: - if(wrtn == 0) - { - return failure(__tr_no_lookup("Remote end has closed the connection")); - } else { - int iSSLErr = m_pSSL->getLastError(true); - if(iSSLErr != 0) - { - return sslFailure(); - } else { - goto handle_system_error; - } - } - break; - case KviSSL::SSLError: - return sslFailure(); - break; - default: - return sslFailure(); - break; - } - } else { -#endif //COMPILE_SSL_SUPPORT - -handle_system_error: - int err = kvi_socket_error(); -#if defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW) - if((err != EAGAIN) && (err != EINTR) && (err != WSAEWOULDBLOCK)) -#else - if((err != EAGAIN) && (err != EINTR)) -#endif - { - return failure(KviError::getUntranslatedDescription(KviError::translateSystemError(err))); - } -#ifdef COMPILE_SSL_SUPPORT - } -#endif - } - } - - int diff = time(0) - startTime; - if(diff > iTimeoutInSecs) - return failure(__tr_no_lookup("Operation timed out")); - - usleep(10000); - } - - return true; -} - -int KviHttpRequestThread::selectForReadStep() -{ - // calls select on the main socket - // returns 1 if there is data available for reading - // returns 0 if there is no data available but there was no error - // returns -1 if there was a critical error (socket closed) - fd_set readSet; - - FD_ZERO(&readSet); - - FD_SET(m_sock,&readSet); - - struct timeval tmv; - tmv.tv_sec = 0; - tmv.tv_usec = 1000; // we wait 1000 usecs for an event - - - int nRet = kvi_socket_select(m_sock + 1,&readSet,0,0,&tmv); - - if(nRet > 0) - { - if(FD_ISSET(m_sock,&readSet)) - { - // ok - return 1; - } - } else { - if(nRet < 0) - { - int err = kvi_socket_error(); -#if defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW) - if((err != EAGAIN) && (err != EINTR) && (err != WSAEWOULDBLOCK)) -#else - if((err != EAGAIN) && (err != EINTR)) -#endif - { - failure(KviError::getUntranslatedDescription(KviError::translateSystemError(err))); - return -1; - } - } - } - - return 0; -} - -bool KviHttpRequestThread::selectForRead(int iTimeoutInSecs) -{ - // waits for some data to arrive on the socket - // up to iTimeoutInSecs seconds - // returns true if data is available on the socket - // or false if there was a select() error or no data - // was available in the specified amount of time - - time_t startTime = time(0); - - for(;;) - { - if(!processInternalEvents()) - { - return failure(); // ensure that the socket is closed - } - - int nRet = selectForReadStep(); - - if(nRet < 0)return false; - if(nRet > 0)return true; - - int diff = time(0) - startTime; - if(diff > iTimeoutInSecs) - return failure(__tr_no_lookup("Operation timed out (while selecting for read)")); - - usleep(100000); // 1/10 sec - } - - return false; -} - -bool KviHttpRequestThread::readDataStep() -{ - unsigned char buffer[2048]; - int readed; - - -#ifdef COMPILE_SSL_SUPPORT - if(m_pSSL) - { - readed = m_pSSL->read((char *)buffer,2048); - if(readed <= 0) - { - // ssl error....? - switch(m_pSSL->getProtocolError(readed)) - { - case KviSSL::ZeroReturn: - readed = 0; - break; - case KviSSL::WantRead: - return selectForRead(m_uConnectionTimeout); - break; - case KviSSL::WantWrite: - return selectForWrite(m_uConnectionTimeout); - break; - case KviSSL::SyscallError: - { - int iE = m_pSSL->getLastError(true); - if(iE != 0)return sslFailure(); - } - break; - case KviSSL::SSLError: - return sslFailure(); - break; - default: - return sslFailure(); - break; - } - } - } else { -#endif - readed = kvi_socket_read(m_sock,buffer,2048); -#ifdef COMPILE_SSL_SUPPORT - } -#endif - - if(readed > 0) - { - postEvent(m_pRequest,new KviThreadDataEvent(KVI_THREAD_EVENT_BINARYDATA,new KviDataBuffer(readed,buffer))); - } else { - if(readed < 0) - { - // Read error ? - int err = kvi_socket_error(); -#if defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW) - if((err != EAGAIN) && (err != EINTR) && (err != WSAEWOULDBLOCK)) -#else - if((err != EAGAIN) && (err != EINTR)) -#endif - { - // yes...read error - return failure(KviError::getUntranslatedDescription(KviError::translateSystemError(err))); - } - return selectForRead(m_uConnectionTimeout); // EINTR or EAGAIN...transient problem - } else { - // readed == 0 - // Connection closed by remote host - postEvent(m_pRequest,new KviThreadEvent(KVI_THREAD_EVENT_SUCCESS)); - return false; - } - } - return selectForRead(m_uConnectionTimeout); -} - -void KviHttpRequestThread::run() -{ - // setup: - // nothing needed - - // run: - runInternal(); - - // cleanup: -#ifdef COMPILE_SSL_SUPPORT - if(m_pSSL) - { - delete m_pSSL; - m_pSSL = 0; - } -#endif - - if(kvi_socket_isValid(m_sock)) - { - kvi_socket_close(m_sock); - m_sock = KVI_INVALID_SOCKET; - } -} - -void KviHttpRequestThread::runInternal() -{ -#ifndef COMPILE_SSL_SUPPORT - if(m_bUseSSL) - { - failure(__tr_no_lookup("This KVIrc executable has no SSL support")); - return; - } -#endif - - if(!connectToRemoteHost())return; - - postEvent(m_pRequest,new KviThreadEvent(KVI_HTTP_REQUEST_THREAD_EVENT_CONNECTED)); - - // FIXME: Other headers ? - - KviCString szMethod; - switch(m_eRequestMethod) - { - case Head: szMethod = "HEAD"; break; - case Post: szMethod = "POST"; break; - case Get: szMethod = "GET"; break; - } - - KviCString szRequest(KviCString::Format,"%s %s HTTP/1.1\r\n" \ - "Host: %s\r\n" \ - "Connection: Close\r\n" \ - "User-Agent: KVIrc-http-slave/1.0.0\r\n" \ - "Accept: */*\r\n", - szMethod.ptr(),KviQString::toUtf8(m_szPath).data(),KviQString::toUtf8(m_szHost).data()); - - if(m_uContentOffset > 0) - szRequest.append(KviCString::Format,"Range: bytes=%u-\r\n",m_uContentOffset); - - if(m_eRequestMethod == Post) - { - szRequest.append(KviCString::Format,"Content-Type: application/x-www-form-urlencoded\r\n" \ - "Content-Length: %u\r\n" \ - "Cache-control: no-cache\r\n" \ - "Pragma: no-cache\r\n",m_szPostData.length()); - } - - szRequest += "\r\n"; - - if(m_eRequestMethod == Post) - { - if(!m_szPostData.isEmpty()) - szRequest.append(m_szPostData); - szRequest += "\r\n"; - } - - //qDebug("SENDING REQUEST:\n%s",szRequest.ptr()); - - if(!sendBuffer(szRequest.ptr(),szRequest.len(),60))return; - - // now loop reading data - postEvent(m_pRequest,new KviThreadDataEvent(KVI_HTTP_REQUEST_THREAD_EVENT_REQUESTSENT,new QString(szRequest))); - - for(;;) - { - if(!readDataStep())return; - } -} - -- cgit v1.3.1-10-gc9f91