diff --git a/kolibri/utils/file_transfer.py b/kolibri/utils/file_transfer.py index dc8398b5f0d..faceb864a7f 100644 --- a/kolibri/utils/file_transfer.py +++ b/kolibri/utils/file_transfer.py @@ -747,9 +747,15 @@ def _set_headers(self): if self._headers_set: return - response = self.session.head(self.source, timeout=self.timeout) + response = self.session.head( + self.source, timeout=self.timeout, allow_redirects=True + ) response.raise_for_status() + if response.url != self.source: + logger.debug("Redirected from {} to {}".format(self.source, response.url)) + self.source = response.url + self.compressed = bool(response.headers.get("content-encoding", "")) self.content_length_header = "content-length" in response.headers diff --git a/kolibri/utils/tests/test_file_transfer.py b/kolibri/utils/tests/test_file_transfer.py index 0845f59b751..ecb803c14e9 100644 --- a/kolibri/utils/tests/test_file_transfer.py +++ b/kolibri/utils/tests/test_file_transfer.py @@ -136,6 +136,7 @@ def mock_get_request(self, url, headers=None, **kwargs): range_headers = self.get_headers(range_data, start, end) mock_response = MagicMock() + mock_response.url = url # Because of the way that requests iterates over the content, we need to # keep track of whether the content has been exhausted, so that we can @@ -166,6 +167,7 @@ def content(other): def mock_head_request(self, url, **kwargs): mock_response = MagicMock() mock_response.headers = self.get_headers(self.content, None, None) + mock_response.url = url return mock_response def set_session_mock(self): @@ -368,6 +370,32 @@ def test_file_download_500_raise(self): with self.assertRaises(HTTPError): fd.run() + def test_file_download_redirect(self): + mock_response = MagicMock() + mock_response.status_code = 302 + mock_response.url = "https://example.com/testfile" + + def mock_head_request_redirect(url, **kwargs): + mock_response = self.mock_head_request(url, **kwargs) + mock_response.status_code = 302 + mock_response.url = "https://example.com/testfile" + return mock_response + + self.mock_session.head.side_effect = mock_head_request_redirect + + with FileDownload( + self.source, + self.dest, + self.checksum, + session=self.mock_session, + retry_wait=0, + full_ranges=self.full_ranges, + ) as fd: + fd.run() + + self.source = "https://example.com/testfile" + self._assert_downloaded_content() + def test_file_download_request_exception(self): mock_session = MagicMock() mock_session.head.side_effect = RequestException