From 7dd166b158594dec3e222bf041cdfd806f633f88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Araujo?= Date: Thu, 23 Apr 2020 17:36:24 -0400 Subject: expand testing for predicate texts --- tests/test_config/test_predicates.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/test_config/test_predicates.py b/tests/test_config/test_predicates.py index d1562947e..31e7a38e7 100644 --- a/tests/test_config/test_predicates.py +++ b/tests/test_config/test_predicates.py @@ -312,6 +312,20 @@ class TestPredicateList(unittest.TestCase): self.assertEqual(predicates[10].text(), 'classmethod predicate') self.assertTrue(predicates[11].text().startswith('custom predicate')) + def test_predicate_text_is_correct_when_multiple(self): + _, predicates, _ = self._callFUT( + request_method=('one', 'two'), + request_param=('param1', 'param2=on'), + header='header:text/*', + accept=('accept1', 'accept2'), + match_param=('foo=bar', 'baz=bim'), + ) + self.assertEqual(predicates[0].text(), "request_method = one,two") + self.assertEqual(predicates[1].text(), 'request_param param1,param2=on') + self.assertEqual(predicates[2].text(), 'header header=text/*') + self.assertEqual(predicates[3].text(), 'accept = accept1, accept2') + self.assertEqual(predicates[4].text(), "match_param baz=bim,foo=bar") + def test_match_param_from_string(self): _, predicates, _ = self._callFUT(match_param='foo=bar') request = DummyRequest() -- cgit v1.2.3 From 254efda1456a707afd36ec8ee505dc1bb76f8a77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Araujo?= Date: Thu, 23 Apr 2020 18:11:55 -0400 Subject: support multiple values for header predicate --- CHANGES.rst | 4 +++ docs/narr/viewconfig.rst | 6 ++-- src/pyramid/config/routes.py | 3 +- src/pyramid/config/views.py | 3 +- src/pyramid/predicates.py | 52 ++++++++++++++++----------- tests/test_config/test_predicates.py | 69 +++++++++++++++++++++++++++++++++--- 6 files changed, 107 insertions(+), 30 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 67256db8d..3bd14705d 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,6 +4,10 @@ unreleased Features -------- +- It is now possible to pass multiple values to the ``header`` predicate + for route and view configuration. + See https://github.com/Pylons/pyramid/pull/3576 + - Add support for Python 3.8. See https://github.com/Pylons/pyramid/pull/3547 diff --git a/docs/narr/viewconfig.rst b/docs/narr/viewconfig.rst index 891d294d7..c40f1181a 100644 --- a/docs/narr/viewconfig.rst +++ b/docs/narr/viewconfig.rst @@ -448,10 +448,10 @@ configured view. associated view callable. ``header`` - This value represents an HTTP header name or a header name/value pair. + This value matches one or more HTTP header names or header name/value pairs. - If ``header`` is specified, it must be a header name or a - ``headername:headervalue`` pair. + If ``header`` is specified, it must be a string or a sequence of strings, + each being a header name or a ``headername:headervalue`` pair. If ``header`` is specified without a value (a bare header name only, e.g., ``If-Modified-Since``), the view will only be invoked if the HTTP header diff --git a/src/pyramid/config/routes.py b/src/pyramid/config/routes.py index 7c78fbfa7..5daa1dc00 100644 --- a/src/pyramid/config/routes.py +++ b/src/pyramid/config/routes.py @@ -220,7 +220,8 @@ class RoutesConfiguratorMixin: header This argument represents an HTTP header name or a header - name/value pair. If the argument contains a ``:`` (colon), + name/value pair, or a sequence of them. + If the argument contains a ``:`` (colon), it will be considered a name/value pair (e.g. ``User-Agent:Mozilla/.*`` or ``Host:localhost``). If the value contains a colon, the value portion should be a diff --git a/src/pyramid/config/views.py b/src/pyramid/config/views.py index 466c31f94..9053160fa 100644 --- a/src/pyramid/config/views.py +++ b/src/pyramid/config/views.py @@ -671,7 +671,8 @@ class ViewsConfiguratorMixin: header This value represents an HTTP header name or a header - name/value pair. If the value contains a ``:`` (colon), it + name/value pair, or a sequence of them. + If the value contains a ``:`` (colon), it will be considered a name/value pair (e.g. ``User-Agent:Mozilla/.*`` or ``Host:localhost``). The value portion should be a regular expression. If the value diff --git a/src/pyramid/predicates.py b/src/pyramid/predicates.py index f51ea3b21..0c74ed6d5 100644 --- a/src/pyramid/predicates.py +++ b/src/pyramid/predicates.py @@ -98,33 +98,43 @@ class RequestParamPredicate: class HeaderPredicate: def __init__(self, val, config): - name = val - v = None - if ':' in name: - name, val_str = name.split(':', 1) - try: - v = re.compile(val_str) - except re.error as why: - raise ConfigurationError(why.args[0]) - if v is None: - self._text = 'header %s' % (name,) - else: - self._text = 'header %s=%s' % (name, val_str) - self.name = name - self.val = v + values = [] + + val = as_sorted_tuple(val) + for name in val: + v, val_str = None, None + if ':' in name: + name, val_str = name.split(':', 1) + try: + v = re.compile(val_str) + except re.error as why: + raise ConfigurationError(why.args[0]) + + values.append((name, v, val_str)) + + self.val = values def text(self): - return self._text + return 'header %s' % ', '.join( + '%s=%s' % (name, val_str) if val_str else name + for name, _, val_str in self.val + ) phash = text def __call__(self, context, request): - if self.val is None: - return self.name in request.headers - val = request.headers.get(self.name) - if val is None: - return False - return self.val.match(val) is not None + for name, val, _ in self.val: + if val is None: + if name not in request.headers: + return False + else: + value = request.headers.get(name) + if value is None: + return False + if val.match(value) is None: + return False + + return True class AcceptPredicate: diff --git a/tests/test_config/test_predicates.py b/tests/test_config/test_predicates.py index 31e7a38e7..c0185340f 100644 --- a/tests/test_config/test_predicates.py +++ b/tests/test_config/test_predicates.py @@ -315,14 +315,14 @@ class TestPredicateList(unittest.TestCase): def test_predicate_text_is_correct_when_multiple(self): _, predicates, _ = self._callFUT( request_method=('one', 'two'), - request_param=('param1', 'param2=on'), - header='header:text/*', + request_param=('par2=on', 'par1'), + header=('header2', 'header1:val.*'), accept=('accept1', 'accept2'), match_param=('foo=bar', 'baz=bim'), ) self.assertEqual(predicates[0].text(), "request_method = one,two") - self.assertEqual(predicates[1].text(), 'request_param param1,param2=on') - self.assertEqual(predicates[2].text(), 'header header=text/*') + self.assertEqual(predicates[1].text(), 'request_param par1,par2=on') + self.assertEqual(predicates[2].text(), 'header header1=val.*, header2') self.assertEqual(predicates[3].text(), 'accept = accept1, accept2') self.assertEqual(predicates[4].text(), "match_param baz=bim,foo=bar") @@ -368,6 +368,66 @@ class TestPredicateList(unittest.TestCase): hash2, _, __ = self._callFUT(request_method='GET') self.assertEqual(hash1, hash2) + def test_header_simple(self): + _, predicates, _ = self._callFUT(header='foo') + request = DummyRequest() + request.headers = {'foo': 'bars', 'baz': 'foo'} + self.assertTrue(predicates[0](Dummy(), request)) + + def test_header_simple_fails(self): + _, predicates, _ = self._callFUT(header='content-length') + request = DummyRequest() + request.headers = {'foo': 'bars', 'baz': 'foo'} + self.assertFalse(predicates[0](Dummy(), request)) + + def test_header_with_value(self): + _, predicates, _ = self._callFUT(header='foo:bar') + request = DummyRequest() + request.headers = {'foo': 'bars', 'baz': 'foo'} + self.assertTrue(predicates[0](Dummy(), request)) + + def test_header_with_value_fails(self): + _, predicates, _ = self._callFUT(header='foo:bar') + request = DummyRequest() + request.headers = {'foo': 'nobar', 'baz': 'foo'} + self.assertFalse(predicates[0](Dummy(), request)) + + def test_header_multiple(self): + _, predicates, _ = self._callFUT(header=('foo', 'content-length')) + request = DummyRequest() + request.headers = {'foo': 'bars', 'content-length': '42'} + self.assertTrue(predicates[0](Dummy(), request)) + + def test_header_multiple_fails(self): + _, predicates, _ = self._callFUT(header=('foo', 'content-encoding')) + request = DummyRequest() + request.headers = {'foo': 'bars', 'content-length': '42'} + self.assertFalse(predicates[0](Dummy(), request)) + + def test_header_multiple_with_values(self): + _, predicates, _ = self._callFUT(header=('foo:bar', 'spam:egg')) + request = DummyRequest() + request.headers = {'foo': 'bars', 'spam': 'eggs'} + self.assertTrue(predicates[0](Dummy(), request)) + + def test_header_multiple_with_values_fails(self): + _, predicates, _ = self._callFUT(header=('foo:bar', 'spam:egg$')) + request = DummyRequest() + request.headers = {'foo': 'bars', 'spam': 'eggs'} + self.assertFalse(predicates[0](Dummy(), request)) + + def test_header_multiple_mixed(self): + _, predicates, _ = self._callFUT(header=('foo:bar', 'spam')) + request = DummyRequest() + request.headers = {'foo': 'bars', 'spam': 'ham'} + self.assertTrue(predicates[0](Dummy(), request)) + + def test_header_multiple_mixed_fails(self): + _, predicates, _ = self._callFUT(header=('foo:bar', 'spam')) + request = DummyRequest() + request.headers = {'foo': 'nobar', 'spamme': 'ham'} + self.assertFalse(predicates[0](Dummy(), request)) + def test_unknown_predicate(self): from pyramid.exceptions import ConfigurationError @@ -486,6 +546,7 @@ class DummyRequest: environ = {} self.environ = environ self.params = {} + self.headers = {} self.cookies = {} -- cgit v1.2.3 From c65d2c03174d5a2d66a7a85974b938070ad01a71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Araujo?= Date: Tue, 5 May 2020 20:23:49 -0400 Subject: reword doc --- src/pyramid/config/routes.py | 30 ++++++++++++++++-------------- src/pyramid/config/views.py | 33 ++++++++++++++++++--------------- 2 files changed, 34 insertions(+), 29 deletions(-) diff --git a/src/pyramid/config/routes.py b/src/pyramid/config/routes.py index 5daa1dc00..7208f5adb 100644 --- a/src/pyramid/config/routes.py +++ b/src/pyramid/config/routes.py @@ -219,24 +219,26 @@ class RoutesConfiguratorMixin: header - This argument represents an HTTP header name or a header - name/value pair, or a sequence of them. - If the argument contains a ``:`` (colon), - it will be considered a name/value pair - (e.g. ``User-Agent:Mozilla/.*`` or ``Host:localhost``). If - the value contains a colon, the value portion should be a - regular expression. If the value does not contain a colon, - the entire value will be considered to be the header name - (e.g. ``If-Modified-Since``). If the value evaluates to a - header name only without a value, the header specified by + This value can be a string or an iterable of strings for HTTP + header names. Any string that does not contain a ``:`` + (colon) will be considered to be the header name (e.g. + ``If-Modified-Since``). In this case, the header specified by the name must be present in the request for this predicate - to be true. If the value evaluates to a header name/value - pair, the header specified by the name must be present in + to be true. + + If a string contains a colon, it will be considered a + name/value pair (e.g. ``User-Agent:Mozilla/.*`` or + ``Host:localhost``), where the value part is a regular + expression. The header specified by the name must be present in the request *and* the regular expression specified as the - value must match the header value. Whether or not the value - represents a header name or a header name/value pair, the + value must match the header value. + + Whether or not the strings + represent a header name or a header name/value pair, the case of the header name is not significant. If this predicate returns ``False``, route matching continues. + When the value is an iterable of strings, they must all + return ``True`` for this predicate to return ``True``. accept diff --git a/src/pyramid/config/views.py b/src/pyramid/config/views.py index 9053160fa..cf1b0a800 100644 --- a/src/pyramid/config/views.py +++ b/src/pyramid/config/views.py @@ -670,23 +670,26 @@ class ViewsConfiguratorMixin: header - This value represents an HTTP header name or a header - name/value pair, or a sequence of them. - If the value contains a ``:`` (colon), it - will be considered a name/value pair - (e.g. ``User-Agent:Mozilla/.*`` or ``Host:localhost``). The - value portion should be a regular expression. If the value - does not contain a colon, the entire value will be - considered to be the header name - (e.g. ``If-Modified-Since``). If the value evaluates to a - header name only without a value, the header specified by + This value can be a string or an iterable of strings for HTTP + header names. Any string that does not contain a ``:`` + (colon) will be considered to be the header name (e.g. + ``If-Modified-Since``). In this case, the header specified by the name must be present in the request for this predicate - to be true. If the value evaluates to a header name/value - pair, the header specified by the name must be present in + to be true. + + If a string contains a colon, it will be considered a + name/value pair (e.g. ``User-Agent:Mozilla/.*`` or + ``Host:localhost``), where the value part is a regular + expression. The header specified by the name must be present in the request *and* the regular expression specified as the - value must match the header value. Whether or not the value - represents a header name or a header name/value pair, the - case of the header name is not significant. + value must match the header value. + + Whether or not the strings + represent a header name or a header name/value pair, the + case of the header name is not significant. If this + predicate returns ``False``, route matching continues. + When the value is an iterable of strings, they must all + return ``True`` for this predicate to return ``True``. path_info -- cgit v1.2.3 From c60c98b5169023f8e7f19eb841a0c72230fa6c30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Araujo?= Date: Wed, 6 May 2020 09:57:21 -0400 Subject: more rewording --- src/pyramid/config/routes.py | 36 +++++++++++++++++------------------- src/pyramid/config/views.py | 36 +++++++++++++++++------------------- 2 files changed, 34 insertions(+), 38 deletions(-) diff --git a/src/pyramid/config/routes.py b/src/pyramid/config/routes.py index 7208f5adb..41c7108df 100644 --- a/src/pyramid/config/routes.py +++ b/src/pyramid/config/routes.py @@ -220,25 +220,23 @@ class RoutesConfiguratorMixin: header This value can be a string or an iterable of strings for HTTP - header names. Any string that does not contain a ``:`` - (colon) will be considered to be the header name (e.g. - ``If-Modified-Since``). In this case, the header specified by - the name must be present in the request for this predicate - to be true. - - If a string contains a colon, it will be considered a - name/value pair (e.g. ``User-Agent:Mozilla/.*`` or - ``Host:localhost``), where the value part is a regular - expression. The header specified by the name must be present in - the request *and* the regular expression specified as the - value must match the header value. - - Whether or not the strings - represent a header name or a header name/value pair, the - case of the header name is not significant. If this - predicate returns ``False``, route matching continues. - When the value is an iterable of strings, they must all - return ``True`` for this predicate to return ``True``. + header names. The header names are determined as follow: + + - If a string does not contain a ``:`` (colon), it will be + considered to be the header name (e.g. ``If-Modified-Since``). + In this case, the header specified by the name must be present + in the request for this string to match. Case is not significant. + + - If a string contains a colon, it will be considered a + name/value pair (e.g. ``User-Agent:Mozilla/.*`` or + ``Host:localhost``), where the value part is a regular + expression. The header specified by the name must be present + in the request *and* the regular expression specified as the + value must match the header value. Case is not significant for + the header name, but it is for the value. + + All strings must be matched for this predicate to return ``True``. + If this predicate returns ``False``, route matching continues. accept diff --git a/src/pyramid/config/views.py b/src/pyramid/config/views.py index cf1b0a800..ebef7840d 100644 --- a/src/pyramid/config/views.py +++ b/src/pyramid/config/views.py @@ -671,25 +671,23 @@ class ViewsConfiguratorMixin: header This value can be a string or an iterable of strings for HTTP - header names. Any string that does not contain a ``:`` - (colon) will be considered to be the header name (e.g. - ``If-Modified-Since``). In this case, the header specified by - the name must be present in the request for this predicate - to be true. - - If a string contains a colon, it will be considered a - name/value pair (e.g. ``User-Agent:Mozilla/.*`` or - ``Host:localhost``), where the value part is a regular - expression. The header specified by the name must be present in - the request *and* the regular expression specified as the - value must match the header value. - - Whether or not the strings - represent a header name or a header name/value pair, the - case of the header name is not significant. If this - predicate returns ``False``, route matching continues. - When the value is an iterable of strings, they must all - return ``True`` for this predicate to return ``True``. + header names. The header names are determined as follow: + + - If a string does not contain a ``:`` (colon), it will be + considered to be the header name (e.g. ``If-Modified-Since``). + In this case, the header specified by the name must be present + in the request for this string to match. Case is not significant. + + - If a string contains a colon, it will be considered a + name/value pair (e.g. ``User-Agent:Mozilla/.*`` or + ``Host:localhost``), where the value part is a regular + expression. The header specified by the name must be present + in the request *and* the regular expression specified as the + value must match the header value. Case is not significant for + the header name, but it is for the value. + + All strings must be matched for this predicate to return ``True``. + If this predicate returns ``False``, view matching continues. path_info -- cgit v1.2.3 From 753f2ec403863d7408a55c5bc52511529b80a997 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Araujo?= Date: Wed, 6 May 2020 09:57:35 -0400 Subject: fix lint check --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 8c36c5f01..756233bd0 100644 --- a/setup.cfg +++ b/setup.cfg @@ -20,4 +20,4 @@ ignore = *.egg-info/* ignore-default-rules = true ignore-bad-ideas = - tests/pkgs/localeapp/* + tests/pkgs/localeapp/**/*.mo -- cgit v1.2.3 From ce6685e1b4a6c240ce9382464b1e0055a33d2b4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Araujo?= Date: Wed, 6 May 2020 10:02:46 -0400 Subject: add test to validate doc assertion --- tests/test_config/test_predicates.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/test_config/test_predicates.py b/tests/test_config/test_predicates.py index c0185340f..8017fc898 100644 --- a/tests/test_config/test_predicates.py +++ b/tests/test_config/test_predicates.py @@ -392,6 +392,12 @@ class TestPredicateList(unittest.TestCase): request.headers = {'foo': 'nobar', 'baz': 'foo'} self.assertFalse(predicates[0](Dummy(), request)) + def test_header_with_value_fails_case(self): + _, predicates, _ = self._callFUT(header='foo:bar') + request = DummyRequest() + request.headers = {'foo': 'BAR'} + self.assertFalse(predicates[0](Dummy(), request)) + def test_header_multiple(self): _, predicates, _ = self._callFUT(header=('foo', 'content-length')) request = DummyRequest() -- cgit v1.2.3 From e218437b7a3343c2abaa0875cf50e9a5bd3dbebc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Araujo?= Date: Thu, 7 May 2020 16:02:14 -0400 Subject: fix merge --- setup.cfg | 1 - 1 file changed, 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 0bda22a2f..a9e760853 100644 --- a/setup.cfg +++ b/setup.cfg @@ -18,7 +18,6 @@ ignore = ignore-default-rules = true ignore-bad-ideas = tests/pkgs/localeapp/**/*.mo - tests/pkgs/localeapp/**/*.mo [tool:pytest] python_files = test_*.py -- cgit v1.2.3 From f5a8cd2840dc6b0fea4fd7642950b5c731445776 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Araujo?= Date: Thu, 7 May 2020 23:52:19 -0400 Subject: better wording --- docs/narr/viewconfig.rst | 39 +++++++++++++++++++-------------------- src/pyramid/config/routes.py | 16 ++++++++-------- src/pyramid/config/views.py | 12 ++++++------ 3 files changed, 33 insertions(+), 34 deletions(-) diff --git a/docs/narr/viewconfig.rst b/docs/narr/viewconfig.rst index c40f1181a..b43ebb93e 100644 --- a/docs/narr/viewconfig.rst +++ b/docs/narr/viewconfig.rst @@ -391,7 +391,7 @@ configured view. the ``REQUEST_METHOD`` of the :term:`WSGI` environment. ``request_param`` - This value can be any string or a sequence of strings. A view declaration + This argument can be any string or a sequence of strings. A view declaration with this argument ensures that the view will only be called when the :term:`request` has a key in the ``request.params`` dictionary (an HTTP ``GET`` or ``POST`` variable) that has a name which matches the supplied @@ -406,7 +406,7 @@ configured view. consideration of keys and values in the ``request.params`` dictionary. ``match_param`` - This param may be either a single string of the format "key=value" or a tuple + This argument may be either a single string of the format "key=value" or a tuple containing one or more of these strings. This argument ensures that the view will only be called when the @@ -448,24 +448,23 @@ configured view. associated view callable. ``header`` - This value matches one or more HTTP header names or header name/value pairs. - - If ``header`` is specified, it must be a string or a sequence of strings, - each being a header name or a ``headername:headervalue`` pair. - - If ``header`` is specified without a value (a bare header name only, e.g., - ``If-Modified-Since``), the view will only be invoked if the HTTP header - exists with any value in the request. - - If ``header`` is specified, and possesses a name/value pair (e.g., - ``User-Agent:Mozilla/.*``), the view will only be invoked if the HTTP header - exists *and* the HTTP header matches the value requested. When the - ``headervalue`` contains a ``:`` (colon), it will be considered a name/value - pair (e.g., ``User-Agent:Mozilla/.*`` or ``Host:localhost``). The value - portion should be a regular expression. - - Whether or not the value represents a header name or a header name/value - pair, the case of the header name is not significant. + This param matches one or more HTTP header names or header name/value pairs. + If specified, this param must be a string or a sequence of strings, + each string being a header name or a ``headername:headervalue`` pair. + + - Each string specified as a bare header name without a value (for example + ``If-Modified-Since``) will match a request if it contains an HTTP header + with that same name. The case of the name is not significant, and the + header may have any value in the request. + + - Each string specified as a name/value pair (that is, if it contains a ``:`` + (colon), like ``User-Agent:Mozilla/.*``) will match a request only if it + contains an HTTP header with the requested name (ignoring case, so + ``User-Agent`` or ``user-agent`` would both match), *and* the value of the + HTTP header matches the value requested (``Mozilla/.*`` in our example). + The value portion is interpreted as a regular expression. + + The view will only be invoked if all strings are matching. If ``header`` is not specified, the composition, presence, or absence of HTTP headers is not taken into consideration when deciding whether or not to diff --git a/src/pyramid/config/routes.py b/src/pyramid/config/routes.py index 4896ce0ea..a12e18fa8 100644 --- a/src/pyramid/config/routes.py +++ b/src/pyramid/config/routes.py @@ -211,29 +211,29 @@ class RoutesConfiguratorMixin: dictionary (an HTTP ``GET`` or ``POST`` variable) that has a name which matches the supplied value. If the value supplied as the argument has a ``=`` sign in it, - e.g. ``request_param="foo=123"``, then the key - (``foo``) must both exist in the ``request.params`` dictionary, and + e.g. ``request_param="foo=123"``, then both the key + (``foo``) must exist in the ``request.params`` dictionary, and the value must match the right hand side of the expression (``123``) for the route to "match" the current request. If this predicate returns ``False``, route matching continues. header - This value can be a string or an iterable of strings for HTTP - header names. The header names are determined as follow: + This argument can be a string or an iterable of strings for HTTP + headers. The matching is determined as follow: - If a string does not contain a ``:`` (colon), it will be - considered to be the header name (e.g. ``If-Modified-Since``). + considered to be the header name (example ``If-Modified-Since``). In this case, the header specified by the name must be present in the request for this string to match. Case is not significant. - If a string contains a colon, it will be considered a - name/value pair (e.g. ``User-Agent:Mozilla/.*`` or + name/value pair (for example ``User-Agent:Mozilla/.*`` or ``Host:localhost``), where the value part is a regular expression. The header specified by the name must be present in the request *and* the regular expression specified as the - value must match the header value. Case is not significant for - the header name, but it is for the value. + value part must match the value of the request header. Case is + not significant for the header name, but it is for the value. All strings must be matched for this predicate to return ``True``. If this predicate returns ``False``, route matching continues. diff --git a/src/pyramid/config/views.py b/src/pyramid/config/views.py index 170f8a028..a064ebd05 100644 --- a/src/pyramid/config/views.py +++ b/src/pyramid/config/views.py @@ -670,21 +670,21 @@ class ViewsConfiguratorMixin: header - This value can be a string or an iterable of strings for HTTP - header names. The header names are determined as follow: + This argument can be a string or an iterable of strings for HTTP + headers. The matching is determined as follow: - If a string does not contain a ``:`` (colon), it will be - considered to be the header name (e.g. ``If-Modified-Since``). + considered to be a header name (example ``If-Modified-Since``). In this case, the header specified by the name must be present in the request for this string to match. Case is not significant. - If a string contains a colon, it will be considered a - name/value pair (e.g. ``User-Agent:Mozilla/.*`` or + name/value pair (for example ``User-Agent:Mozilla/.*`` or ``Host:localhost``), where the value part is a regular expression. The header specified by the name must be present in the request *and* the regular expression specified as the - value must match the header value. Case is not significant for - the header name, but it is for the value. + value part must match the value of the request header. Case is + not significant for the header name, but it is for the value. All strings must be matched for this predicate to return ``True``. If this predicate returns ``False``, view matching continues. -- cgit v1.2.3