Browse Source

Implement http persistence connection

Max simultaneous connection limit set to 500
This also release allocated memory of Connection instances at runtime instead of at program shutdown.
adaptive-webui-19844
Chocobo1 8 years ago
parent
commit
0b28fb6c6b
  1. 32
      src/base/http/connection.cpp
  2. 8
      src/base/http/connection.h
  3. 34
      src/base/http/server.cpp
  4. 4
      src/base/http/server.h

32
src/base/http/connection.cpp

@ -29,14 +29,14 @@ @@ -29,14 +29,14 @@
* Contact : chris@qbittorrent.org
*/
#include <QTcpSocket>
#include <QDebug>
#include "connection.h"
#include <QRegExp>
#include "types.h"
#include <QTcpSocket>
#include "irequesthandler.h"
#include "requestparser.h"
#include "responsegenerator.h"
#include "irequesthandler.h"
#include "connection.h"
using namespace Http;
@ -46,27 +46,33 @@ Connection::Connection(QTcpSocket *socket, IRequestHandler *requestHandler, QObj @@ -46,27 +46,33 @@ Connection::Connection(QTcpSocket *socket, IRequestHandler *requestHandler, QObj
, m_requestHandler(requestHandler)
{
m_socket->setParent(this);
m_idleTimer.start();
connect(m_socket, SIGNAL(readyRead()), SLOT(read()));
connect(m_socket, SIGNAL(disconnected()), SLOT(deleteLater()));
}
Connection::~Connection()
{
m_socket->close();
}
void Connection::read()
{
m_receivedData.append(m_socket->readAll());
m_idleTimer.restart();
m_receivedData.append(m_socket->readAll());
Request request;
RequestParser::ErrorCode err = RequestParser::parse(m_receivedData, request);
switch (err) {
case RequestParser::IncompleteRequest:
// Partial request waiting for the rest
break;
case RequestParser::BadRequest:
sendResponse(Response(400, "Bad Request"));
m_receivedData.clear();
break;
case RequestParser::NoError:
Environment env;
env.clientAddress = m_socket->peerAddress();
@ -74,6 +80,7 @@ void Connection::read() @@ -74,6 +80,7 @@ void Connection::read()
if (acceptsGzipEncoding(request.headers["accept-encoding"]))
response.headers[HEADER_CONTENT_ENCODING] = "gzip";
sendResponse(response);
m_receivedData.clear();
break;
}
}
@ -81,7 +88,16 @@ void Connection::read() @@ -81,7 +88,16 @@ void Connection::read()
void Connection::sendResponse(const Response &response)
{
m_socket->write(ResponseGenerator::generate(response));
m_socket->disconnectFromHost();
}
bool Connection::hasExpired(const qint64 timeout) const
{
return m_idleTimer.hasExpired(timeout);
}
bool Connection::isClosed() const
{
return (m_socket->state() == QAbstractSocket::UnconnectedState);
}
bool Connection::acceptsGzipEncoding(const QString &encoding)

8
src/base/http/connection.h

@ -33,12 +33,12 @@ @@ -33,12 +33,12 @@
#ifndef HTTP_CONNECTION_H
#define HTTP_CONNECTION_H
#include <QElapsedTimer>
#include <QObject>
#include "types.h"
QT_BEGIN_NAMESPACE
class QTcpSocket;
QT_END_NAMESPACE
namespace Http
{
@ -53,6 +53,9 @@ namespace Http @@ -53,6 +53,9 @@ namespace Http
Connection(QTcpSocket *socket, IRequestHandler *requestHandler, QObject *parent = 0);
~Connection();
bool hasExpired(qint64 timeout) const;
bool isClosed() const;
private slots:
void read();
@ -63,6 +66,7 @@ namespace Http @@ -63,6 +66,7 @@ namespace Http
QTcpSocket *m_socket;
IRequestHandler *m_requestHandler;
QByteArray m_receivedData;
QElapsedTimer m_idleTimer;
};
}

34
src/base/http/server.cpp

@ -30,8 +30,10 @@ @@ -30,8 +30,10 @@
#include "server.h"
#include <QMutableListIterator>
#include <QNetworkProxy>
#include <QStringList>
#include <QTimer>
#ifndef QT_NO_OPENSSL
#include <QSslSocket>
@ -41,6 +43,10 @@ @@ -41,6 +43,10 @@
#include "connection.h"
static const int KEEP_ALIVE_DURATION = 7; // seconds
static const int CONNECTIONS_LIMIT = 500;
static const int CONNECTIONS_SCAN_INTERVAL = 2; // seconds
using namespace Http;
Server::Server(IRequestHandler *requestHandler, QObject *parent)
@ -54,6 +60,10 @@ Server::Server(IRequestHandler *requestHandler, QObject *parent) @@ -54,6 +60,10 @@ Server::Server(IRequestHandler *requestHandler, QObject *parent)
#ifndef QT_NO_OPENSSL
QSslSocket::setDefaultCiphers(safeCipherList());
#endif
QTimer *dropConnectionTimer = new QTimer(this);
connect(dropConnectionTimer, &QTimer::timeout, this, &Server::dropTimedOutConnection);
dropConnectionTimer->start(CONNECTIONS_SCAN_INTERVAL * 1000);
}
Server::~Server()
@ -62,6 +72,8 @@ Server::~Server() @@ -62,6 +72,8 @@ Server::~Server()
void Server::incomingConnection(qintptr socketDescriptor)
{
if (m_connections.size() >= CONNECTIONS_LIMIT) return;
QTcpSocket *serverSocket;
#ifndef QT_NO_OPENSSL
if (m_https)
@ -70,7 +82,11 @@ void Server::incomingConnection(qintptr socketDescriptor) @@ -70,7 +82,11 @@ void Server::incomingConnection(qintptr socketDescriptor)
#endif
serverSocket = new QTcpSocket(this);
if (serverSocket->setSocketDescriptor(socketDescriptor)) {
if (!serverSocket->setSocketDescriptor(socketDescriptor)) {
delete serverSocket;
return;
}
#ifndef QT_NO_OPENSSL
if (m_https) {
static_cast<QSslSocket *>(serverSocket)->setProtocol(QSsl::SecureProtocols);
@ -80,10 +96,20 @@ void Server::incomingConnection(qintptr socketDescriptor) @@ -80,10 +96,20 @@ void Server::incomingConnection(qintptr socketDescriptor)
static_cast<QSslSocket *>(serverSocket)->startServerEncryption();
}
#endif
new Connection(serverSocket, m_requestHandler, this);
Connection *c = new Connection(serverSocket, m_requestHandler, this);
m_connections.append(c);
}
void Server::dropTimedOutConnection()
{
QMutableListIterator<Connection *> i(m_connections);
while (i.hasNext()) {
auto connection = i.next();
if (connection->isClosed() || connection->hasExpired(KEEP_ALIVE_DURATION)) {
delete connection;
i.remove();
}
else {
serverSocket->deleteLater();
}
}

4
src/base/http/server.h

@ -60,10 +60,14 @@ namespace Http @@ -60,10 +60,14 @@ namespace Http
void disableHttps();
#endif
private slots:
void dropTimedOutConnection();
private:
void incomingConnection(qintptr socketDescriptor);
IRequestHandler *m_requestHandler;
QList<Connection *> m_connections; // for tracking persistence connections
#ifndef QT_NO_OPENSSL
QList<QSslCipher> safeCipherList() const;

Loading…
Cancel
Save