* @brief Extracts the filename from the Content-Disposition HTTP header. */
| 390 | * @brief Extracts the filename from the Content-Disposition HTTP header. |
| 391 | */ |
| 392 | void Downloader::metaDataChanged() |
| 393 | { |
| 394 | if (!m_reply) |
| 395 | return; |
| 396 | |
| 397 | QVariant variant = m_reply->header(QNetworkRequest::ContentDispositionHeader); |
| 398 | if (variant.isValid()) { |
| 399 | QString contentDisposition = QByteArray::fromPercentEncoding(variant.toByteArray()).constData(); |
| 400 | QRegularExpression regExp(R"rx(filename\s*=\s*"?([^";]+)"?)rx"); |
| 401 | QRegularExpressionMatch match = regExp.match(contentDisposition); |
| 402 | if (match.hasMatch()) { |
| 403 | // Keep only the base name so a malicious header cannot escape the |
| 404 | // download directory (e.g. "filename=../../evil") |
| 405 | QString filename = QFileInfo(match.captured(1).trimmed()).fileName(); |
| 406 | if (!filename.isEmpty()) |
| 407 | setFileName(filename); |
| 408 | } |
| 409 | } |
| 410 | } |
| 411 | |
| 412 | /** |
| 413 | * @brief Updates the progress bar and triggers size/time calculations. |