mirror of
https://github.com/qbittorrent/qBittorrent
synced 2025-07-13 08:43:08 -07:00
Improve coding style
This commit is contained in:
parent
acad35c5bc
commit
c41df9ffbd
147 changed files with 4454 additions and 2227 deletions
|
@ -77,7 +77,8 @@ namespace
|
|||
QStringMap ret;
|
||||
const QVector<QStringRef> cookies = cookieStr.splitRef(';', QString::SkipEmptyParts);
|
||||
|
||||
for (const auto &cookie : cookies) {
|
||||
for (const auto &cookie : cookies)
|
||||
{
|
||||
const int idx = cookie.indexOf('=');
|
||||
if (idx < 0)
|
||||
continue;
|
||||
|
@ -104,7 +105,8 @@ namespace
|
|||
return QLatin1String("private, max-age=604800"); // 1 week
|
||||
|
||||
if ((contentType == Http::CONTENT_TYPE_CSS)
|
||||
|| (contentType == Http::CONTENT_TYPE_JS)) {
|
||||
|| (contentType == Http::CONTENT_TYPE_JS))
|
||||
{
|
||||
// short interval in case of program update
|
||||
return QLatin1String("private, max-age=43200"); // 12 hrs
|
||||
}
|
||||
|
@ -144,21 +146,25 @@ void WebApplication::sendWebUIFile()
|
|||
if (pathItems.contains(".") || pathItems.contains(".."))
|
||||
throw InternalServerErrorHTTPError();
|
||||
|
||||
if (!m_isAltUIUsed) {
|
||||
if (request().path.startsWith(PATH_PREFIX_ICONS)) {
|
||||
if (!m_isAltUIUsed)
|
||||
{
|
||||
if (request().path.startsWith(PATH_PREFIX_ICONS))
|
||||
{
|
||||
const QString imageFilename {request().path.mid(PATH_PREFIX_ICONS.size())};
|
||||
sendFile(QLatin1String(":/icons/") + imageFilename);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const QString path {
|
||||
const QString path
|
||||
{
|
||||
(request().path != QLatin1String("/")
|
||||
? request().path
|
||||
: QLatin1String("/index.html"))
|
||||
};
|
||||
|
||||
QString localPath {
|
||||
QString localPath
|
||||
{
|
||||
m_rootFolder
|
||||
+ (session() ? PRIVATE_FOLDER : PUBLIC_FOLDER)
|
||||
+ path
|
||||
|
@ -166,22 +172,26 @@ void WebApplication::sendWebUIFile()
|
|||
|
||||
QFileInfo fileInfo {localPath};
|
||||
|
||||
if (!fileInfo.exists() && session()) {
|
||||
if (!fileInfo.exists() && session())
|
||||
{
|
||||
// try to send public file if there is no private one
|
||||
localPath = m_rootFolder + PUBLIC_FOLDER + path;
|
||||
fileInfo.setFile(localPath);
|
||||
}
|
||||
|
||||
if (m_isAltUIUsed) {
|
||||
if (m_isAltUIUsed)
|
||||
{
|
||||
#ifdef Q_OS_UNIX
|
||||
if (!Utils::Fs::isRegularFile(localPath)) {
|
||||
if (!Utils::Fs::isRegularFile(localPath))
|
||||
{
|
||||
status(500, "Internal Server Error");
|
||||
print(tr("Unacceptable file type, only regular file is allowed."), Http::CONTENT_TYPE_TXT);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
while (fileInfo.filePath() != m_rootFolder) {
|
||||
while (fileInfo.filePath() != m_rootFolder)
|
||||
{
|
||||
if (fileInfo.isSymLink())
|
||||
throw InternalServerErrorHTTPError(tr("Symlinks inside alternative UI folder are forbidden."));
|
||||
|
||||
|
@ -198,10 +208,12 @@ void WebApplication::translateDocument(QString &data) const
|
|||
|
||||
int i = 0;
|
||||
bool found = true;
|
||||
while (i < data.size() && found) {
|
||||
while (i < data.size() && found)
|
||||
{
|
||||
QRegularExpressionMatch regexMatch;
|
||||
i = data.indexOf(regex, i, ®exMatch);
|
||||
if (i >= 0) {
|
||||
if (i >= 0)
|
||||
{
|
||||
const QString sourceText = regexMatch.captured(1);
|
||||
const QString context = regexMatch.captured(3);
|
||||
|
||||
|
@ -219,7 +231,8 @@ void WebApplication::translateDocument(QString &data) const
|
|||
data.replace(i, regexMatch.capturedLength(), translation);
|
||||
i += translation.length();
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
found = false; // no more translatable strings
|
||||
}
|
||||
|
||||
|
@ -246,7 +259,8 @@ const Http::Environment &WebApplication::env() const
|
|||
void WebApplication::doProcessRequest()
|
||||
{
|
||||
const QRegularExpressionMatch match = m_apiPathPattern.match(request().path);
|
||||
if (!match.hasMatch()) {
|
||||
if (!match.hasMatch())
|
||||
{
|
||||
sendWebUIFile();
|
||||
return;
|
||||
}
|
||||
|
@ -265,9 +279,11 @@ void WebApplication::doProcessRequest()
|
|||
for (const Http::UploadedFile &torrent : request().files)
|
||||
data[torrent.filename] = torrent.data;
|
||||
|
||||
try {
|
||||
try
|
||||
{
|
||||
const QVariant result = controller->run(action, m_params, data);
|
||||
switch (result.userType()) {
|
||||
switch (result.userType())
|
||||
{
|
||||
case QMetaType::QJsonDocument:
|
||||
print(result.toJsonDocument().toJson(QJsonDocument::Compact), Http::CONTENT_TYPE_JSON);
|
||||
break;
|
||||
|
@ -277,9 +293,11 @@ void WebApplication::doProcessRequest()
|
|||
break;
|
||||
}
|
||||
}
|
||||
catch (const APIError &error) {
|
||||
catch (const APIError &error)
|
||||
{
|
||||
// re-throw as HTTPError
|
||||
switch (error.type()) {
|
||||
switch (error.type())
|
||||
{
|
||||
case APIErrorType::AccessDenied:
|
||||
throw ForbiddenHTTPError(error.message());
|
||||
case APIErrorType::BadData:
|
||||
|
@ -303,7 +321,8 @@ void WebApplication::configure()
|
|||
const bool isAltUIUsed = pref->isAltWebUiEnabled();
|
||||
const QString rootFolder = Utils::Fs::expandPathAbs(
|
||||
!isAltUIUsed ? WWW_FOLDER : pref->getWebUiRootFolder());
|
||||
if ((isAltUIUsed != m_isAltUIUsed) || (rootFolder != m_rootFolder)) {
|
||||
if ((isAltUIUsed != m_isAltUIUsed) || (rootFolder != m_rootFolder))
|
||||
{
|
||||
m_isAltUIUsed = isAltUIUsed;
|
||||
m_rootFolder = rootFolder;
|
||||
m_translatedFiles.clear();
|
||||
|
@ -314,16 +333,19 @@ void WebApplication::configure()
|
|||
}
|
||||
|
||||
const QString newLocale = pref->getLocale();
|
||||
if (m_currentLocale != newLocale) {
|
||||
if (m_currentLocale != newLocale)
|
||||
{
|
||||
m_currentLocale = newLocale;
|
||||
m_translatedFiles.clear();
|
||||
|
||||
m_translationFileLoaded = m_translator.load(m_rootFolder + QLatin1String("/translations/webui_") + newLocale);
|
||||
if (m_translationFileLoaded) {
|
||||
if (m_translationFileLoaded)
|
||||
{
|
||||
LogMsg(tr("Web UI translation for selected locale (%1) has been successfully loaded.")
|
||||
.arg(newLocale));
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
LogMsg(tr("Couldn't load Web UI translation for selected locale (%1).").arg(newLocale), Log::WARNING);
|
||||
}
|
||||
}
|
||||
|
@ -361,13 +383,16 @@ void WebApplication::configure()
|
|||
if (!contentSecurityPolicy.isEmpty())
|
||||
m_prebuiltHeaders.push_back({QLatin1String(Http::HEADER_CONTENT_SECURITY_POLICY), contentSecurityPolicy});
|
||||
|
||||
if (pref->isWebUICustomHTTPHeadersEnabled()) {
|
||||
if (pref->isWebUICustomHTTPHeadersEnabled())
|
||||
{
|
||||
const QString customHeaders = pref->getWebUICustomHTTPHeaders().trimmed();
|
||||
const QVector<QStringRef> customHeaderLines = customHeaders.splitRef('\n', QString::SkipEmptyParts);
|
||||
|
||||
for (const QStringRef &line : customHeaderLines) {
|
||||
for (const QStringRef &line : customHeaderLines)
|
||||
{
|
||||
const int idx = line.indexOf(':');
|
||||
if (idx < 0) {
|
||||
if (idx < 0)
|
||||
{
|
||||
// require separator `:` to be present even if `value` field can be empty
|
||||
LogMsg(tr("Missing ':' separator in WebUI custom HTTP header: \"%1\"").arg(line.toString()), Log::WARNING);
|
||||
continue;
|
||||
|
@ -399,19 +424,22 @@ void WebApplication::sendFile(const QString &path)
|
|||
|
||||
// find translated file in cache
|
||||
const auto it = m_translatedFiles.constFind(path);
|
||||
if ((it != m_translatedFiles.constEnd()) && (lastModified <= it->lastModified)) {
|
||||
if ((it != m_translatedFiles.constEnd()) && (lastModified <= it->lastModified))
|
||||
{
|
||||
print(it->data, it->mimeType);
|
||||
setHeader({Http::HEADER_CACHE_CONTROL, getCachingInterval(it->mimeType)});
|
||||
return;
|
||||
}
|
||||
|
||||
QFile file {path};
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
if (!file.open(QIODevice::ReadOnly))
|
||||
{
|
||||
qDebug("File %s was not found!", qUtf8Printable(path));
|
||||
throw NotFoundHTTPError();
|
||||
}
|
||||
|
||||
if (file.size() > MAX_ALLOWED_FILESIZE) {
|
||||
if (file.size() > MAX_ALLOWED_FILESIZE)
|
||||
{
|
||||
qWarning("%s: exceeded the maximum allowed file size!", qUtf8Printable(path));
|
||||
throw InternalServerErrorHTTPError(tr("Exceeded the maximum allowed file size (%1)!")
|
||||
.arg(Utils::Misc::friendlyUnit(MAX_ALLOWED_FILESIZE)));
|
||||
|
@ -424,7 +452,8 @@ void WebApplication::sendFile(const QString &path)
|
|||
const bool isTranslatable {mimeType.inherits(QLatin1String("text/plain"))};
|
||||
|
||||
// Translate the file
|
||||
if (isTranslatable) {
|
||||
if (isTranslatable)
|
||||
{
|
||||
QString dataStr {data};
|
||||
translateDocument(dataStr);
|
||||
data = dataStr.toUtf8();
|
||||
|
@ -443,28 +472,33 @@ Http::Response WebApplication::processRequest(const Http::Request &request, cons
|
|||
m_env = env;
|
||||
m_params.clear();
|
||||
|
||||
if (m_request.method == Http::METHOD_GET) {
|
||||
if (m_request.method == Http::METHOD_GET)
|
||||
{
|
||||
for (auto iter = m_request.query.cbegin(); iter != m_request.query.cend(); ++iter)
|
||||
m_params[iter.key()] = QString::fromUtf8(iter.value());
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
m_params = m_request.posts;
|
||||
}
|
||||
|
||||
// clear response
|
||||
clear();
|
||||
|
||||
try {
|
||||
try
|
||||
{
|
||||
// block suspicious requests
|
||||
if ((m_isCSRFProtectionEnabled && isCrossSiteRequest(m_request))
|
||||
|| (m_isHostHeaderValidationEnabled && !validateHostHeader(m_domainList))) {
|
||||
|| (m_isHostHeaderValidationEnabled && !validateHostHeader(m_domainList)))
|
||||
{
|
||||
throw UnauthorizedHTTPError();
|
||||
}
|
||||
|
||||
sessionInitialize();
|
||||
doProcessRequest();
|
||||
}
|
||||
catch (const HTTPError &error) {
|
||||
catch (const HTTPError &error)
|
||||
{
|
||||
status(error.statusCode(), error.statusText());
|
||||
print((!error.message().isEmpty() ? error.message() : error.statusText()), Http::CONTENT_TYPE_TXT);
|
||||
}
|
||||
|
@ -488,19 +522,24 @@ void WebApplication::sessionInitialize()
|
|||
|
||||
// TODO: Additional session check
|
||||
|
||||
if (!sessionId.isEmpty()) {
|
||||
if (!sessionId.isEmpty())
|
||||
{
|
||||
m_currentSession = m_sessions.value(sessionId);
|
||||
if (m_currentSession) {
|
||||
if (m_currentSession->hasExpired(m_sessionTimeout)) {
|
||||
if (m_currentSession)
|
||||
{
|
||||
if (m_currentSession->hasExpired(m_sessionTimeout))
|
||||
{
|
||||
// session is outdated - removing it
|
||||
delete m_sessions.take(sessionId);
|
||||
m_currentSession = nullptr;
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
m_currentSession->updateTimestamp();
|
||||
}
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << "session does not exist!";
|
||||
}
|
||||
}
|
||||
|
@ -513,8 +552,10 @@ QString WebApplication::generateSid() const
|
|||
{
|
||||
QString sid;
|
||||
|
||||
do {
|
||||
const quint32 tmp[] = {Utils::Random::rand(), Utils::Random::rand(), Utils::Random::rand()
|
||||
do
|
||||
{
|
||||
const quint32 tmp[] =
|
||||
{Utils::Random::rand(), Utils::Random::rand(), Utils::Random::rand()
|
||||
, Utils::Random::rand(), Utils::Random::rand(), Utils::Random::rand()};
|
||||
sid = QByteArray::fromRawData(reinterpret_cast<const char *>(tmp), sizeof(tmp)).toBase64();
|
||||
}
|
||||
|
@ -544,7 +585,8 @@ void WebApplication::sessionStart()
|
|||
// remove outdated sessions
|
||||
Algorithm::removeIf(m_sessions, [this](const QString &, const WebSession *session)
|
||||
{
|
||||
if (session->hasExpired(m_sessionTimeout)) {
|
||||
if (session->hasExpired(m_sessionTimeout))
|
||||
{
|
||||
delete session;
|
||||
return true;
|
||||
}
|
||||
|
@ -595,14 +637,16 @@ bool WebApplication::isCrossSiteRequest(const Http::Request &request) const
|
|||
const QString originValue = request.headers.value(Http::HEADER_ORIGIN);
|
||||
const QString refererValue = request.headers.value(Http::HEADER_REFERER);
|
||||
|
||||
if (originValue.isEmpty() && refererValue.isEmpty()) {
|
||||
if (originValue.isEmpty() && refererValue.isEmpty())
|
||||
{
|
||||
// owasp.org recommends to block this request, but doing so will inevitably lead Web API users to spoof headers
|
||||
// so lets be permissive here
|
||||
return false;
|
||||
}
|
||||
|
||||
// sent with CORS requests, as well as with POST requests
|
||||
if (!originValue.isEmpty()) {
|
||||
if (!originValue.isEmpty())
|
||||
{
|
||||
const bool isInvalid = !isSameOrigin(urlFromHostHeader(targetOrigin), originValue);
|
||||
if (isInvalid)
|
||||
LogMsg(tr("WebUI: Origin header & Target origin mismatch! Source IP: '%1'. Origin header: '%2'. Target origin: '%3'")
|
||||
|
@ -611,7 +655,8 @@ bool WebApplication::isCrossSiteRequest(const Http::Request &request) const
|
|||
return isInvalid;
|
||||
}
|
||||
|
||||
if (!refererValue.isEmpty()) {
|
||||
if (!refererValue.isEmpty())
|
||||
{
|
||||
const bool isInvalid = !isSameOrigin(urlFromHostHeader(targetOrigin), refererValue);
|
||||
if (isInvalid)
|
||||
LogMsg(tr("WebUI: Referer header & Target origin mismatch! Source IP: '%1'. Referer header: '%2'. Target origin: '%3'")
|
||||
|
@ -630,7 +675,8 @@ bool WebApplication::validateHostHeader(const QStringList &domains) const
|
|||
|
||||
// (if present) try matching host header's port with local port
|
||||
const int requestPort = hostHeader.port();
|
||||
if ((requestPort != -1) && (m_env.localPort != requestPort)) {
|
||||
if ((requestPort != -1) && (m_env.localPort != requestPort))
|
||||
{
|
||||
LogMsg(tr("WebUI: Invalid Host header, port mismatch. Request source IP: '%1'. Server port: '%2'. Received Host header: '%3'")
|
||||
.arg(m_env.clientAddress.toString()).arg(m_env.localPort)
|
||||
.arg(m_request.headers[Http::HEADER_HOST])
|
||||
|
@ -645,7 +691,8 @@ bool WebApplication::validateHostHeader(const QStringList &domains) const
|
|||
return true;
|
||||
|
||||
// try matching host header with domain list
|
||||
for (const auto &domain : domains) {
|
||||
for (const auto &domain : domains)
|
||||
{
|
||||
QRegExp domainRegex(domain, Qt::CaseInsensitive, QRegExp::Wildcard);
|
||||
if (requestHost.contains(domainRegex))
|
||||
return true;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue