From 2bb9a14110d909af1894426d456237bfc0b60ad4 Mon Sep 17 00:00:00 2001 From: Javier Date: Tue, 15 Dec 2015 02:42:46 +0100 Subject: implement the WebProxy agent --- webproxyconn.cc | 160 ++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 145 insertions(+), 15 deletions(-) (limited to 'webproxyconn.cc') diff --git a/webproxyconn.cc b/webproxyconn.cc index 1eb4909..d1590ca 100644 --- a/webproxyconn.cc +++ b/webproxyconn.cc @@ -1,7 +1,9 @@ #include +#include #include "sappeer.h" #include "endianhelpers.h" +#include "webproxytrans.h" #include "webproxyconn.h" WebProxyConn::WebProxyConn(SAPConnection *conn, QObject *parent) @@ -13,13 +15,13 @@ WebProxyConn::WebProxyConn(SAPConnection *conn, QObject *parent) connect(_in, SIGNAL(messageReceived()), SLOT(handleMessageReceived())); } -WebProxyConn::RequestMessage WebProxyConn::unpackRequestMessage(const QByteArray &data) +WebProxyConn::Message WebProxyConn::unpackMessage(const QByteArray &data) { - RequestMessage msg; + Message msg; int offset = 0; msg.command = read(data, offset); msg.subCommand = read(data, offset); - msg.type = static_cast(read(data, offset)); + msg.type = static_cast(read(data, offset)); msg.transactionId = read(data, offset); const quint32 len = read(data, offset); @@ -28,35 +30,163 @@ WebProxyConn::RequestMessage WebProxyConn::unpackRequestMessage(const QByteArray return msg; } -void WebProxyConn::handleStartTransaction(const RequestMessage &msg) +QByteArray WebProxyConn::packMessage(const Message &msg) { - QString req = QString::fromUtf8(msg.payload); + QByteArray data; + append(data, msg.command); + append(data, msg.subCommand); + append(data, msg.type); + append(data, msg.transactionId); + append(data, msg.payload.size()); + data.append(msg.payload); + return data; +} + +WebProxyConn::RequestHeader WebProxyConn::parseRequestHeader(const QByteArray &req) +{ + RequestHeader hdr; + int first = req.indexOf('\n'); + if (first <= 0) { + qWarning() << "Invalid request header"; + return hdr; + } + + QStringList reqLine = QString::fromLatin1(req.mid(0, first).trimmed()).split(' '); + QString method = reqLine.at(0); + + if (QString::compare(method, "connect", Qt::CaseInsensitive) == 0) { + hdr.connect = true; + QStringList host = reqLine.at(1).split(':'); + hdr.host = host.at(0); + hdr.port = host.at(1).toUInt(); + } else { + QUrl url(reqLine.at(1)); + hdr.connect = false; + hdr.host = url.host(QUrl::EncodeUnicode); + if (QString::compare(url.scheme(), "https", Qt::CaseInsensitive) == 0) { + hdr.port = url.port(443); + } else { + hdr.port = url.port(80); + } + } + + return hdr; +} + +QByteArray WebProxyConn::removeHeaders(const QByteArray &req) +{ + int offset = 0; + int next; + qDebug() << req; + qDebug() << "--- end ---"; + + while ((next = req.indexOf('\n', offset)) > 0) { + QByteArray line = req.mid(offset, next - offset).trimmed(); + if (line.isEmpty()) { + return req.mid(next + 1); + } + offset = next + 1; + } + + return QByteArray(); } -void WebProxyConn::handleCancelTransaction(const RequestMessage &msg) +void WebProxyConn::sendMessage(const Message &msg) { + _out->send(packMessage(msg)); +} + +void WebProxyConn::handleRequest(const Message &msg) +{ + QByteArray payload = msg.payload; + WebProxyTrans *trans = _trans.value(msg.transactionId, 0); + + if (!trans) { + RequestHeader hdr = parseRequestHeader(msg.payload); + qDebug() << "Starting transaction to" << hdr.host << hdr.port << (hdr.connect ? "tunnel" : "http"); + trans = new WebProxyTrans(msg.transactionId, hdr.connect, hdr.host, hdr.port, this); + connect(trans, SIGNAL(dataReceived(QByteArray)), this, SLOT(handleTransDataReceived(QByteArray))); + connect(trans, SIGNAL(disconnected()), this, SLOT(handleTransDisconnected())); + + // Discard request body if it was a CONNECT request. + if (hdr.connect) { + payload = removeHeaders(payload); + } + + _trans.insert(msg.transactionId, trans); + } + + if (!payload.isEmpty()) { + qDebug() << "Sending" << msg.transactionId << QString::fromLatin1(payload.mid(0, 30)) << "-"; + trans->write(payload); + } +} + +void WebProxyConn::handleAbort(const Message &msg) +{ + qDebug() << "Abort transaction" << msg.transactionId; + WebProxyTrans *trans = _trans.value(msg.transactionId, 0); + if (trans) { + delete trans; + _trans.remove(msg.transactionId); + } else { + qWarning() << "Transaction" << msg.transactionId << "does not exist"; + } } void WebProxyConn::handleMessageReceived() { QByteArray data = _in->receive(); - RequestMessage req = unpackRequestMessage(data); + Message msg = unpackMessage(data); - if (req.command != 1 || req.subCommand != 1) { - qWarning() << "Invalid command/subcommand: " << req.command << "/" << req.subCommand; + if (msg.command != 1 || msg.subCommand != 1) { + qWarning() << "Invalid command/subcommand: " << msg.command << "/" << msg.subCommand; return; } - switch (req.type) { - case RequestStartTransaction: - handleStartTransaction(req); + switch (msg.type) { + case MessageRequest: + handleRequest(msg); break; - case RequestCancelTransaction: - handleCancelTransaction(req); + case MessageAbort: + handleAbort(msg); break; default: - qWarning() << "Unknown request type" << req.type; + qWarning() << "Unknown request type" << msg.type; } } + +void WebProxyConn::handleTransDataReceived(const QByteArray &data) +{ + WebProxyTrans *trans = static_cast(sender()); + Message msg; + msg.command = 1; + msg.subCommand = 1; + msg.type = MessageResponse; + msg.transactionId = trans->transactionId(); + msg.payload = data; + + qDebug() << "Receiving" << msg.transactionId << QString::fromLatin1(data.mid(0, 30)) << "-"; + + sendMessage(msg); +} + +void WebProxyConn::handleTransDisconnected() +{ + WebProxyTrans *trans = static_cast(sender()); + Message msg; + msg.command = 1; + msg.subCommand = 1; + msg.type = MessageAbort; + msg.transactionId = trans->transactionId(); + msg.payload.clear(); // Empty payload signals disconnection + + qDebug() << "Sending disconnected event"; + + sendMessage(msg); + + _trans.remove(msg.transactionId); + trans->deleteLater(); +} -- cgit v1.2.3