Skip to content

Commit cadecfe

Browse files
committed
Merge tag '0.25.11' into develop
2 parents d8c0744 + af9f9e0 commit cadecfe

File tree

11 files changed

+114
-35
lines changed

11 files changed

+114
-35
lines changed

CHANGELOG

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
ChangeLog
33
*********
44

5+
0.25.11 (2018-06-08)
6+
====================
7+
- Fix: Percent-encode quote characters in urls to avoid breaking some renderers.
8+
59
0.25.10 (2018-06-06)
610
====================
711
- Fix: Brown-paper-bag release: actual change version in the code.

mfr/extensions/audio/render.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from mako.lookup import TemplateLookup
44

55
from mfr.core import extension
6+
from mfr.extensions.utils import escape_url_for_template
67

78

89
class AudioRenderer(extension.BaseRenderer):
@@ -13,7 +14,8 @@ class AudioRenderer(extension.BaseRenderer):
1314
]).get_template('viewer.mako')
1415

1516
def render(self):
16-
return self.TEMPLATE.render(base=self.assets_url, url=self.url)
17+
safe_url = escape_url_for_template(self.url)
18+
return self.TEMPLATE.render(base=self.assets_url, url=safe_url)
1719

1820
@property
1921
def file_required(self):

mfr/extensions/image/render.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
from mfr.core import extension
77
from mfr.extensions.image import settings
8-
from mfr.extensions.utils import munge_url_for_localdev
8+
from mfr.extensions.utils import munge_url_for_localdev, escape_url_for_template
99

1010

1111
class ImageRenderer(extension.BaseRenderer):
@@ -19,7 +19,8 @@ def render(self):
1919
self.metrics.add('needs_export', False)
2020
if self.metadata.ext in settings.EXPORT_EXCLUSIONS:
2121
download_url = munge_url_for_localdev(self.url)
22-
return self.TEMPLATE.render(base=self.assets_url, url=download_url.geturl())
22+
safe_url = escape_url_for_template(download_url.geturl())
23+
return self.TEMPLATE.render(base=self.assets_url, url=safe_url)
2324

2425
exported_url = furl.furl(self.export_url)
2526
if settings.EXPORT_MAXIMUM_SIZE and settings.EXPORT_TYPE:
@@ -28,10 +29,12 @@ def render(self):
2829
exported_url.args['format'] = settings.EXPORT_TYPE
2930
else:
3031
download_url = munge_url_for_localdev(self.url)
31-
return self.TEMPLATE.render(base=self.assets_url, url=download_url.geturl())
32+
safe_url = escape_url_for_template(download_url.geturl())
33+
return self.TEMPLATE.render(base=self.assets_url, url=safe_url)
3234

3335
self.metrics.add('needs_export', True)
34-
return self.TEMPLATE.render(base=self.assets_url, url=exported_url.url)
36+
safe_url = escape_url_for_template(exported_url.url)
37+
return self.TEMPLATE.render(base=self.assets_url, url=safe_url)
3538

3639
@property
3740
def file_required(self):

mfr/extensions/jsc3d/render.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
from mfr.core import extension
99
from mfr.extensions.jsc3d import settings
10-
from mfr.extensions.utils import munge_url_for_localdev
10+
from mfr.extensions.utils import munge_url_for_localdev, escape_url_for_template
1111

1212

1313
class JSC3DRenderer(extension.BaseRenderer):
@@ -21,18 +21,20 @@ def render(self):
2121
self.metrics.add('needs_export', False)
2222
if self.metadata.ext in settings.EXPORT_EXCLUSIONS:
2323
download_url = munge_url_for_localdev(self.metadata.download_url)
24+
safe_url = escape_url_for_template(download_url.geturl())
2425
return self.TEMPLATE.render(
2526
base=self.assets_url,
26-
url=download_url.geturl(),
27+
url=safe_url,
2728
ext=self.metadata.ext.lower(),
2829
)
2930

