#include <WOb>
-class QNetworkAccessManager;
+class WobNetworkAccessManager;
class QNetworkRequest;
class QNetworkReply;
class WServerRequest;
class WServerReply;
+/// base class of all interfaces
class WInterface:public QObject
{
Q_OBJECT
unsigned short m_proxyport;
int m_wtimeout;
LogLevel loglvl;
- QNetworkAccessManager*m_netman;
+ WobNetworkAccessManager*m_netman;
};
#endif
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;
};
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;
};
/** 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<QHostAddress,int>&);
+ ///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*);
#include <QMutex>
#include <QMutexLocker>
-#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QNetworkProxy>
+#include "wobnam.h"
+
QMap<QString,WInterface*> WInterface::inst;
static QMutex mtx(QMutex::Recursive);
delete inst[name];
}
inst.insert(name,this);
- m_netman=new QNetworkAccessManager(this);
+ m_netman=new WobNetworkAccessManager(this);
connect(m_netman,SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)), this,SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
}
#include <QTcpServer>
#include <QTcpSocket>
#include <QTimer>
+#include <QFile>
static int metaid=qRegisterMetaType<WServerRequest>();
#define ERR404 "<h1>Path does not exist</h1>\nSorry, the path you requested does not exist.\n"
#define ERR400 "<h1>Invalid Request</h1>\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"<<path;
err404=ERR404;
err400=ERR400;
}
-WServer::~WServer()
-{
-}
void WServer::enableDebugUrl(bool enable){mdebugenabled=enable;}
if(tcpserv!=0){
while(tcpserv->hasPendingConnections()){
QTcpSocket*sock=tcpserv->nextPendingConnection();
- qDebug()<<"new TCP connection from"<<sock->peerAddress()<<"port"<<sock->peerPort();
+// qDebug()<<"new TCP connection from"<<sock->peerAddress()<<"port"<<sock->peerPort();
if(sourcehost.second>0){
if(!sock->peerAddress().isInSubnet(sourcehost)){
sock->close();
sock->deleteLater();
- qDebug()<<"dropping TCP connection";
+// qDebug()<<"dropping TCP connection";
continue;
}
}
}
if(locserv!=0){
while(locserv->hasPendingConnections()){
- qDebug()<<"new Local connection";
+// qDebug()<<"new Local connection";
handleConnection(locserv->nextPendingConnection());
}
}
void WServer::handleRequestHelper(WServerRequest rq,QIODevice*sock)
{
+// qDebug()<<"handling request for host"<<rq.hostInfo()<<"path"<<rq.pathInfo();
+// qDebug()<<rq.dump();
//reject invalid requests outright
if(!rq.isValid()){
- qDebug()<<"rejecting invalid request with code 400";
+// qDebug()<<"rejecting invalid request with code 400";
sock->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;
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)
}
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;
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
//read
qint64 ba=sock->bytesAvailable();
if(ba<=0)return;
- qDebug()<<"reading next"<<ba<<"bytes";
+// qDebug()<<"reading next"<<ba<<"bytes";
buffer+=sock->read(ba);
//interpret
if(mode==StartMode){
explen=buffer.left(p).toInt();
buffer=buffer.mid(p+1);
mode=HeaderMode;
- qDebug()<<"proceeding to header of size"<<explen;
+// qDebug()<<"proceeding to header of size"<<explen;
}
}
if(mode==HeaderMode){
mode=BodyMode;
else
mode=Completed;
- qDebug()<<"header complete next is"<<explen;
+// qDebug()<<"header complete next is"<<explen;
}
}
if(mode==BodyMode){
if(buffer.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();
#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:
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)
//
#include "wobnam.h"
+#include "wobnam_p.h"
-#include <QSslSocket>
+#include <QStringList>
+#include <QDebug>
+#include <QUrlQuery>
#include <stdlib.h>
+WobNetworkAccessManager::WobNetworkAccessManager(QObject* parent)
+ : QNetworkAccessManager(parent)
+{
+}
+
+
static inline QByteArray translateOperation(QNetworkAccessManager::Operation op)
{
switch(op){
{
//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)),
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();
}
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<QSslSocket*>(sock);
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<QByteArray>&hnames=req.rawHeaderList();
+ const QList<QByteArray>&hnames=request().rawHeaderList();
for(int i=0;i<hnames.size();i++){
const QByteArray hname=hnames[i].toUpper().replace('-','_');
if(hname=="CONTENT_LENGTH" || hname=="SCGI" ||
hname=="REQUEST_METHOD"||hname=="REQUEST_URI" || hname=="HOST")
continue;
- head.append(hname).append('\0');
- head.append(req.rawHeader(hnames[i])).append('\0');
+ head.append("HTTP_"+hname).append('\0');
+ head.append(request().rawHeader(hnames[i])).append('\0');
}
//generate netstring from headers
head.prepend(QByteArray::number(head.size())+":");
if(inhead[pos]=='\n')cn++;
pos++;
}
- incontent=inhead.mid(pos);
+ outcontent=inhead.mid(pos);
inhead=inhead.left(pos).trimmed();
//switch mode
readMode=ContentRead;
const QByteArray head=heads[i].trimmed();
pos=head.indexOf(':');
if(pos<0)continue;
- setRawHeader(head.left(pos).trimmed(),head.mid(pos+1).trimmed());
+ const QString hname=head.left(pos).trimmed();
+ const QString hval=head.mid(pos+1).trimmed();
+ if(hname.toLower()=="status"){
+ setAttribute(QNetworkRequest::HttpStatusCodeAttribute, hval.left(3).toInt());
+ setAttribute(QNetworkRequest::HttpReasonPhraseAttribute, hval.mid(3).trimmed());
+ }else
+ setRawHeader(hname.toLatin1(),hval.toLatin1());
}
}else{
- incontent+=sock->read(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()
sockread();
//now go in peace
sock->close();
- emit finished();
+ finishUp();
}
static inline QNetworkReply::NetworkError translateError(QAbstractSocket::SocketError err)
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
#include <QNetworkAccessManager>
-#include <QNetworkReply>
-#include <QNetworkRequest>
-#include <QTcpSocket>
-
+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
--- /dev/null
+// Copyright (C) 2013 by Konrad Rosenbaum <konrad@silmor.de>
+// 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 <QNetworkReply>
+#include <QNetworkRequest>
+#include <QSslSocket>
+#include <QLocalSocket>
+
+/// \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
include/interface.h \
include/server.h \
src/server_p.h \
- src/wobnam.h
+ src/wobnam.h \
+ src/wobnam_p.h
SOURCES += \
src/object.cpp \
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