1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
|
/*
* Copyright (C) 2012 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*
* See COPYING for license information.
*
*/
#include "JsonScgiServer.h"
#include <ctime>
#include <QtCore/QTimer>
JsonScgiServer::JsonScgiServer(QObject *parent) :
QObject(parent)
{
qsrand(time(0) + 42);
connect(&m_listener, SIGNAL(newConnection()), this, SLOT(newConnection()));
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(cleanOldSessions()));
timer->setSingleShot(false);
timer->start(1000 * 60 * 1);
}
bool JsonScgiServer::listen(const QHostAddress &address, quint16 port)
{
return m_listener.listen(address, port);
}
void JsonScgiServer::newWebRequest(const QUrl &url, QString &sessionCookie, const QVariantMap &request, JsonScgiPeer &peer)
{
if (sessionCookie.isEmpty())
sessionCookie = randomString(); // Create the session if there isn't one yet.
if (!m_sessions.contains(sessionCookie) && m_sessions.size() > 8192) {
// We abruptly cut off if there are already too many sessions. A silly way to prevent from memory DoS.
peer.die();
return;
}
Session &session = m_sessions[sessionCookie];
if (!isSessionValid(session)) {
session.expiration = QDateTime();
session.data.clear();
}
if (!session.expiration.isValid() || qAbs(session.expiration.secsTo(QDateTime::currentDateTimeUtc())) < 60 * 60)
session.expiration = QDateTime::currentDateTimeUtc().addSecs(60 * 60); //Default expiration: 1 hour
emit webRequest(url, session, request, peer);
}
QDateTime JsonScgiServer::cookieExpiration(const QString &cookie) const
{
if (!m_sessions.contains(cookie))
return QDateTime();
return m_sessions[cookie].expiration;
}
QString JsonScgiServer::randomString(int size) const
{
static const char alphanum[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
QString str(size, 0);
for (int i = 0; i < size; ++i) // Not perfect, but I don't actually care.
str[i] = alphanum[qrand() % (sizeof(alphanum) - 1)];
return str;
}
bool JsonScgiServer::isSessionValid(const JsonScgiServer::Session &session) const
{
if (session.expiration.isNull())
return false;
return session.expiration > QDateTime::currentDateTimeUtc();
}
void JsonScgiServer::newConnection()
{
while (m_listener.hasPendingConnections())
new JsonScgiPeer(m_listener.nextPendingConnection(), this);
}
void JsonScgiServer::cleanOldSessions()
{
for (QHash<QString, Session>::iterator i = m_sessions.begin(); i != m_sessions.end();) {
if (!isSessionValid(i.value()) || i.value().data.size() == 0)
i = m_sessions.erase(i);
else
++i;
}
}
|