summaryrefslogtreecommitdiff
path: root/webproxyconn.cc
diff options
context:
space:
mode:
authorJavier <dev.git@javispedro.com>2015-12-15 02:42:46 +0100
committerJavier <dev.git@javispedro.com>2015-12-15 02:42:46 +0100
commit2bb9a14110d909af1894426d456237bfc0b60ad4 (patch)
tree71ac5a40e0d0934ead3ceff120e9201b7a61d686 /webproxyconn.cc
parent5abd8e0359cfa1dc2437427f2f0446d8801441cb (diff)
downloadsapd-2bb9a14110d909af1894426d456237bfc0b60ad4.tar.gz
sapd-2bb9a14110d909af1894426d456237bfc0b60ad4.zip
implement the WebProxy agent
Diffstat (limited to 'webproxyconn.cc')
-rw-r--r--webproxyconn.cc160
1 files changed, 145 insertions, 15 deletions
diff --git a/webproxyconn.cc b/webproxyconn.cc
index 1eb4909..d1590ca 100644
--- a/webproxyconn.cc
+++ b/webproxyconn.cc
@@ -1,7 +1,9 @@
#include <QtCore/QDebug>
+#include <QtCore/QUrl>
#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<quint8>(data, offset);
msg.subCommand = read<quint8>(data, offset);
- msg.type = static_cast<RequestMessageType>(read<quint8>(data, offset));
+ msg.type = static_cast<MessageType>(read<quint8>(data, offset));
msg.transactionId = read<quint8>(data, offset);
const quint32 len = read<quint32>(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<quint8>(data, msg.command);
+ append<quint8>(data, msg.subCommand);
+ append<quint8>(data, msg.type);
+ append<quint8>(data, msg.transactionId);
+ append<quint32>(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<WebProxyTrans*>(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<WebProxyTrans*>(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();
+}