Skip to content

Commit 682420c

Browse files
committed
Merge branch 'feature/legacy-redirect' into develop
Closes #410 [ENG-10136]
2 parents 4da9b7d + c6146c5 commit 682420c

1 file changed

Lines changed: 46 additions & 15 deletions

File tree

mfr/providers/osf/provider.py

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import os
2+
import re
23
import json
34
import hashlib
45
import logging
@@ -159,11 +160,35 @@ async def download(self):
159160

160161
return streams.ResponseStreamReader(response)
161162

163+
@staticmethod
164+
def _is_osf_download_route(url):
165+
"""True when ``url`` is OSF's persistent file download path ``/download/<id>/``."""
166+
path = urlparse(url).path or ''
167+
osf_download_path_re = re.compile(r'^/download/[^/]+', re.IGNORECASE)
168+
return bool(osf_download_path_re.match(path))
169+
170+
async def _fetch_redirect(self, url, headers):
171+
request = await self._make_request(
172+
'GET',
173+
url,
174+
allow_redirects=False,
175+
headers=headers,
176+
)
177+
status = request.status
178+
location = request.headers.get('Location') or request.headers.get('location')
179+
reason = request.reason
180+
await request.release()
181+
return location, status, reason
182+
162183
async def _fetch_download_url(self):
163184
"""Provider needs a WaterButler URL to download and get metadata. If ``url`` is already
164185
a WaterButler url, return that. If not, then the url points to an OSF endpoint that will
165186
redirect to WB. Issue a GET request against it, then return the WB url stored in the
166187
Location header.
188+
189+
First ``GET`` may return **301** with ``Location`` for legacy download route. If ``Location``
190+
points at OSF's ``/download/<id>/`` route, perform a second ``GET`` there and expect **302**
191+
to WaterButler. If ``Location`` is not that route (e.g. already WaterButler), use it as ``download_url``.
167192
"""
168193
if not self.download_url:
169194
# v1 Waterbutler url provided
@@ -173,26 +198,32 @@ async def _fetch_download_url(self):
173198
self.metrics.add('download_url.orig_type', 'wb_v1')
174199
else:
175200
self.metrics.add('download_url.orig_type', 'osf')
176-
# make request to osf, don't follow, store waterbutler download url
177-
request = await self._make_request(
178-
'GET',
179-
self.url,
180-
allow_redirects=False,
181-
headers={
182-
'Content-Type': 'application/json'
183-
}
184-
)
185-
await request.release()
201+
# make request to osf, store waterbutler download url
202+
headers = {'Content-Type': 'application/json'}
186203

187-
logger.debug(f'osf-download-resolver: request.status::{request.status}')
188-
if request.status != 302:
204+
location, status, reason = await self._fetch_redirect(self.url, headers)
205+
logger.debug(f'osf-download-resolver: url={self.url} status={status} location={location}')
206+
if status not in (301, 302) or not location:
189207
raise exceptions.MetadataError(
190-
request.reason,
208+
reason,
191209
metadata_url=self.url,
192210
provider=self.NAME,
193-
code=request.status,
211+
code=status,
194212
)
195-
self.download_url = request.headers['location']
213+
214+
if self._is_osf_download_route(location):
215+
location, status, reason = await self._fetch_redirect(location, headers)
216+
217+
logger.debug(f'osf-download-resolver follow /download/: url={location} status={status} location={location}')
218+
if status != 302 or not location:
219+
raise exceptions.MetadataError(
220+
reason,
221+
metadata_url=location,
222+
provider=self.NAME,
223+
code=status,
224+
)
225+
226+
self.download_url = location
196227

197228
self.metrics.add('download_url.derived_url', str(self.download_url))
198229

0 commit comments

Comments
 (0)