--- /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.
+//
+
+#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