| 174 | } |
| 175 | |
| 176 | auto Download::handleRedirect() -> bool |
| 177 | { |
| 178 | QUrl redirect = m_reply->header(QNetworkRequest::LocationHeader).toUrl(); |
| 179 | if (!redirect.isValid()) { |
| 180 | if (!m_reply->hasRawHeader("Location")) { |
| 181 | // no redirect -> it's fine to continue |
| 182 | return false; |
| 183 | } |
| 184 | // there is a Location header, but it's not correct. we need to apply some workarounds... |
| 185 | QByteArray redirectBA = m_reply->rawHeader("Location"); |
| 186 | if (redirectBA.size() == 0) { |
| 187 | // empty, yet present redirect header? WTF? |
| 188 | return false; |
| 189 | } |
| 190 | QString redirectStr = QString::fromUtf8(redirectBA); |
| 191 | |
| 192 | if (redirectStr.startsWith("//")) { |
| 193 | /* |
| 194 | * IF the URL begins with //, we need to insert the URL scheme. |
| 195 | * See: https://bugreports.qt.io/browse/QTBUG-41061 |
| 196 | * See: http://tools.ietf.org/html/rfc3986#section-4.2 |
| 197 | */ |
| 198 | redirectStr = m_reply->url().scheme() + ":" + redirectStr; |
| 199 | } else if (redirectStr.startsWith("/")) { |
| 200 | /* |
| 201 | * IF the URL begins with /, we need to process it as a relative URL |
| 202 | */ |
| 203 | auto url = m_reply->url(); |
| 204 | url.setPath(redirectStr, QUrl::TolerantMode); |
| 205 | redirectStr = url.toString(); |
| 206 | } |
| 207 | |
| 208 | /* |
| 209 | * Next, make sure the URL is parsed in tolerant mode. Qt doesn't parse the location header in tolerant mode, which causes issues. |
| 210 | * FIXME: report Qt bug for this |
| 211 | */ |
| 212 | redirect = QUrl(redirectStr, QUrl::TolerantMode); |
| 213 | if (!redirect.isValid()) { |
| 214 | qWarning() << "Failed to parse redirect URL:" << redirectStr; |
| 215 | downloadError(QNetworkReply::ProtocolFailure); |
| 216 | return false; |
| 217 | } |
| 218 | qDebug() << "Fixed location header:" << redirect; |
| 219 | } else { |
| 220 | qDebug() << "Location header:" << redirect; |
| 221 | } |
| 222 | |
| 223 | m_url = QUrl(redirect.toString()); |
| 224 | qDebug() << "Following redirect to " << m_url.toString(); |
| 225 | startAction(m_network); |
| 226 | |
| 227 | return true; |
| 228 | } |
| 229 | |
| 230 | void Download::downloadFinished() |
| 231 | { |