3031
exported_url = furl.furl(self.export_url)
3132
exported_url.args['format'] = settings.EXPORT_TYPE
3233
self.metrics.add('needs_export', True)
34+
safe_url = escape_url_for_template(exported_url.url)
3335
return self.TEMPLATE.render(
3436
base=self.assets_url,
35-
url=exported_url.url,
37+
url=safe_url,
3638
ext=settings.EXPORT_TYPE,
3739
)
3840

mfr/extensions/pdb/render.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
from mfr.core import extension
88
from mfr.extensions.pdb import settings
9-
from mfr.extensions.utils import munge_url_for_localdev
9+
from mfr.extensions.utils import munge_url_for_localdev, escape_url_for_template
1010

1111

1212
class PdbRenderer(extension.BaseRenderer):
@@ -18,9 +18,10 @@ class PdbRenderer(extension.BaseRenderer):
1818

1919
def render(self):
2020
download_url = munge_url_for_localdev(self.metadata.download_url)
21+
safe_url = escape_url_for_template(download_url.geturl())
2122
return self.TEMPLATE.render(
2223
base=self.assets_url,
23-
url=download_url.geturl(),
24+
url=safe_url,
2425
options=json.dumps(settings.OPTIONS),
2526
)
2627

mfr/extensions/pdf/render.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
from mfr.core import extension
88
from mfr.extensions.pdf import settings
9-
from mfr.extensions.utils import munge_url_for_localdev
9+
from mfr.extensions.utils import munge_url_for_localdev, escape_url_for_template
1010

1111
logger = logging.getLogger(__name__)
1212

@@ -19,14 +19,16 @@ class PdfRenderer(extension.BaseRenderer):
1919
]).get_template('viewer.mako')
2020

2121
def render(self):
22+
2223
download_url = munge_url_for_localdev(self.metadata.download_url)
23-
logger.debug('extension::{} supported-list::{}'.format(self.metadata.ext, settings.EXPORT_SUPPORTED))
24+
logger.debug('extension::{} supported-list::{}'.format(self.metadata.ext,
25+
settings.EXPORT_SUPPORTED))
2426
if self.metadata.ext.lower() not in settings.EXPORT_SUPPORTED:
2527
logger.debug('Extension not found in supported list!')
2628
return self.TEMPLATE.render(
2729
base=self.assets_url,
28-
url=download_url.geturl(),
29-
enable_hypothesis=settings.ENABLE_HYPOTHESIS
30+
url=escape_url_for_template(download_url.geturl()),
31+
enable_hypothesis=settings.ENABLE_HYPOTHESIS,
3032
)
3133

3234
logger.debug('Extension found in supported list!')
@@ -41,14 +43,15 @@ def render(self):
4143
self.metrics.add('needs_export', True)
4244
return self.TEMPLATE.render(
4345
base=self.assets_url,
44-
url=exported_url.url,
46+
url=escape_url_for_template(exported_url.url),
4547
enable_hypothesis=settings.ENABLE_HYPOTHESIS
4648
)
4749

50+
# TODO: is this dead code? ``settings.EXPORT_TYPE`` is never None or empty
4851
return self.TEMPLATE.render(
4952
base=self.assets_url,
50-
url=download_url.geturl(),
51-
enable_hypothesis=settings.ENABLE_HYPOTHESIS
53+
url=escape_url_for_template(download_url.geturl()),
54+
enable_hypothesis=settings.ENABLE_HYPOTHESIS,
5255
)
5356

5457
@property

mfr/extensions/svg/render.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from mako.lookup import TemplateLookup
55

66
from mfr.core import extension
7+
from mfr.extensions.utils import escape_url_for_template
78

89

910
class SvgRenderer(extension.BaseRenderer):
@@ -14,7 +15,8 @@ class SvgRenderer(extension.BaseRenderer):
1415
]).get_template('viewer.mako')
1516

1617
def render(self):
17-
return self.TEMPLATE.render(base=self.assets_url, url=self.url)
18+
safe_url = escape_url_for_template(self.url)
19+
return self.TEMPLATE.render(base=self.assets_url, url=safe_url)
1820

