draft SCGI client
authorKonrad Rosenbaum <konrad@silmor.de>
Tue, 29 Jan 2013 06:42:02 +0000 (07:42 +0100)
committerKonrad Rosenbaum <konrad@silmor.de>
Tue, 29 Jan 2013 06:42:02 +0000 (07:42 +0100)
examples/clock/README
examples/clock/qtc/clock.cpp
examples/clock/qtc/clock.pro
qtbase/src/interface.cpp
qtbase/src/transaction.cpp
qtbase/src/wobnam.cpp [new file with mode: 0644]
qtbase/src/wobnam.h [new file with mode: 0644]
qtbase/wbase.pro

index b450f44..22b90bb 100644 (file)
@@ -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
+--------
+
index e48c6f2..23e1f85 100644 (file)
@@ -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:"<<args[0].toAscii().data()<<"url...";
+               qDebug()<<"Usage:"<<args[0].toLatin1().data()<<"url...";
                return 1;
        }
        url=args[1];
index cc5d2de..3d750fb 100644 (file)
@@ -2,6 +2,7 @@ TEMPLATE = app
 TARGET = clock
 CONFIG += debug link_prl
 QT += xml network
+contains(QT_MAJOR_VERSION,"5") {QT+=widgets}
 LIBS += -L../../../qtbase -lqwbase
 INCLUDEPATH += ../../../qtbase/include
 
index 57028b0..ce7c553 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2009-2011 by Konrad Rosenbaum <konrad@silmor.de>
+// Copyright (C) 2009-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.
 //
@@ -6,7 +6,6 @@
 #include <WInterface>
 #include <WServer>
 
-// #include <QHttp>
 #include <QMutex>
 #include <QMutexLocker>
 #include <QNetworkAccessManager>
index 85d317d..9e4b196 100644 (file)
@@ -13,7 +13,7 @@
 #include <QDomDocument>
 #include <QDomElement>
 #include <QEventLoop>
-#include <QNetworkAccessManager>
+// #include <QNetworkAccessManager>
 #include <QNetworkReply>
 #include <QNetworkRequest>
 #include <QStringList>
diff --git a/qtbase/src/wobnam.cpp b/qtbase/src/wobnam.cpp
new file mode 100644 (file)
index 0000000..853b2d9
--- /dev/null
@@ -0,0 +1,205 @@
+// 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.
+//
+
+#include "wobnam.h"
+
+#include <QSslSocket>
+
+#include <stdlib.h>
+
+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<QSslError>)),
+                       this,SIGNAL(sslErrors(QList<QSslError>)));
+               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<QSslSocket*>(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<QByteArray>&hnames=req.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');
+       }
+       //generate netstring from headers
+       head.prepend(QByteArray::number(head.size())+":");
+       head.append(",");
+       //send it
+       sock->write(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(pos<inhead.size() && cn<2 && (inhead[pos]=='\r' || inhead[pos]=='\n')){
+                       if(inhead[pos]=='\n')cn++;
+                       pos++;
+               }
+               incontent=inhead.mid(pos);
+               inhead=inhead.left(pos).trimmed();
+               //switch mode
+               readMode=ContentRead;
+               //parse headers
+               const QList<QByteArray>heads=inhead.split('\n');
+               for(int i=0;i<heads.size();i++){
+                       const QByteArray head=heads[i].trimmed();
+                       pos=head.indexOf(':');
+                       if(pos<0)continue;
+                       setRawHeader(head.left(pos).trimmed(),head.mid(pos+1).trimmed());
+               }
+       }else{
+               incontent+=sock->read(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 (file)
index 0000000..a80f151
--- /dev/null
@@ -0,0 +1,55 @@
+// 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_H
+#define WOB_NAM_H
+
+
+#include <QNetworkAccessManager>
+#include <QNetworkReply>
+#include <QNetworkRequest>
+#include <QTcpSocket>
+
+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
index 6135f30..3f942cf 100644 (file)
@@ -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