mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2024-10-22 10:46:04 +03:00
Improve connection handling
1. Previously unhandled connections will stay in pending state. It won't be closed until timeout happened. This may lead to wasting system resources. Now the (over-limit) connection is actively rejected. 2. When out-of-memory occurs here, reject the new connection instead of throwing exception and crash. 3. Also clean up some unused bits. PR #20961.
This commit is contained in:
parent
c2cf898ccd
commit
0f5a27ed50
5 changed files with 32 additions and 34 deletions
|
@ -40,7 +40,6 @@
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
|
|
||||||
#include "base/algorithm.h"
|
|
||||||
#include "base/exceptions.h"
|
#include "base/exceptions.h"
|
||||||
#include "base/global.h"
|
#include "base/global.h"
|
||||||
#include "base/logger.h"
|
#include "base/logger.h"
|
||||||
|
|
|
@ -44,6 +44,7 @@ Connection::Connection(QTcpSocket *socket, IRequestHandler *requestHandler, QObj
|
||||||
, m_requestHandler(requestHandler)
|
, m_requestHandler(requestHandler)
|
||||||
{
|
{
|
||||||
m_socket->setParent(this);
|
m_socket->setParent(this);
|
||||||
|
connect(m_socket, &QAbstractSocket::disconnected, this, &Connection::closed);
|
||||||
|
|
||||||
// reserve common size for requests, don't use the max allowed size which is too big for
|
// reserve common size for requests, don't use the max allowed size which is too big for
|
||||||
// memory constrained platforms
|
// memory constrained platforms
|
||||||
|
@ -62,11 +63,6 @@ Connection::Connection(QTcpSocket *socket, IRequestHandler *requestHandler, QObj
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Connection::~Connection()
|
|
||||||
{
|
|
||||||
m_socket->close();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Connection::read()
|
void Connection::read()
|
||||||
{
|
{
|
||||||
// reuse existing buffer and avoid unnecessary memory allocation/relocation
|
// reuse existing buffer and avoid unnecessary memory allocation/relocation
|
||||||
|
@ -182,11 +178,6 @@ bool Connection::hasExpired(const qint64 timeout) const
|
||||||
&& m_idleTimer.hasExpired(timeout);
|
&& m_idleTimer.hasExpired(timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Connection::isClosed() const
|
|
||||||
{
|
|
||||||
return (m_socket->state() == QAbstractSocket::UnconnectedState);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Connection::acceptsGzipEncoding(QString codings)
|
bool Connection::acceptsGzipEncoding(QString codings)
|
||||||
{
|
{
|
||||||
// [rfc7231] 5.3.4. Accept-Encoding
|
// [rfc7231] 5.3.4. Accept-Encoding
|
||||||
|
|
|
@ -47,10 +47,11 @@ namespace Http
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Connection(QTcpSocket *socket, IRequestHandler *requestHandler, QObject *parent = nullptr);
|
Connection(QTcpSocket *socket, IRequestHandler *requestHandler, QObject *parent = nullptr);
|
||||||
~Connection();
|
|
||||||
|
|
||||||
bool hasExpired(qint64 timeout) const;
|
bool hasExpired(qint64 timeout) const;
|
||||||
bool isClosed() const;
|
|
||||||
|
signals:
|
||||||
|
void closed();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static bool acceptsGzipEncoding(QString codings);
|
static bool acceptsGzipEncoding(QString codings);
|
||||||
|
|
|
@ -32,7 +32,10 @@
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <memory>
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
#include <QtLogging>
|
||||||
#include <QNetworkProxy>
|
#include <QNetworkProxy>
|
||||||
#include <QSslCipher>
|
#include <QSslCipher>
|
||||||
#include <QSslConfiguration>
|
#include <QSslConfiguration>
|
||||||
|
@ -40,7 +43,6 @@
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
#include "base/algorithm.h"
|
|
||||||
#include "base/global.h"
|
#include "base/global.h"
|
||||||
#include "base/utils/net.h"
|
#include "base/utils/net.h"
|
||||||
#include "base/utils/sslkey.h"
|
#include "base/utils/sslkey.h"
|
||||||
|
@ -113,32 +115,38 @@ Server::Server(IRequestHandler *requestHandler, QObject *parent)
|
||||||
|
|
||||||
void Server::incomingConnection(const qintptr socketDescriptor)
|
void Server::incomingConnection(const qintptr socketDescriptor)
|
||||||
{
|
{
|
||||||
if (m_connections.size() >= CONNECTIONS_LIMIT) return;
|
std::unique_ptr<QTcpSocket> serverSocket = m_https ? std::make_unique<QSslSocket>(this) : std::make_unique<QTcpSocket>(this);
|
||||||
|
|
||||||
QTcpSocket *serverSocket = nullptr;
|
|
||||||
if (m_https)
|
|
||||||
serverSocket = new QSslSocket(this);
|
|
||||||
else
|
|
||||||
serverSocket = new QTcpSocket(this);
|
|
||||||
|
|
||||||
if (!serverSocket->setSocketDescriptor(socketDescriptor))
|
if (!serverSocket->setSocketDescriptor(socketDescriptor))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (m_connections.size() >= CONNECTIONS_LIMIT)
|
||||||
{
|
{
|
||||||
delete serverSocket;
|
qWarning("Too many connections. Exceeded CONNECTIONS_LIMIT (%d). Connection closed.", CONNECTIONS_LIMIT);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
if (m_https)
|
if (m_https)
|
||||||
{
|
{
|
||||||
static_cast<QSslSocket *>(serverSocket)->setProtocol(QSsl::SecureProtocols);
|
auto *sslSocket = static_cast<QSslSocket *>(serverSocket.get());
|
||||||
static_cast<QSslSocket *>(serverSocket)->setPrivateKey(m_key);
|
sslSocket->setProtocol(QSsl::SecureProtocols);
|
||||||
static_cast<QSslSocket *>(serverSocket)->setLocalCertificateChain(m_certificates);
|
sslSocket->setPrivateKey(m_key);
|
||||||
static_cast<QSslSocket *>(serverSocket)->setPeerVerifyMode(QSslSocket::VerifyNone);
|
sslSocket->setLocalCertificateChain(m_certificates);
|
||||||
static_cast<QSslSocket *>(serverSocket)->startServerEncryption();
|
sslSocket->setPeerVerifyMode(QSslSocket::VerifyNone);
|
||||||
|
sslSocket->startServerEncryption();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto *c = new Connection(serverSocket, m_requestHandler, this);
|
auto *connection = new Connection(serverSocket.release(), m_requestHandler, this);
|
||||||
m_connections.insert(c);
|
m_connections.insert(connection);
|
||||||
connect(serverSocket, &QAbstractSocket::disconnected, this, [c, this]() { removeConnection(c); });
|
connect(connection, &Connection::closed, this, [this, connection] { removeConnection(connection); });
|
||||||
|
}
|
||||||
|
catch (const std::bad_alloc &exception)
|
||||||
|
{
|
||||||
|
// drop the connection instead of throwing exception and crash
|
||||||
|
qWarning("Failed to allocate memory for HTTP connection. Connection closed.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Server::removeConnection(Connection *connection)
|
void Server::removeConnection(Connection *connection)
|
||||||
|
|
|
@ -39,7 +39,6 @@
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
#include "base/algorithm.h"
|
|
||||||
#include "base/bittorrent/session.h"
|
#include "base/bittorrent/session.h"
|
||||||
#include "base/bittorrent/torrent.h"
|
#include "base/bittorrent/torrent.h"
|
||||||
#include "base/bittorrent/trackerentrystatus.h"
|
#include "base/bittorrent/trackerentrystatus.h"
|
||||||
|
|
Loading…
Reference in a new issue