From 6620180edff3e7081441818a68118ffa0747778d Mon Sep 17 00:00:00 2001 From: Konrad Rosenbaum Date: Tue, 29 Jan 2013 07:42:02 +0100 Subject: [PATCH] draft SCGI client --- examples/clock/README | 17 +++- examples/clock/qtc/clock.cpp | 2 +- examples/clock/qtc/clock.pro | 1 + qtbase/src/interface.cpp | 3 +- qtbase/src/transaction.cpp | 2 +- qtbase/src/wobnam.cpp | 205 ++++++++++++++++++++++++++++++++++++++++++ qtbase/src/wobnam.h | 55 +++++++++++ qtbase/wbase.pro | 6 +- 8 files changed, 283 insertions(+), 8 deletions(-) create mode 100644 qtbase/src/wobnam.cpp create mode 100644 qtbase/src/wobnam.h diff --git a/examples/clock/README b/examples/clock/README index b450f44..22b90bb 100644 --- a/examples/clock/README +++ b/examples/clock/README @@ -10,7 +10,20 @@ phpc - PHP based client phps - PHP based server You need Apache or another CGI or SCGI capable web server for the server -examples. +examples if you want to connect the client using HTTP. Please read the documentation on how to install servers. -The examples are in the public domain - you can use them however you want. \ No newline at end of file +The examples are in the public domain - you can use them however you want. + +Compiling +---------- + +In this directory call: ../../woc/woc ./clock.wolf + +Qt examples: cd qt? ; qmake && make + +PHP: copy the subdirectory to a directory that the web server has access to. + +Running +-------- + diff --git a/examples/clock/qtc/clock.cpp b/examples/clock/qtc/clock.cpp index e48c6f2..23e1f85 100644 --- a/examples/clock/qtc/clock.cpp +++ b/examples/clock/qtc/clock.cpp @@ -91,7 +91,7 @@ int main(int argc,char**argv) //parse arguments, we expect the URL... QStringList args=app.arguments(); if(args.size()<2){ - qDebug()<<"Usage:"< +// Copyright (C) 2009-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. // @@ -6,7 +6,6 @@ #include #include -// #include #include #include #include diff --git a/qtbase/src/transaction.cpp b/qtbase/src/transaction.cpp index 85d317d..9e4b196 100644 --- a/qtbase/src/transaction.cpp +++ b/qtbase/src/transaction.cpp @@ -13,7 +13,7 @@ #include #include #include -#include +// #include #include #include #include diff --git a/qtbase/src/wobnam.cpp b/qtbase/src/wobnam.cpp new file mode 100644 index 0000000..853b2d9 --- /dev/null +++ b/qtbase/src/wobnam.cpp @@ -0,0 +1,205 @@ +// 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. +// + +#include "wobnam.h" + +#include + +#include + +static inline QByteArray translateOperation(QNetworkAccessManager::Operation op) +{ + switch(op){ + case QNetworkAccessManager::HeadOperation:return "HEAD"; + case QNetworkAccessManager::GetOperation:return "GET"; + case QNetworkAccessManager::PutOperation:return "PUT"; + case QNetworkAccessManager::PostOperation:return "POST"; + case QNetworkAccessManager::DeleteOperation:return "DELETE"; + default:return "NOOP"; + } +} + +QNetworkReply* WobNetworkAccessManager::createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest& req, QIODevice* outgoingData) +{ + //check whether it is scgi or scgissl + QUrl url=req.url(); + if(url.scheme()=="scgi" || url.scheme()=="scgissl"){ + 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) +{ + //check whether it is scgi or scgissl + QUrl url=req.url(); + if(url.scheme()=="scgi" || url.scheme()=="scgissl"){ + 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_) +{ + offset=0; + readMode=HeadRead; + //create connection + if(req.url().scheme()=="scgi"){ + sock=new QTcpSocket(this); + connect(sock,SIGNAL(error(QAbstractSocket::SocketError)), + this,SLOT(sockerror(QAbstractSocket::SocketError))); + connect(sock,SIGNAL(connected()), + this,SLOT(startwrite())); + connect(sock,SIGNAL(disconnected()), + this,SLOT(sockabort())); + sock->connectToHost(req.url().host(),req.url().port(9080)); + }else{ + QSslSocket *ssock=new QSslSocket(this); + sock=ssock; + connect(sock,SIGNAL(error(QAbstractSocket::SocketError)), + this,SLOT(sockerror(QAbstractSocket::SocketError))); + connect(ssock,SIGNAL(sslErrors(QList)), + this,SIGNAL(sslErrors(QList))); + connect(ssock,SIGNAL(encrypted()), + this,SLOT(startwrite())); + connect(sock,SIGNAL(disconnected()), + this,SLOT(sockabort())); + sock->connectToHost(req.url().host(),req.url().port(9443)); + } + connect(sock,SIGNAL(readyRead()),this,SLOT(sockread())); + //get input + if(input)incontent=input->readAll(); +} + + +qint64 WobScgiNetworkReplyImpl::readData(char* data, qint64 maxSize) +{ + if(data==0)return 0; + qint64 mmax=bytesAvailable(); + if(mmax>maxSize)mmax=maxSize; + if(mmax<=0)return mmax; + memcpy(data,outcontent.constData()+offset,mmax); + offset+=mmax; + return mmax; +} + +void WobScgiNetworkReplyImpl::ignoreSslErrors() +{ + QSslSocket *ssock=qobject_cast(sock); + if(ssock)ssock->ignoreSslErrors(); +} + +void WobScgiNetworkReplyImpl::startwrite() +{ + //generate basic headers + QByteArray head="CONTENT_LENGTH"; + 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(); + head.append("REQUEST_URI").append('\0').append(uri).append('\0'); + head.append("HOST").append('\0').append(req.url().host()).append('\0'); + //generate remaining headers + const QList&hnames=req.rawHeaderList(); + for(int i=0;iwrite(head); + sock->write(incontent); +} + +void WobScgiNetworkReplyImpl::sockread() +{ + qint64 avl=sock->bytesAvailable(); + if(avl<1)return; + if(readMode==HeadRead){ + inhead+=sock->read(avl); + //check for body + int pos=inhead.indexOf("\r\n\r\n"); + if(pos<0)pos=inhead.indexOf("\n\n"); + if(pos<0)return; + //ok split it + int cn=0; + while(posheads=inhead.split('\n'); + for(int i=0;iread(avl); + emit downloadProgress(incontent.size(),header(QNetworkRequest::ContentLengthHeader).toLongLong()); + } +} + +void WobScgiNetworkReplyImpl::sockabort() +{ + //received a socketclosed signal + //just in case: read remainder + sockread(); + //now go in peace + sock->close(); + emit finished(); +} + +static inline QNetworkReply::NetworkError translateError(QAbstractSocket::SocketError err) +{ + switch(err){ + case QAbstractSocket::ConnectionRefusedError: + return QNetworkReply::ConnectionRefusedError; + case QAbstractSocket::RemoteHostClosedError: + return QNetworkReply::RemoteHostClosedError; + case QAbstractSocket::HostNotFoundError: + return QNetworkReply::HostNotFoundError; + + case QAbstractSocket::ProxyAuthenticationRequiredError: + return QNetworkReply::ProxyAuthenticationRequiredError; + + case QAbstractSocket::ProxyConnectionRefusedError: + return QNetworkReply::ProxyConnectionRefusedError; + case QAbstractSocket::ProxyConnectionClosedError: + return QNetworkReply::ProxyConnectionClosedError; + case QAbstractSocket::ProxyConnectionTimeoutError: + return QNetworkReply::ProxyTimeoutError; + case QAbstractSocket::ProxyNotFoundError: + return QNetworkReply::ProxyNotFoundError; + case QAbstractSocket::ProxyProtocolError: + return QNetworkReply::UnknownProxyError; + + case QAbstractSocket::SslHandshakeFailedError: + case QAbstractSocket::SslInternalError: + case QAbstractSocket::SslInvalidUserDataError: + return QNetworkReply::SslHandshakeFailedError; + + default: + return QNetworkReply::UnknownNetworkError; + } +} + +void WobScgiNetworkReplyImpl::sockerror(QAbstractSocket::SocketError err) +{ + emit error(translateError(err)); +} \ No newline at end of file diff --git a/qtbase/src/wobnam.h b/qtbase/src/wobnam.h new file mode 100644 index 0000000..a80f151 --- /dev/null +++ b/qtbase/src/wobnam.h @@ -0,0 +1,55 @@ +// 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_H +#define WOB_NAM_H + + +#include +#include +#include +#include + +class WobNetworkAccessManager:public QNetworkAccessManager +{ +protected: + virtual QNetworkReply * createRequest(Operation op, const QNetworkRequest & req, QIODevice * outgoingData = 0); +public: + 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/wbase.pro b/qtbase/wbase.pro index 6135f30..3f942cf 100644 --- a/qtbase/wbase.pro +++ b/qtbase/wbase.pro @@ -22,14 +22,16 @@ HEADERS += \ include/transaction_p.h \ include/interface.h \ include/server.h \ - src/server_p.h + src/server_p.h \ + src/wobnam.h SOURCES += \ src/object.cpp \ src/helper.cpp \ src/transaction.cpp \ src/interface.cpp \ - src/server.cpp + src/server.cpp \ + src/wobnam.cpp INCLUDEPATH += include src DEPENDPATH += include src \ No newline at end of file -- 1.7.2.5