Add an argument to the .update() method for explicit error handling

This is not yet particularly apparent with the current error conditions,
but in follow up commits we are going to make use of this facility for
good causes:

In some circumstances, it might be desirable to explicitly handle
error conditions - and in fact the .update() method is already,
historically, prepared for this pattern from the days before intro-
duction of VRT_fail()
parent 92dca54a
......@@ -25,7 +25,7 @@ SYNOPSIS
new xdigest = blobdigest.digest(ENUM hash, BLOB init, ENUM scope)
BOOL xdigest.update(BLOB msg)
BOOL xdigest.update(BLOB msg, BOOL fail)
BLOB xdigest.final()
......@@ -140,7 +140,7 @@ Here are some examples::
sub vcl_recv {
# Use the fooprefix object to get the hash of "foobar"
if (!fooprefix.update(blob.decode(encoded="bar"))) {
if (!fooprefix.update(blob.decode(encoded="bar"), fail=false)) {
call do_error;
}
set req.http.Foobar-Hash = blob.encode(encoding=BASE64,
......@@ -152,7 +152,7 @@ Here are some examples::
# The uses of the object in client and backend contexts have
# no effect on each other, or on subsequent client or
# backend transactions.
if (!fooprefix.update(blob.decode(encoded="baz"))) {
if (!fooprefix.update(blob.decode(encoded="baz"), fail=false)) {
call do_error;
}
set req.http.Foobaz-Hash = blob.encode(encoding=BASE64,
......@@ -266,8 +266,8 @@ Example::
.. _xdigest.update():
BOOL xdigest.update(BLOB msg)
-----------------------------
BOOL xdigest.update(BLOB msg, BOOL fail=1)
------------------------------------------
Incrementally add the BLOB ``msg`` to the digest context of this
object. Returns ``true`` if and only if the operation was successful.
......@@ -280,11 +280,15 @@ task (client or backend transaction).
This method MAY NOT be called after ``.final()`` has been called
for the same object, either in ``vcl_init`` or in the current task.
The method fails and returns ``false`` if ``msg`` is NULL, or if it is
called after ``.final()``. If it fails in ``vcl_init``, the VCL load
will fail with an error message. If it fails in any other VCL
subroutine, an error message is emitted to the Varnish log with the
``VCL_Error`` tag, and the message digest context is unchanged.
The method returns ``false`` if ``msg`` is NULL, or if it is called
after ``.final()``. If the ``fail`` argument is ``true`` (the
default), this also triggers a VCL Error. A ``fail=false`` argument
can be used for explicit error handling.
If it fails in ``vcl_init``, the VCL load will fail with an error
message. If it fails in any other VCL subroutine, an error message is
emitted to the Varnish log with the ``VCL_Error`` tag, and the message
digest context is unchanged.
Example::
......@@ -310,13 +314,13 @@ Example::
sub vcl_recv {
# Update the SHA3_256 digest in the current client transaction
if (!sha3_256.update(blob.blob(IDENTITY, "bar"))) {
if (!sha3_256.update(blob.blob(IDENTITY, "bar")), fail=false) {
call do_client_error;
}
sub vcl_backend_fetch {
# Update the SHA3_256 digest in the current backend transaction
if (!sha3_256.update(blob.blob(IDENTITY, "baz"))) {
if (!sha3_256.update(blob.blob(IDENTITY, "baz")), fail=false) {
call do_backend_error;
}
......
......@@ -87,6 +87,13 @@ varnish v1 -vcl+backend {
}
sub vcl_backend_fetch {
if (bereq.url == "/handle") {
d2.final();
if (! d2.update(blob.decode(encoded="illegal"),
fail=false)) {
return (error(400));
}
}
if (bereq.url == "/fail") {
dtop.update(blob.decode(encoded="illegal"));
}
......@@ -129,6 +136,10 @@ client c1 {
expect resp.http.d2_c1 == "0CC175B9C0F1B6A831C399E269772661"
expect resp.http.d2_c2 == "0CC175B9C0F1B6A831C399E269772661"
txreq -url "/handle"
rxresp
expect resp.status == 400
txreq -url "/fail"
rxresp
expect resp.status == 503
......
......@@ -444,7 +444,8 @@ vmod_digest__fini(struct vmod_blobdigest_digest **digestp)
}
VCL_BOOL
vmod_digest_update(VRT_CTX, struct vmod_blobdigest_digest *h, VCL_BLOB b)
vmod_digest_update(VRT_CTX, struct vmod_blobdigest_digest *h, VCL_BLOB b,
VCL_BOOL fail)
{
struct digest_task *task;
hash_ctx *hctx;
......@@ -453,7 +454,7 @@ vmod_digest_update(VRT_CTX, struct vmod_blobdigest_digest *h, VCL_BLOB b)
CHECK_OBJ_NOTNULL(h, VMOD_BLOBDIGEST_DIGEST_MAGIC);
if (h->result != NULL) {
VFAIL(ctx, "already finalized in %s.update()", h->vcl_name);
VERR(fail, ctx, "already finalized in %s.update()", h->vcl_name);
return (0);
}
......@@ -462,14 +463,14 @@ vmod_digest_update(VRT_CTX, struct vmod_blobdigest_digest *h, VCL_BLOB b)
return (0);
if (b == NULL) {
VFAIL(ctx, "null BLOB passed to %s.update()", h->vcl_name);
VERR(fail, ctx, "null BLOB passed to %s.update()", h->vcl_name);
return (0);
}
hctx = INIT_FINI(ctx) ? &h->ctx : &task->ctx;
if (task->result != NULL) {
VFAIL(ctx, "already finalized in %s.update()", h->vcl_name);
VERR(fail, ctx, "already finalized in %s.update()", h->vcl_name);
return (0);
}
if (b->len > 0 && b->blob != NULL)
......
......@@ -108,7 +108,7 @@ Here are some examples::
sub vcl_recv {
# Use the fooprefix object to get the hash of "foobar"
if (!fooprefix.update(blob.decode(encoded="bar"))) {
if (!fooprefix.update(blob.decode(encoded="bar"), fail=false)) {
call do_error;
}
set req.http.Foobar-Hash = blob.encode(encoding=BASE64,
......@@ -120,7 +120,7 @@ Here are some examples::
# The uses of the object in client and backend contexts have
# no effect on each other, or on subsequent client or
# backend transactions.
if (!fooprefix.update(blob.decode(encoded="baz"))) {
if (!fooprefix.update(blob.decode(encoded="baz"), fail=false)) {
call do_error;
}
set req.http.Foobaz-Hash = blob.encode(encoding=BASE64,
......@@ -223,7 +223,7 @@ Example::
new sha512 = blobdigest.digest(SHA512, foo.get());
}
$Method BOOL .update(BLOB msg)
$Method BOOL .update(BLOB msg, BOOL fail=1)
Incrementally add the BLOB ``msg`` to the digest context of this
object. Returns ``true`` if and only if the operation was successful.
......@@ -236,11 +236,15 @@ task (client or backend transaction).
This method MAY NOT be called after ``.final()`` has been called
for the same object, either in ``vcl_init`` or in the current task.
The method fails and returns ``false`` if ``msg`` is NULL, or if it is
called after ``.final()``. If it fails in ``vcl_init``, the VCL load
will fail with an error message. If it fails in any other VCL
subroutine, an error message is emitted to the Varnish log with the
``VCL_Error`` tag, and the message digest context is unchanged.
The method returns ``false`` if ``msg`` is NULL, or if it is called
after ``.final()``. If the ``fail`` argument is ``true`` (the
default), this also triggers a VCL Error. A ``fail=false`` argument
can be used for explicit error handling.
If it fails in ``vcl_init``, the VCL load will fail with an error
message. If it fails in any other VCL subroutine, an error message is
emitted to the Varnish log with the ``VCL_Error`` tag, and the message
digest context is unchanged.
Example::
......@@ -266,13 +270,13 @@ Example::
sub vcl_recv {
# Update the SHA3_256 digest in the current client transaction
if (!sha3_256.update(blob.blob(IDENTITY, "bar"))) {
if (!sha3_256.update(blob.blob(IDENTITY, "bar")), fail=false) {
call do_client_error;
}
sub vcl_backend_fetch {
# Update the SHA3_256 digest in the current backend transaction
if (!sha3_256.update(blob.blob(IDENTITY, "baz"))) {
if (!sha3_256.update(blob.blob(IDENTITY, "baz")), fail=false) {
call do_backend_error;
}
......
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