Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sanitize text before making repr_html #3378

Merged
merged 12 commits into from
Oct 16, 2019
10 changes: 6 additions & 4 deletions lib/iris/experimental/representation.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from __future__ import (absolute_import, division, print_function)
from six.moves import (filter, input, map, range, zip) # noqa

from html import escape
import re


Expand Down Expand Up @@ -96,7 +97,7 @@ class CubeRepresentation(object):
def __init__(self, cube):
self.cube = cube
self.cube_id = id(self.cube)
self.cube_str = str(self.cube)
self.cube_str = escape(str(self.cube))

self.str_headings = {
'Dimension coordinates:': None,
Expand All @@ -115,9 +116,9 @@ def __init__(self, cube):
self.scalar_cube = self.shapes == ()
self.ndims = self.cube.ndim

self.name = self.cube.name().title().replace('_', ' ')
self.names = self._dim_names()
self.units = self.cube.units
self.name = escape(self.cube.name().title().replace('_', ' '))
self.names = [escape(dim_name) for dim_name in self._dim_names()]
self.units = escape(str(self.cube.units))

def _get_dim_names(self):
"""
Expand Down Expand Up @@ -401,6 +402,7 @@ def make_content(self):
for i, cube in enumerate(self.cubelist):
title = '{i}: {summary}'.format(i=i,
summary=cube.summary(shorten=True))
title = escape(title)
content = cube._repr_html_()
html.append(self._accordian_panel.format(uid=self.cubelist_id,
title=title,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# (C) British Crown Copyright 2018, Met Office
# (C) British Crown Copyright 2018 - 2019, Met Office
#
# This file is part of Iris.
#
Expand All @@ -18,6 +18,7 @@

from __future__ import (absolute_import, division, print_function)
from six.moves import (filter, input, map, range, zip) # noqa
from html import escape

# Import iris.tests first so that some things can be initialised before
# importing anything else.
Expand Down Expand Up @@ -136,12 +137,12 @@ def test_identfication(self):

def test_header__name(self):
header = self.representer._make_header()
expected_name = self.cube.name().title().replace('_', ' ')
expected_name = escape(self.cube.name().title().replace('_', ' '))
pp-mo marked this conversation as resolved.
Show resolved Hide resolved
self.assertIn(expected_name, header)

def test_header__units(self):
header = self.representer._make_header()
expected_units = self.cube.units.symbol
expected_units = escape(self.cube.units.symbol)
self.assertIn(expected_units, header)

def test_header__scalar_str(self):
Expand All @@ -160,9 +161,9 @@ def test_content__specific_scalar_coord(self):
# Check a specific scalar coord is present in the main content.
content = self.representer._make_content()
expected_coord = self.cube.coords()[0]
expected_coord_name = expected_coord.name()
expected_coord_name = escape(expected_coord.name())
self.assertIn(expected_coord_name, content)
expected_coord_val = str(expected_coord.points[0])
expected_coord_val = escape(str(expected_coord.points[0]))
self.assertIn(expected_coord_val, content)

def test_content__attributes(self):
Expand Down
20 changes: 20 additions & 0 deletions lib/iris/tests/unit/experimental/representation/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# (C) British Crown Copyright 2019, Met Office
#
# This file is part of Iris.
#
# Iris is free software: you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the
# Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Iris is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Iris. If not, see <http://www.gnu.org/licenses/>.
"""Unit tests for the :mod:`iris.experimental.representation` package."""

from __future__ import (absolute_import, division, print_function)
from six.moves import (filter, input, map, range, zip) # noqa
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

from __future__ import (absolute_import, division, print_function)
from six.moves import (filter, input, map, range, zip) # noqa
from html import escape

# Import iris.tests first so that some things can be initialised before
# importing anything else.
Expand All @@ -44,6 +45,7 @@ class Test_make_content(tests.IrisTest):
def setUp(self):
self.cubes = CubeList([stock.simple_3d(),
stock.lat_lon_cube()])
self.cubes[0].rename('name & <html>')
self.representer = CubeListRepresentation(self.cubes)
self.content = self.representer.make_content()

Expand All @@ -53,17 +55,18 @@ def test_repr_len(self):
def test_summary_lines(self):
names = [c.name() for c in self.cubes]
for name, content in zip(names, self.content):
name = escape(name)
self.assertIn(name, content)

def test__cube_name_summary_consistency(self):
# Just check the first cube in the CubeList.
single_cube_html = self.content[0]
first_contents_line = single_cube_html.split('\n')[1]
# Get the cube name out of the repr html...
cube_name = first_contents_line.split('>0: ')[1].split('/')[0]
# ... and prettify it (to be the same as in the following cube repr).
# Get a "prettified" cube name, as it should be in the cubelist repr.
cube_name = self.cubes[0].name()
pretty_cube_name = cube_name.strip().replace('_', ' ').title()
self.assertIn(pretty_cube_name, single_cube_html)
pretty_escaped_name = escape(pretty_cube_name)
self.assertIn(pretty_escaped_name, single_cube_html)


@tests.skip_data
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

from __future__ import (absolute_import, division, print_function)
from six.moves import (filter, input, map, range, zip) # noqa
from html import escape

# Import iris.tests first so that some things can be initialised before
# importing anything else.
Expand Down Expand Up @@ -81,13 +82,13 @@ class Test__summary_content(tests.IrisTest):
def setUp(self):
self.cube = stock.lat_lon_cube()
# Check we're not tripped up by names containing spaces.
self.cube.rename('Electron density')
self.cube.rename('Electron density (&<html>)')
self.cube.units = '1e11 e/m^3'
self.representer = CubeRepresentation(self.cube)

def test_name(self):
# Check the cube name is being set and formatted correctly.
expected = self.cube.name().replace('_', ' ').title()
expected = escape(self.cube.name().replace('_', ' ').title())
result = self.representer.name
self.assertEqual(expected, result)

Expand Down