Commit 61dfec02 authored by Geoff Simmons's avatar Geoff Simmons

Add the element parameter to .matched().

parent 44080166
...@@ -38,7 +38,7 @@ SYNOPSIS ...@@ -38,7 +38,7 @@ SYNOPSIS
# Match properties # Match properties
INT <obj>.nmatches() INT <obj>.nmatches()
BOOL <obj>.matched([INT n] [, ENUM select]) BOOL <obj>.matched([INT n] [, STRING element] [, ENUM select])
INT <obj>.which([ENUM select]) INT <obj>.which([ENUM select])
# Retrieving objects after match # Retrieving objects after match
...@@ -618,59 +618,74 @@ Example:: ...@@ -618,59 +618,74 @@ Example::
.. _xset.matched(): .. _xset.matched():
BOOL xset.matched(INT n, ENUM select) BOOL xset.matched(INT n, STRING element, ENUM select)
------------------------------------- -----------------------------------------------------
:: ::
BOOL xset.matched( BOOL xset.matched(
INT n=0, INT n=0,
STRING element=0,
ENUM {UNIQUE, EXACT, FIRST, LAST, SHORTEST, LONGEST} select=UNIQUE ENUM {UNIQUE, EXACT, FIRST, LAST, SHORTEST, LONGEST} select=UNIQUE
) )
After a successful ``.match()`` or ``.hasprefix()`` call for the same After a successful ``.match()`` or ``.hasprefix()`` call for the same
set object in the same task scope, return ``true`` if the element set object in the same task scope, return ``true`` if the element
indicated by the ``n`` and ``select`` parameters was matched, according to indicated by the ``n``, ``element`` and ``select`` parameters was
the rules described above. matched, according to the rules described above.
For example if ``n`` > 0, ``.matched(n)`` returns ``true`` if and only For example if ``n`` > 0, ``.matched(n)`` returns ``true`` if and only
if the ``n``-th element matched. The numbering corresponds to the if the ``n``-th element matched. The numbering corresponds to the
order of ``.add()`` invocations in ``vcl_init`` (starting from 1). The order of ``.add()`` invocations in ``vcl_init`` (starting from 1). The
``select`` parameter is ignored in this case. ``select`` and ``element`` parameters are ignored in this case.
If ``n`` <= 0, the set element is determined by the ``select`` enum. If ``n`` <= 0 and ``element`` is set, then ``.matched()`` returns
In that case, ``.matched()`` returns ``true`` if and only if the ``true`` if and only if the string specified by ``element`` was
element indicated by the enum was matched by the previous successful matched in the previous successful ``.match()`` or ``.hasprefix()``
match operation. These distinctions are only relevant if the previous call. If ``element`` is not in the set, then ``.matched()`` does not
operation was ``.hasprefix()``, and more than one string was matched invoke VCL failure (this is a deviation from the general rules for
due to overlapping prefixes. ``.matched()`` returns ``true`` for all ``element``), but ``.matched()`` always returns ``false`` in that
values of ``select`` if the previous successful operation was case. Thus ``.matched()`` can always used with ``element`` to safely
``.match()``. ``n`` defaults to 0, so the ``n`` parameter can be left check if a string was previously matched, regardless of whether the
out if the use of ``select`` is intended. string is in the set.
If ``n`` <= 0 and ``select`` is ``UNIQUE`` or ``EXACT``, then ``n`` defaults to 0, so the ``n`` parameter can be left out if
``.matched()`` returns ``true`` if the enum's criteria are met; ``element`` is set.
otherwise it returns ``false``, and does not fail. This can be used as
a safeguard for the methods described below, which invoke VCL failure If ``n`` <= 0 and ``element`` is unset, the set element is determined
if either of these two enums are specified, but their criteria are not by the ``select`` enum. In that case, ``.matched()`` returns ``true``
met. if and only if the element indicated by the enum was matched by the
previous successful match operation. These distinctions are only
relevant if the previous operation was ``.hasprefix()``, and more than
one string was matched due to overlapping prefixes. ``.matched()``
returns ``true`` for all values of ``select`` if the previous
successful operation was ``.match()``.
``n`` defaults to 0 and ``element`` is unset by default, so the ``n``
and ``element`` parameters can be left out if the use of ``select`` is
intended.
If ``n`` <= 0, ``element`` is unset, and ``select`` is ``UNIQUE`` or
``EXACT``, then ``.matched()`` returns ``true`` if the enum's criteria
are met; otherwise it returns ``false``, and does not fail. This can
be used as a safeguard for the methods described below, which invoke
VCL failure if either of these two enums are specified, but their
criteria are not met.
The other enum values (``FIRST``, ``LAST``, ``SHORTEST`` and The other enum values (``FIRST``, ``LAST``, ``SHORTEST`` and
``LONGEST``) are included for consistency with the other methods, but ``LONGEST``) are included for consistency with the other methods, but
they don't make a relevant distinction. If the prior invocation of they don't make a relevant distinction. If the prior invocation of
``.match()`` or ``.hasprefix()`` was successful (returned ``true``), ``.match()`` or ``.hasprefix()`` was successful (returned ``true``),
then ``.matched()`` returns ``true`` for each of these, since there is then ``.matched()`` returns ``true`` for each of these, since there is
always an element that meets the criteria. If the prior invocation was always an element that meets the criteria.
unsuccessful, ``.matched()`` always returns ``false`` for each of the
four enums.
``.matched()`` always returns ``false`` if the most recent ``.matched()`` always returns ``false`` if the most recent
``.match()`` or ``.hasprefix()`` call returned ``false``. ``.match()`` or ``.hasprefix()`` call returned ``false``.
``.matched()`` invokes VCL failure if: ``.matched()`` invokes VCL failure if:
* The parameter is out of range -- greater than the number of elements * The ``n`` parameter is out of range -- greater than the number of
in the set. elements in the set.
* There was no prior invocation of ``.match()`` or ``.hasprefix()`` in * There was no prior invocation of ``.match()`` or ``.hasprefix()`` in
the same task scope. the same task scope.
...@@ -689,6 +704,12 @@ Example:: ...@@ -689,6 +704,12 @@ Example::
} }
} }
if (url_prefixes.hasprefix(bereq.url)) {
if (urls.matched(element="/foo/")) {
call do_if_foo_was_matched;
}
}
.. _xset.which(): .. _xset.which():
INT xset.which(ENUM select) INT xset.which(ENUM select)
...@@ -1059,10 +1080,10 @@ failure is invoked. VCL failure has the same results as if ...@@ -1059,10 +1080,10 @@ failure is invoked. VCL failure has the same results as if
VCL failure is meant to "fail fast" on conditions that cannot be VCL failure is meant to "fail fast" on conditions that cannot be
correct, or when resource limitations such as workspace exhaustion correct, or when resource limitations such as workspace exhaustion
prevent further processing. Depending on your use case, you may be prevent further processing. Depending on your use case, you may be
able to use the VMOD's methods without risk of failure. For example, able to use the VMOD's methods without additional checking and with no
if it is known that none of the strings in a set have common prefixes, risk of failure. For example, if it is known that none of the strings
then methods with ``select=UNIQUE`` can be used safely after calling in a set have common prefixes, then methods with ``select=UNIQUE`` can
``.hasprefix()``. be used safely after calling ``.hasprefix()``.
If you need to check against possible failure conditions: If you need to check against possible failure conditions:
...@@ -1075,6 +1096,12 @@ If you need to check against possible failure conditions: ...@@ -1075,6 +1096,12 @@ If you need to check against possible failure conditions:
ensure that VCL load fails if a set unintentionally has strings ensure that VCL load fails if a set unintentionally has strings
with common prefixes. with common prefixes.
* In most cases, a method invokes VCL failure if the value of the
``element`` parameter is not in the set. But ``element`` can be used
safely with any string in ``.matched()`` to check if a string
matched previously -- ``.matched()`` returns ``false`` if the
``element`` is not in the set.
See `LIMITATIONS`_ for considerations if you encounter conditions such See `LIMITATIONS`_ for considerations if you encounter conditions such
as workspace exhaustion. as workspace exhaustion.
......
...@@ -837,12 +837,16 @@ varnish v1 -vcl { ...@@ -837,12 +837,16 @@ varnish v1 -vcl {
set resp.http.Matched-Last = s.matched(select=LAST); set resp.http.Matched-Last = s.matched(select=LAST);
set resp.http.Matched-Shortest = s.matched(select=SHORTEST); set resp.http.Matched-Shortest = s.matched(select=SHORTEST);
set resp.http.Matched-Longest = s.matched(select=LONGEST); set resp.http.Matched-Longest = s.matched(select=LONGEST);
set resp.http.Matched-Foo = s.matched(element="foo");
set resp.http.Matched-Baz = s.matched(element="baz");
set resp.http.Non-Match = s.hasprefix("baz"); set resp.http.Non-Match = s.hasprefix("baz");
set resp.http.Non-Matched-First = s.matched(select=FIRST); set resp.http.Non-Matched-First = s.matched(select=FIRST);
set resp.http.Non-Matched-Last = s.matched(select=LAST); set resp.http.Non-Matched-Last = s.matched(select=LAST);
set resp.http.Non-Matched-Shortest = s.matched(select=SHORTEST); set resp.http.Non-Matched-Shortest = s.matched(select=SHORTEST);
set resp.http.Non-Matched-Longest = s.matched(select=LONGEST); set resp.http.Non-Matched-Longest = s.matched(select=LONGEST);
set resp.http.Non-Matched-Foo = s.matched(element="foo");
set resp.http.Non-Matched-Baz = s.matched(element="baz");
return (deliver); return (deliver);
} }
...@@ -857,11 +861,15 @@ client c1 { ...@@ -857,11 +861,15 @@ client c1 {
expect resp.http.Matched-Last == "true" expect resp.http.Matched-Last == "true"
expect resp.http.Matched-Shortest == "true" expect resp.http.Matched-Shortest == "true"
expect resp.http.Matched-Longest == "true" expect resp.http.Matched-Longest == "true"
expect resp.http.Matched-Foo == "true"
expect resp.http.Matched-Baz == "false"
expect resp.http.Non-Match == "false" expect resp.http.Non-Match == "false"
expect resp.http.Non-Matched-First == "false" expect resp.http.Non-Matched-First == "false"
expect resp.http.Non-Matched-Last == "false" expect resp.http.Non-Matched-Last == "false"
expect resp.http.Non-Matched-Shortest == "false" expect resp.http.Non-Matched-Shortest == "false"
expect resp.http.Non-Matched-Longest == "false" expect resp.http.Non-Matched-Longest == "false"
expect resp.http.Non-Matched-Foo == "false"
expect resp.http.Non-Matched-Baz == "false"
txreq -hdr "Range-Error: oops" txreq -hdr "Range-Error: oops"
rxresp rxresp
......
...@@ -606,7 +606,7 @@ vmod_set_nmatches(VRT_CTX, struct vmod_selector_set *set) ...@@ -606,7 +606,7 @@ vmod_set_nmatches(VRT_CTX, struct vmod_selector_set *set)
VCL_BOOL VCL_BOOL
vmod_set_matched(VRT_CTX, struct VPFX(selector_set) *set, VCL_INT idx, vmod_set_matched(VRT_CTX, struct VPFX(selector_set) *set, VCL_INT idx,
VCL_ENUM selects) VCL_STRING element, VCL_ENUM selects)
{ {
struct match_data *match; struct match_data *match;
...@@ -636,6 +636,14 @@ vmod_set_matched(VRT_CTX, struct VPFX(selector_set) *set, VCL_INT idx, ...@@ -636,6 +636,14 @@ vmod_set_matched(VRT_CTX, struct VPFX(selector_set) *set, VCL_INT idx,
return (0); return (0);
} }
if (element != NULL) {
for (unsigned i = 0; i < match->n; i++)
if (strcmp(set->members[match->indices[i]], element)
== 0)
return (1);
return (0);
}
if (selects == VENUM(UNIQUE)) if (selects == VENUM(UNIQUE))
return (match->n == 1); return (match->n == 1);
if (selects == VENUM(EXACT)) if (selects == VENUM(EXACT))
......
...@@ -34,7 +34,7 @@ SYNOPSIS ...@@ -34,7 +34,7 @@ SYNOPSIS
# Match properties # Match properties
INT <obj>.nmatches() INT <obj>.nmatches()
BOOL <obj>.matched([INT n] [, ENUM select]) BOOL <obj>.matched([INT n] [, STRING element] [, ENUM select])
INT <obj>.which([ENUM select]) INT <obj>.which([ENUM select])
# Retrieving objects after match # Retrieving objects after match
...@@ -575,53 +575,67 @@ Example:: ...@@ -575,53 +575,67 @@ Example::
set bereq.backend = myset.backend(select=UNIQUE); set bereq.backend = myset.backend(select=UNIQUE);
} }
$Method BOOL .matched(INT n=0, $Method BOOL .matched(INT n=0, STRING element=0,
ENUM {UNIQUE, EXACT, FIRST, LAST, SHORTEST, LONGEST} ENUM {UNIQUE, EXACT, FIRST, LAST, SHORTEST, LONGEST}
select=UNIQUE) select=UNIQUE)
After a successful ``.match()`` or ``.hasprefix()`` call for the same After a successful ``.match()`` or ``.hasprefix()`` call for the same
set object in the same task scope, return ``true`` if the element set object in the same task scope, return ``true`` if the element
indicated by the ``n`` and ``select`` parameters was matched, according to indicated by the ``n``, ``element`` and ``select`` parameters was
the rules described above. matched, according to the rules described above.
For example if ``n`` > 0, ``.matched(n)`` returns ``true`` if and only For example if ``n`` > 0, ``.matched(n)`` returns ``true`` if and only
if the ``n``-th element matched. The numbering corresponds to the if the ``n``-th element matched. The numbering corresponds to the
order of ``.add()`` invocations in ``vcl_init`` (starting from 1). The order of ``.add()`` invocations in ``vcl_init`` (starting from 1). The
``select`` parameter is ignored in this case. ``select`` and ``element`` parameters are ignored in this case.
If ``n`` <= 0, the set element is determined by the ``select`` enum. If ``n`` <= 0 and ``element`` is set, then ``.matched()`` returns
In that case, ``.matched()`` returns ``true`` if and only if the ``true`` if and only if the string specified by ``element`` was
element indicated by the enum was matched by the previous successful matched in the previous successful ``.match()`` or ``.hasprefix()``
match operation. These distinctions are only relevant if the previous call. If ``element`` is not in the set, then ``.matched()`` does not
operation was ``.hasprefix()``, and more than one string was matched invoke VCL failure (this is a deviation from the general rules for
due to overlapping prefixes. ``.matched()`` returns ``true`` for all ``element``), but ``.matched()`` always returns ``false`` in that
values of ``select`` if the previous successful operation was case. Thus ``.matched()`` can always used with ``element`` to safely
``.match()``. ``n`` defaults to 0, so the ``n`` parameter can be left check if a string was previously matched, regardless of whether the
out if the use of ``select`` is intended. string is in the set.
If ``n`` <= 0 and ``select`` is ``UNIQUE`` or ``EXACT``, then ``n`` defaults to 0, so the ``n`` parameter can be left out if
``.matched()`` returns ``true`` if the enum's criteria are met; ``element`` is set.
otherwise it returns ``false``, and does not fail. This can be used as
a safeguard for the methods described below, which invoke VCL failure If ``n`` <= 0 and ``element`` is unset, the set element is determined
if either of these two enums are specified, but their criteria are not by the ``select`` enum. In that case, ``.matched()`` returns ``true``
met. if and only if the element indicated by the enum was matched by the
previous successful match operation. These distinctions are only
relevant if the previous operation was ``.hasprefix()``, and more than
one string was matched due to overlapping prefixes. ``.matched()``
returns ``true`` for all values of ``select`` if the previous
successful operation was ``.match()``.
``n`` defaults to 0 and ``element`` is unset by default, so the ``n``
and ``element`` parameters can be left out if the use of ``select`` is
intended.
If ``n`` <= 0, ``element`` is unset, and ``select`` is ``UNIQUE`` or
``EXACT``, then ``.matched()`` returns ``true`` if the enum's criteria
are met; otherwise it returns ``false``, and does not fail. This can
be used as a safeguard for the methods described below, which invoke
VCL failure if either of these two enums are specified, but their
criteria are not met.
The other enum values (``FIRST``, ``LAST``, ``SHORTEST`` and The other enum values (``FIRST``, ``LAST``, ``SHORTEST`` and
``LONGEST``) are included for consistency with the other methods, but ``LONGEST``) are included for consistency with the other methods, but
they don't make a relevant distinction. If the prior invocation of they don't make a relevant distinction. If the prior invocation of
``.match()`` or ``.hasprefix()`` was successful (returned ``true``), ``.match()`` or ``.hasprefix()`` was successful (returned ``true``),
then ``.matched()`` returns ``true`` for each of these, since there is then ``.matched()`` returns ``true`` for each of these, since there is
always an element that meets the criteria. If the prior invocation was always an element that meets the criteria.
unsuccessful, ``.matched()`` always returns ``false`` for each of the
four enums.
``.matched()`` always returns ``false`` if the most recent ``.matched()`` always returns ``false`` if the most recent
``.match()`` or ``.hasprefix()`` call returned ``false``. ``.match()`` or ``.hasprefix()`` call returned ``false``.
``.matched()`` invokes VCL failure if: ``.matched()`` invokes VCL failure if:
* The parameter is out of range -- greater than the number of elements * The ``n`` parameter is out of range -- greater than the number of
in the set. elements in the set.
* There was no prior invocation of ``.match()`` or ``.hasprefix()`` in * There was no prior invocation of ``.match()`` or ``.hasprefix()`` in
the same task scope. the same task scope.
...@@ -640,6 +654,12 @@ Example:: ...@@ -640,6 +654,12 @@ Example::
} }
} }
if (url_prefixes.hasprefix(bereq.url)) {
if (urls.matched(element="/foo/")) {
call do_if_foo_was_matched;
}
}
$Method INT .which(ENUM {UNIQUE, EXACT, FIRST, LAST, SHORTEST, LONGEST} $Method INT .which(ENUM {UNIQUE, EXACT, FIRST, LAST, SHORTEST, LONGEST}
select=UNIQUE) select=UNIQUE)
...@@ -943,10 +963,10 @@ failure is invoked. VCL failure has the same results as if ...@@ -943,10 +963,10 @@ failure is invoked. VCL failure has the same results as if
VCL failure is meant to "fail fast" on conditions that cannot be VCL failure is meant to "fail fast" on conditions that cannot be
correct, or when resource limitations such as workspace exhaustion correct, or when resource limitations such as workspace exhaustion
prevent further processing. Depending on your use case, you may be prevent further processing. Depending on your use case, you may be
able to use the VMOD's methods without risk of failure. For example, able to use the VMOD's methods without additional checking and with no
if it is known that none of the strings in a set have common prefixes, risk of failure. For example, if it is known that none of the strings
then methods with ``select=UNIQUE`` can be used safely after calling in a set have common prefixes, then methods with ``select=UNIQUE`` can
``.hasprefix()``. be used safely after calling ``.hasprefix()``.
If you need to check against possible failure conditions: If you need to check against possible failure conditions:
...@@ -959,6 +979,12 @@ If you need to check against possible failure conditions: ...@@ -959,6 +979,12 @@ If you need to check against possible failure conditions:
ensure that VCL load fails if a set unintentionally has strings ensure that VCL load fails if a set unintentionally has strings
with common prefixes. with common prefixes.
* In most cases, a method invokes VCL failure if the value of the
``element`` parameter is not in the set. But ``element`` can be used
safely with any string in ``.matched()`` to check if a string
matched previously -- ``.matched()`` returns ``false`` if the
``element`` is not in the set.
See `LIMITATIONS`_ for considerations if you encounter conditions such See `LIMITATIONS`_ for considerations if you encounter conditions such
as workspace exhaustion. as workspace exhaustion.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment