From: Konrad Rosenbaum Date: Thu, 31 Jan 2013 21:23:32 +0000 (+0100) Subject: fix server and finish the SCGI client for Qt X-Git-Url: http://git.silmor.de/gitweb/?a=commitdiff_plain;h=4afd47ebbbe2324b13ed6c7a4dacdf5d7b59544b;p=web%2Fkonrad%2Fpack.git fix server and finish the SCGI client for Qt --- diff --git a/qtbase/include/interface.h b/qtbase/include/interface.h index f65d866..8085a1f 100644 --- a/qtbase/include/interface.h +++ b/qtbase/include/interface.h @@ -14,12 +14,13 @@ #include -class QNetworkAccessManager; +class WobNetworkAccessManager; class QNetworkRequest; class QNetworkReply; class WServerRequest; class WServerReply; +/// base class of all interfaces class WInterface:public QObject { Q_OBJECT @@ -135,7 +136,7 @@ class WInterface:public QObject unsigned short m_proxyport; int m_wtimeout; LogLevel loglvl; - QNetworkAccessManager*m_netman; + WobNetworkAccessManager*m_netman; }; #endif diff --git a/qtbase/include/server.h b/qtbase/include/server.h index 3f47861..2e69b67 100644 --- a/qtbase/include/server.h +++ b/qtbase/include/server.h @@ -15,28 +15,42 @@ class QTcpServer; class QLocalServer; class WInterface; +///Encapsulates the request as it comes in via (S)CGI class WServerRequest { public: + ///instantiates an empty request WServerRequest(); + ///copies a request WServerRequest(const WServerRequest&); + ///copies a request WServerRequest& operator=(const WServerRequest&); + ///checks HTTP level header for its existence, in (S)CGI these are prefixed with "HTTP_" -> so hasHeader("Host") checks for the CGI header/variable HTTP_HOST to exist bool hasHeader(const QString&)const; + ///returns true if the given low-level variable/header exists bool hasCgiHeader(const QString&)const; + ///returns the value of the given HTTP level header QByteArray header(const QString&)const; + ///returns the value of the given low-level variable/header QByteArray cgiHeader(const QString&)const; - + ///returns the request body, or an empty array if there was none QByteArray bodyData()const; + ///returns true if this is a valid SCGI request bool isValid()const; + ///dumps the request in a human readable format QByteArray dump()const; + ///returns the path (Request-Uri) that has been requested by the client QString pathInfo()const; + ///returns the (virtual) Host that the client wants to access + QString hostInfo()const; protected: + ///used by WServerReceiver to instantiate requests WServerRequest(const QByteArray&); void setBody(const QByteArray&); friend class WServer; @@ -48,20 +62,29 @@ class WServerRequest }; Q_DECLARE_METATYPE(WServerRequest); +///reply object for the server side: contains the data sent back to the client class WServerReply { public: + ///creates an invalid reply (500 Server Error) WServerReply(); - WServerReply(const WServerReply&); - WServerReply& operator=(const WServerReply&); + ///copies the reply object + WServerReply(const WServerReply&)=default; + ///copies the reply object + WServerReply& operator=(const WServerReply&)=default; + ///sets the return status of the reply bool setStatus(short code,QString str); + ///sets a specific header, Content-Length cannot be overridden bool setHeader(const QString&,const QString&); + ///converts the string to UTF-8 and sets it as the message body void setBody(const QString&); + ///sets the message body and the Content-Length header accordingly void setBody(const QByteArray&); protected: friend class WServer; + /// \internal converts the reply to the SCGI wire format ready to be sent QByteArray toWireFormat()const; private: short mStatCode; @@ -70,31 +93,65 @@ class WServerReply }; /** Represents an SCGI server as a proxy to server side interfaces. + * + * Use the cgi2scgi helper to translate between CGI and SCGI. */ class WServer:public QObject { Q_OBJECT public: - WServer(const QString&,QObject*parent=0); - WServer(const QHostAddress&,unsigned short,QObject*parent=0); - virtual ~WServer(); + /** creates a new server listening to a local socket + * + * \param path the (file) name of the socket (or named pipe on Windows) + * \param removeIfExist if true the socket file is removed before trying to create it again (this is a good idea on Unix/Linux, since existing sockets cannot be created) + * \param parent the owning QObject of this server */ + WServer(const QString&path,bool removeIfExist=true,QObject*parent=0); + /** creates a new server listening to a TCP socket + * + * \param addr the address to listen on + * \param port the TCP port to listen on + * \param parent owning QObject of this server */ + WServer(const QHostAddress&addr,unsigned short port,QObject*parent=0); + ///deletes the server object + virtual ~WServer()=default; + ///returns true if this is a working server (i.e. the constructor did not have errors) bool isActive()const{return tcpserv!=0 || locserv!=0;} + ///returns the current receive timeout in seconds + ///this is the time that a request has to be completely received int receiveTimeout()const{return mrecvtimeout;} + public slots: - void registerInterface(const QString&,WInterface*); - void registerStatic(const QString&,const QString&); + /** registers an interface to handle a specific path + * + * \param path the relative path inside the server's address space + * \param ifc the interface that handles this path */ + void registerInterface(const QString&path,WInterface*ifc); + /** registers a specific content to be served on a path + * + * \param path the relative path inside the server's address space + * \param content the page content to deliver */ + void registerStatic(const QString&path,const QString&content); + ///deletes whatever registration exists at a specific path void unregisterPath(const QString&); + ///registers a custom page for a 404 Not Found error void register404(const QString&); + ///registers a custom page for a 400 Invalid Request error void register400(const QString&); + ///sets the receive timeout of the server void setReceiveTimeout(int); + ///restricts the hosts that can connect to this server void restrictSourceHosts(const QPair&); + ///enable or disable the /debug path, if enabled a request at that path simply returns the content of the request as a response void enableDebugUrl(bool enable=true); private slots: + /// \internal called when a new connection is available void newConnection(); + /// \internal creates a WServerReceiver object to receive and parse the connection void handleConnection(QIODevice*); + /// \internal called to actually handle requests once they are fully received void handleRequest(WServerRequest,QIODevice*); private: void handleRequestHelper(WServerRequest,QIODevice*); diff --git a/qtbase/src/interface.cpp b/qtbase/src/interface.cpp index ce7c553..fcc2f6d 100644 --- a/qtbase/src/interface.cpp +++ b/qtbase/src/interface.cpp @@ -8,11 +8,12 @@ #include #include -#include #include #include #include +#include "wobnam.h" + QMap WInterface::inst; static QMutex mtx(QMutex::Recursive); @@ -34,7 +35,7 @@ WInterface::WInterface(QString name) delete inst[name]; } inst.insert(name,this); - m_netman=new QNetworkAccessManager(this); + m_netman=new WobNetworkAccessManager(this); connect(m_netman,SIGNAL(sslErrors(QNetworkReply*,QList)), this,SLOT(sslErrors(QNetworkReply*,QList))); } diff --git a/qtbase/src/server.cpp b/qtbase/src/server.cpp index dc0ee0c..81f3162 100644 --- a/qtbase/src/server.cpp +++ b/qtbase/src/server.cpp @@ -14,18 +14,22 @@ #include #include #include +#include static int metaid=qRegisterMetaType(); #define ERR404 "

Path does not exist

\nSorry, the path you requested does not exist.\n" #define ERR400 "

Invalid Request

\nSorry, the request was invalid.\n" -WServer::WServer(const QString&path,QObject*parent) +WServer::WServer(const QString&path,bool removeIfExist,QObject*parent) :QObject(parent) { mrecvtimeout=30000; tcpserv=0; mdebugenabled=false; + if(removeIfExist){ + QFile::remove(path); + } locserv=new QLocalServer(this); if(!locserv->listen(path)){ qDebug()<<"Error creating server socket on path"<hasPendingConnections()){ QTcpSocket*sock=tcpserv->nextPendingConnection(); - qDebug()<<"new TCP connection from"<peerAddress()<<"port"<peerPort(); +// qDebug()<<"new TCP connection from"<peerAddress()<<"port"<peerPort(); if(sourcehost.second>0){ if(!sock->peerAddress().isInSubnet(sourcehost)){ sock->close(); sock->deleteLater(); - qDebug()<<"dropping TCP connection"; +// qDebug()<<"dropping TCP connection"; continue; } } @@ -125,7 +126,7 @@ void WServer::newConnection() } if(locserv!=0){ while(locserv->hasPendingConnections()){ - qDebug()<<"new Local connection"; +// qDebug()<<"new Local connection"; handleConnection(locserv->nextPendingConnection()); } } @@ -152,16 +153,18 @@ static bool qstringlonger(const QString&s1,const QString&s2) void WServer::handleRequestHelper(WServerRequest rq,QIODevice*sock) { +// qDebug()<<"handling request for host"<write(QByteArray("Status: 400 Invalid Request\r\nContent-Type: text/html; charset=utf-8\r\n\r\n")+err400.toUtf8()); return; } QString path=rq.pathInfo(); //check for debug mode if(mdebugenabled && pathMatch("/debug",path)){ - qDebug()<<"debug: dumping request data as response"; +// qDebug()<<"debug: dumping request data as response"; sock->write(QByteArray("Status: 200 Ok\r\nContent-Type: text/plain\r\n\r\n")); sock->write(rq.dump()); return; @@ -174,21 +177,21 @@ void WServer::handleRequestHelper(WServerRequest rq,QIODevice*sock) if(pathMatch(k[i],path)){ //find a static match if(statcontent.contains(k[i])){ - qDebug()<<"returning static content"; +// qDebug()<<"returning static content"; sock->write(QByteArray("Status: 200 Ok\r\nContent-Type: text/html; charset=utf-8\r\n\r\n")); sock->write(statcontent[k[i]].toUtf8()); return; }else //find dynamic match if(iface.contains(k[i])){ - qDebug()<<"returning dynamic content"; +// qDebug()<<"returning dynamic content"; WServerReply rp=iface[k[i]]->execute(rq); sock->write(rp.toWireFormat()); return; } } //no match, send a 404 - qDebug()<<"no match found, sending 404"; +// qDebug()<<"no match found, sending 404"; sock->write(QByteArray("Status: 404 File not found\r\nContent-Type: text/html; charset=utf-8\r\n\r\n")+err404.toUtf8()); } void WServer::handleRequest(WServerRequest rq,QIODevice*sock) @@ -261,10 +264,14 @@ QByteArray WServerRequest::cgiHeader(const QString&h)const } QString WServerRequest::pathInfo()const { - QString p=QString::fromLatin1(cgiHeader("PATH_INFO")); + QString p=QString::fromLatin1(cgiHeader("Request-Uri")); if(p=="")return "/"; else return p; } +QString WServerRequest::hostInfo()const +{ + return QString::fromLatin1(header("Host")); +} QByteArray WServerRequest::bodyData()const { return mbody; @@ -292,18 +299,6 @@ WServerReply::WServerReply() mStatCode=500; mStatStr="Internal Error"; } -WServerReply::WServerReply(const WServerReply&r) -{ - operator=(r); -} -WServerReply& WServerReply::operator=(const WServerReply&r) -{ - mStatCode=r.mStatCode; - mStatStr=r.mStatStr; - mBody=r.mBody; - mHead=r.mHead; - return *this; -} bool WServerReply::setStatus(short code,QString str) { //check the return code @@ -390,7 +385,7 @@ void WServerReceiver::receiveMore() //read qint64 ba=sock->bytesAvailable(); if(ba<=0)return; - qDebug()<<"reading next"<read(ba); //interpret if(mode==StartMode){ @@ -399,7 +394,7 @@ void WServerReceiver::receiveMore() explen=buffer.left(p).toInt(); buffer=buffer.mid(p+1); mode=HeaderMode; - qDebug()<<"proceeding to header of size"<explen){//this is not an off-by-one, see below request.setBody(buffer.mid(1,explen)); - qDebug()<<"body completed"; +// qDebug()<<"body completed"; mode=Completed; } } //check for completion if(mode==Completed){ - qDebug()<<"request completed, now handling it"; +// qDebug()<<"request completed, now handling it"; emit readyForProcess(request,sock); sock=0; deleteLater(); diff --git a/qtbase/src/server_p.h b/qtbase/src/server_p.h index 96e278c..c763aac 100644 --- a/qtbase/src/server_p.h +++ b/qtbase/src/server_p.h @@ -8,16 +8,23 @@ #include "server.h" +/// \internal helper class for WServer - helps with receiving and parsing SCGI requests class WServerReceiver:public QObject { Q_OBJECT public: - WServerReceiver(WServer*,QIODevice*); + ///constructs a new receiver + /// \param srv the server this receiver belongs to + /// \param sock the socket to handle + WServerReceiver(WServer*srv,QIODevice*sock); + ///deletes the receiver object and its socket if it had an error or timeout virtual ~WServerReceiver(); - public slots: + private slots: + /// \internal helper to receive data void receiveMore(); signals: + ///returns the completely parsed request back to the server to handle it void readyForProcess(WServerRequest,QIODevice*); private: diff --git a/qtbase/src/transaction.cpp b/qtbase/src/transaction.cpp index 9e4b196..b239a1b 100644 --- a/qtbase/src/transaction.cpp +++ b/qtbase/src/transaction.cpp @@ -93,8 +93,9 @@ void WTransaction_Private::startQuery(QString hreq,QByteArray data) QUrl url=iface->url(); int port=url.port(); if(port<=0){ - if(url.scheme().toLower()=="http")port=80; - else port=443; + const QString&s=url.scheme().toLower(); + if(s=="http")port=80; + else if(s=="https")port=443; } if(m_log)m_log->setInfo(QString("New HTTP Request %1 URL %2\n\tto host=%3 port=%4 scheme=%5") .arg(hreq) diff --git a/qtbase/src/wobnam.cpp b/qtbase/src/wobnam.cpp index 853b2d9..f8923dd 100644 --- a/qtbase/src/wobnam.cpp +++ b/qtbase/src/wobnam.cpp @@ -4,11 +4,20 @@ // #include "wobnam.h" +#include "wobnam_p.h" -#include +#include +#include +#include #include +WobNetworkAccessManager::WobNetworkAccessManager(QObject* parent) + : QNetworkAccessManager(parent) +{ +} + + static inline QByteArray translateOperation(QNetworkAccessManager::Operation op) { switch(op){ @@ -25,39 +34,44 @@ QNetworkReply* WobNetworkAccessManager::createRequest(QNetworkAccessManager::Ope { //check whether it is scgi or scgissl QUrl url=req.url(); - if(url.scheme()=="scgi" || url.scheme()=="scgissl"){ + if(url.scheme()=="scgi" || url.scheme()=="scgissl" || url.scheme()=="scgilocal"){ return new WobScgiNetworkReplyImpl(req,translateOperation(op),outgoingData,this); } return QNetworkAccessManager::createRequest(op, req, outgoingData); } -QNetworkReply* WobNetworkAccessManager::QNetworkAccessManager::sendCustomRequest(const QNetworkRequest& req, const QByteArray& op, QIODevice* data) +QNetworkReply* WobNetworkAccessManager::sendCustomRequest(const QNetworkRequest& req, const QByteArray& op, QIODevice* data) { //check whether it is scgi or scgissl QUrl url=req.url(); - if(url.scheme()=="scgi" || url.scheme()=="scgissl"){ + if(url.scheme()=="scgi" || url.scheme()=="scgissl" || url.scheme()=="scgilocal"){ return new WobScgiNetworkReplyImpl(req,op,data,this); } return QNetworkAccessManager::sendCustomRequest(req, op, data); } -WobScgiNetworkReplyImpl::WobScgiNetworkReplyImpl(const QNetworkRequest& req_, QByteArray op_, QIODevice* input, QObject* parent) - : QNetworkReply(parent),req(req_),op(op_) +WobScgiNetworkReplyImpl::WobScgiNetworkReplyImpl(QNetworkRequest req, QByteArray op_, QIODevice* input, QObject* parent) + : QNetworkReply(parent),op(op_) { + setRequest(req); offset=0; readMode=HeadRead; + setOpenMode(QIODevice::ReadOnly|QIODevice::Unbuffered); + //get input + if(input)incontent=input->readAll(); //create connection if(req.url().scheme()=="scgi"){ - sock=new QTcpSocket(this); - connect(sock,SIGNAL(error(QAbstractSocket::SocketError)), + QTcpSocket* tsock=new QTcpSocket(this); + sock=tsock; + connect(tsock,SIGNAL(error(QAbstractSocket::SocketError)), this,SLOT(sockerror(QAbstractSocket::SocketError))); - connect(sock,SIGNAL(connected()), + connect(tsock,SIGNAL(connected()), this,SLOT(startwrite())); - connect(sock,SIGNAL(disconnected()), + connect(tsock,SIGNAL(disconnected()), this,SLOT(sockabort())); - sock->connectToHost(req.url().host(),req.url().port(9080)); - }else{ + tsock->connectToHost(req.url().host(),req.url().port(9080)); + }else if(req.url().scheme()=="scgissl"){ QSslSocket *ssock=new QSslSocket(this); sock=ssock; connect(sock,SIGNAL(error(QAbstractSocket::SocketError)), @@ -68,11 +82,29 @@ WobScgiNetworkReplyImpl::WobScgiNetworkReplyImpl(const QNetworkRequest& req_, QB this,SLOT(startwrite())); connect(sock,SIGNAL(disconnected()), this,SLOT(sockabort())); - sock->connectToHost(req.url().host(),req.url().port(9443)); + ssock->connectToHostEncrypted(req.url().host(),req.url().port(9443)); + }else{ + //create socket + QLocalSocket *lsock=new QLocalSocket(this); + sock=lsock; + connect(lsock,SIGNAL(error(QLocalSocket::LocalSocketError)), + this,SLOT(lsockerror(QLocalSocket::LocalSocketError))); + connect(lsock,SIGNAL(connected()), + this,SLOT(startwrite())); + connect(lsock,SIGNAL(disconnected()), + this,SLOT(sockabort())); + //parse url + QUrl url=req.url(); + QUrlQuery query(url); + const QString path=query.queryItemValue("_lpath_"); + query.removeQueryItem("_lpath_"); + url.setQuery(query); + req.setUrl(url); + setRequest(req); + //connnect + lsock->connectToServer(path); } connect(sock,SIGNAL(readyRead()),this,SLOT(sockread())); - //get input - if(input)incontent=input->readAll(); } @@ -87,6 +119,19 @@ qint64 WobScgiNetworkReplyImpl::readData(char* data, qint64 maxSize) return mmax; } +qint64 WobScgiNetworkReplyImpl::bytesAvailable() const +{ + return outcontent.size()-offset; +} + +qint64 WobScgiNetworkReplyImpl::size()const +{ + return outcontent.size(); +} + +void WobScgiNetworkReplyImpl::abort(){QNetworkReply::close();} +void WobScgiNetworkReplyImpl::close(){QNetworkReply::close();} + void WobScgiNetworkReplyImpl::ignoreSslErrors() { QSslSocket *ssock=qobject_cast(sock); @@ -100,18 +145,19 @@ void WobScgiNetworkReplyImpl::startwrite() head.append('\0').append(QByteArray::number(incontent.size())).append('\0'); head.append("SCGI").append('\0').append("1").append('\0'); head.append("REQUEST_METHOD").append('\0').append(op).append('\0'); - QByteArray uri=req.url().toString(QUrl::RemoveScheme|QUrl::RemoveAuthority|QUrl::EncodeSpaces|QUrl::RemoveFragment).toLatin1(); + const QUrl url=request().url(); + QByteArray uri=url.toString(QUrl::RemoveScheme|QUrl::RemoveAuthority|QUrl::EncodeSpaces|QUrl::RemoveFragment).toLatin1(); head.append("REQUEST_URI").append('\0').append(uri).append('\0'); - head.append("HOST").append('\0').append(req.url().host()).append('\0'); + head.append("HTTP_HOST").append('\0').append(url.host()).append('\0'); //generate remaining headers - const QList&hnames=req.rawHeaderList(); + const QList&hnames=request().rawHeaderList(); for(int i=0;iread(avl); + outcontent+=sock->read(avl); emit downloadProgress(incontent.size(),header(QNetworkRequest::ContentLengthHeader).toLongLong()); } + //are we done yet? + if(readMode==ContentRead){ + qint64 len=header(QNetworkRequest::ContentLengthHeader).toInt(); + if(len>0 && outcontent.size()>=len){ + finishUp(); + } + } } void WobScgiNetworkReplyImpl::sockabort() @@ -162,7 +221,7 @@ void WobScgiNetworkReplyImpl::sockabort() sockread(); //now go in peace sock->close(); - emit finished(); + finishUp(); } static inline QNetworkReply::NetworkError translateError(QAbstractSocket::SocketError err) @@ -201,5 +260,34 @@ static inline QNetworkReply::NetworkError translateError(QAbstractSocket::Socket void WobScgiNetworkReplyImpl::sockerror(QAbstractSocket::SocketError err) { + if(err==QAbstractSocket::RemoteHostClosedError && readMode==ContentRead){ + finishUp(); + return; + } + qDebug()<<"WobScgiNetworkReplyImpl received network socket error"<<(int)err; + emit error(translateError(err)); +} + +static inline QNetworkReply::NetworkError translateError(QLocalSocket::LocalSocketError err) +{ + return translateError((QAbstractSocket::SocketError)err); +} + +void WobScgiNetworkReplyImpl::lsockerror(QLocalSocket::LocalSocketError err) +{ + if(err==QLocalSocket::PeerClosedError && readMode==ContentRead){ + qint64 len=header(QNetworkRequest::ContentLengthHeader).toLongLong(); + if(len<=0)setRawHeader("Content-Length",QByteArray::number(outcontent.size())); + finishUp(); + return; + } + qDebug()<<"WobScgiNetworkReplyImpl received local socket error"<<(int)err; emit error(translateError(err)); +} + +void WobScgiNetworkReplyImpl::finishUp() +{ + if(isFinished())return; + setFinished(true); + emit finished(); } \ No newline at end of file diff --git a/qtbase/src/wobnam.h b/qtbase/src/wobnam.h index a80f151..580443a 100644 --- a/qtbase/src/wobnam.h +++ b/qtbase/src/wobnam.h @@ -8,48 +8,29 @@ #include -#include -#include -#include - +class QNetworkReply; + +/** Extended version of QNetworkAccessManager that can handle SCGI directly. + * + * This is used by PACK to be able to connect to Qt based PACK servers directly + * instead of tunneling through a web server and/or CGI. + * + * URL formats: + * scgi://host:port/path -> TCP + * scgissl://host:port/path -> SSL + * scgilocal://dummyhost/path?_lpath_=/path/to/sock -> local socket, the socket path name is encoded in the _lpath_ attribute + */ class WobNetworkAccessManager:public QNetworkAccessManager { protected: + ///creates a request for a standard operation virtual QNetworkReply * createRequest(Operation op, const QNetworkRequest & req, QIODevice * outgoingData = 0); public: + ///creates a new Network Access Manager + explicit WobNetworkAccessManager(QObject* parent = 0); + ///creates a request with a custom operation virtual QNetworkReply * sendCustomRequest(const QNetworkRequest & request, const QByteArray & verb, QIODevice * data = 0); }; -class WobScgiNetworkReplyImpl:public QNetworkReply -{ -public: - WobScgiNetworkReplyImpl(const QNetworkRequest&,QByteArray op,QIODevice*, QObject* parent); - void abort(){} - qint64 bytesAvailable() const {return outcontent.size()-offset;} - bool isSequential() const{return true;} - -public slots: - virtual void ignoreSslErrors(); - -protected: - qint64 readData(char *data, qint64 maxSize); - -private slots: - void sockerror(QAbstractSocket::SocketError); - void startwrite(); - void sockabort(); - void sockread(); - -private: - QByteArray outcontent,incontent,inhead; - qint64 offset; - QNetworkRequest req; - QTcpSocket*sock; - QByteArray op; - - enum ReadMode {HeadRead,ContentRead}readMode; -}; - - #endif \ No newline at end of file diff --git a/qtbase/src/wobnam_p.h b/qtbase/src/wobnam_p.h new file mode 100644 index 0000000..2434cd2 --- /dev/null +++ b/qtbase/src/wobnam_p.h @@ -0,0 +1,65 @@ +// Copyright (C) 2013 by Konrad Rosenbaum +// protected under the GNU LGPL version 3 or at your option any newer. +// See COPYING.LGPL file that comes with this distribution. +// + +#ifndef WOB_NAM_P_H +#define WOB_NAM_P_H + + +#include +#include +#include +#include + +/// \internal SCGI client reply +class WobScgiNetworkReplyImpl:public QNetworkReply +{ + Q_OBJECT +public: + /// creates a new reply handler/receiver + WobScgiNetworkReplyImpl(QNetworkRequest,QByteArray op,QIODevice*, QObject* parent); + ///abort the reception (just closes the stream, does not actually abort anything yet) + void abort()override; + ///closes the reply stream, call this only if you are no longer interested in the answer + void close()override; + ///returns the amount of body data available to be read + qint64 bytesAvailable() const override; + bool isSequential() const override{return true;} + ///returns the complete size of the body + qint64 size()const override; + +public slots: + ///relays SSL errors + virtual void ignoreSslErrors()override; + +protected: + ///implementation of reading body data + qint64 readData(char *data, qint64 maxSize) override; + +private slots: + /// \internal TCP socket errors + void sockerror(QAbstractSocket::SocketError); + /// \internal Local socket errors + void lsockerror(QLocalSocket::LocalSocketError); + /// \internal starts writing request data + void startwrite(); + /// \internal the connection was aborted/closed by the peer + void sockabort(); + /// \internal more response data available for reading + void sockread(); + +private: + QByteArray outcontent,incontent,inhead; + qint64 offset; + QIODevice*sock; + QByteArray op; + + enum ReadMode {HeadRead,ContentRead}readMode; + + /// \internal helper to finish the response and signal the owner + void finishUp(); +}; + + +#endif \ No newline at end of file diff --git a/qtbase/wbase.pro b/qtbase/wbase.pro index 3f942cf..570fde4 100644 --- a/qtbase/wbase.pro +++ b/qtbase/wbase.pro @@ -23,7 +23,8 @@ HEADERS += \ include/interface.h \ include/server.h \ src/server_p.h \ - src/wobnam.h + src/wobnam.h \ + src/wobnam_p.h SOURCES += \ src/object.cpp \ @@ -34,4 +35,6 @@ SOURCES += \ src/wobnam.cpp INCLUDEPATH += include src -DEPENDPATH += include src \ No newline at end of file +DEPENDPATH += include src + +*g++* { QMAKE_CXXFLAGS += -std=c++11 } \ No newline at end of file