Improve coding style

This commit is contained in:
Vladimir Golovnev (Glassez) 2020-11-16 10:02:11 +03:00
parent acad35c5bc
commit c41df9ffbd
No known key found for this signature in database
GPG key ID: 52A2C7DEE2DFA6F7
147 changed files with 4454 additions and 2227 deletions

View file

@ -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, &regexMatch);
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;