1921
@property
2022
def file_required(self):

mfr/extensions/utils.py

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,49 @@
1+
import logging
2+
from typing import Tuple
13
from urllib.parse import parse_qs, urlencode, urlparse
24

35
from mfr.extensions import settings
46

7+
logger = logging.getLogger(__name__)
58

6-
def munge_url_for_localdev(url):
7-
"""
8-
If MFR is being run in a local development environment (i.e. LOCAL_DEVELOPMENT is True), we
9+
10+
def munge_url_for_localdev(url: str) -> Tuple:
11+
"""If MFR is being run in a local development environment (i.e. LOCAL_DEVELOPMENT is True), we
912
need to replace the internal host (the one the backend services communicate on, default:
1013
192.168.168.167) with the external host (the one the user provides, default: "localhost")
1114
e.g. http://192.168.168.167:7777/foo/bar => http://localhost:7777/foo/bar
1215
"""
16+
1317
url_obj = urlparse(url)
14-
if (settings.LOCAL_DEVELOPMENT and url_obj.hostname == settings.DOCKER_LOCAL_HOST):
15-
query_dict = parse_qs(url_obj.query, keep_blank_values=True)
18+
if settings.LOCAL_DEVELOPMENT and url_obj.hostname == settings.DOCKER_LOCAL_HOST:
19+
query_dict = parse_qs(url_obj.query, keep_blank_values=True)
1620

17-
# the 'mode' param will break image downloads from the osf
18-
query_dict.pop('mode', None)
21+
# the 'mode' param will break image downloads from the osf
22+
query_dict.pop('mode', None)
1923

20-
url_obj = url_obj._replace(
21-
query=urlencode(query_dict, doseq=True),
22-
netloc='{}:{}'.format(settings.LOCAL_HOST, url_obj.port)
23-
)
24+
url_obj = url_obj._replace(
25+
query=urlencode(query_dict, doseq=True),
26+
netloc='{}:{}'.format(settings.LOCAL_HOST, url_obj.port)
27+
)
2428

2529
return url_obj
30+
31+
32+
def escape_url_for_template(url: str, logs: bool=True) -> str:
33+
"""Escape (URL Encode) single and double quote(s) for the given URL.
34+
35+
Download and export URLs may end up not properly encoded right before they are about to be sent
36+
to the mako template due to issues including (but not limited to) (1) ``furl`` dropping encoding
37+
for single quote (2) URL (provided by users or constructed by scripts) not having the correct
38+
encoding. This helper method must be called for each render request that sends URL to the mako
39+
template.
40+
41+
:param str url: the URL to be sent to the mako template
42+
:param bool logs: whether to enable warnings, default is `True` and is set to `False` for tests
43+
:return: the properly encoded URL
44+
"""
45+
46+
safe_url = url.replace('"', '%22').replace("'", '%27')
47+
if url != safe_url and logs:
48+
logger.warning('Unsafe URL containing unescaped single (double) quote(s) has been replaced')
49+
return safe_url

mfr/extensions/video/render.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from mako.lookup import TemplateLookup
44

55
from mfr.core import extension
6-
from mfr.extensions.utils import munge_url_for_localdev
6+
from mfr.extensions.utils import munge_url_for_localdev, escape_url_for_template
77

88

99
class VideoRenderer(extension.BaseRenderer):
@@ -15,7 +15,8 @@ class VideoRenderer(extension.BaseRenderer):
1515

1616
def render(self):
1717
download_url = munge_url_for_localdev(self.metadata.download_url)
18-
return self.TEMPLATE.render(url=download_url.geturl())
18+
safe_url = escape_url_for_template(download_url.geturl())
19+
return self.TEMPLATE.render(url=safe_url)
1920

2021
@property
2122
def file_required(self):

mfr/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = '0.25.10'
1+
__version__ = '0.25.11'

0 commit comments

Comments
 (0)