aboutsummaryrefslogtreecommitdiffstats
path: root/lib/JsonScgiServer.cpp
blob: 8b0f6ad6eec9a063045e5e9062902933e03de918 (plain) (blame)
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;
	}
}