From a45977185a485624095bff1a15024e9199eee676 Mon Sep 17 00:00:00 2001 From: Javier Date: Fri, 1 Jan 2016 22:05:42 +0100 Subject: reorganize source files into SAP and agents --- agents/webproxyconn.cc | 187 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 agents/webproxyconn.cc (limited to 'agents/webproxyconn.cc') diff --git a/agents/webproxyconn.cc b/agents/webproxyconn.cc new file mode 100644 index 0000000..91a9510 --- /dev/null +++ b/agents/webproxyconn.cc @@ -0,0 +1,187 @@ +#include +#include + +#include "sappeer.h" +#include "endianhelpers.h" +#include "webproxytrans.h" +#include "webproxyconn.h" + +WebProxyConn::WebProxyConn(SAPConnection *conn, QObject *parent) + : QObject(parent), _conn(conn), + _in(conn->getSocket(501)), _out(conn->getSocket(502)) +{ + connect(_conn, SIGNAL(disconnected()), SLOT(deleteLater())); + connect(_conn, SIGNAL(destroyed()), SLOT(deleteLater())); + Q_ASSERT(_in && _out); + connect(_in, SIGNAL(messageReceived()), SLOT(handleMessageReceived())); +} + +WebProxyConn::Message WebProxyConn::unpackMessage(const QByteArray &data) +{ + Message msg; + int offset = 0; + msg.command = read(data, offset); + msg.subCommand = read(data, offset); + msg.type = static_cast(read(data, offset)); + msg.transactionId = read(data, offset); + + const quint32 len = read(data, offset); + msg.payload = data.mid(offset, len); + + return msg; +} + +QByteArray WebProxyConn::packMessage(const Message &msg) +{ + 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; + + 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::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" << msg.transactionId << "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, but if it was a CONNECT request. + if (hdr.connect) { + payload = removeHeaders(payload); + } + + _trans.insert(msg.transactionId, trans); + } + + if (!payload.isEmpty()) { + 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(); + Message msg = unpackMessage(data); + + if (msg.command != 1 || msg.subCommand != 1) { + qWarning() << "Invalid command/subcommand: " << msg.command << "/" << msg.subCommand; + return; + } + + switch (msg.type) { + case MessageRequest: + handleRequest(msg); + break; + case MessageAbort: + handleAbort(msg); + break; + default: + 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; + + 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