Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
libvmod-blobdigest
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
2
Issues
2
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
uplex-varnish
libvmod-blobdigest
Commits
e2756ace
Commit
e2756ace
authored
Oct 30, 2017
by
Nils Goroll
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
basic support for scope=TOP digests
parent
4b12af66
Pipeline
#358
skipped
Changes
5
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
212 additions
and
27 deletions
+212
-27
README.rst
README.rst
+10
-3
esi.vtc
src/tests/esi.vtc
+103
-0
usage.vtc
src/tests/usage.vtc
+26
-5
vmod_blobdigest.c
src/vmod_blobdigest.c
+63
-17
vmod_blobdigest.vcc
src/vmod_blobdigest.vcc
+10
-2
No files found.
README.rst
View file @
e2756ace
...
...
@@ -26,7 +26,7 @@ import blobdigest [from "path"] ;
::
new OBJECT = blobdigest.digest(ENUM hash [, BLOB init])
new OBJECT = blobdigest.digest(ENUM hash [, BLOB init]
, ["TASK"|"TOP"]
)
BOOL <obj>.update(BLOB)
BLOB <obj>.final()
...
...
@@ -202,7 +202,7 @@ values:
CONTENTS
========
* digest(ENUM {CRC32,MD5,SHA1,SHA224,SHA256,SHA384,SHA512,SHA3_224,SHA3_256,SHA3_384,SHA3_512}, BLOB)
* digest(ENUM {CRC32,MD5,SHA1,SHA224,SHA256,SHA384,SHA512,SHA3_224,SHA3_256,SHA3_384,SHA3_512}, BLOB
, ENUM {TASK,TOP}
)
* BLOB hash(ENUM {CRC32,MD5,SHA1,SHA224,SHA256,SHA384,SHA512,SHA3_224,SHA3_256,SHA3_384,SHA3_512}, BLOB)
* hmac(ENUM {MD5,SHA1,SHA224,SHA256,SHA384,SHA512,SHA3_224,SHA3_256,SHA3_384,SHA3_512}, BLOB)
* BLOB hmacf(ENUM {MD5,SHA1,SHA224,SHA256,SHA384,SHA512,SHA3_224,SHA3_256,SHA3_384,SHA3_512}, BLOB, BLOB)
...
...
@@ -215,7 +215,7 @@ digest
::
new OBJ = digest(ENUM {CRC32,MD5,SHA1,SHA224,SHA256,SHA384,SHA512,SHA3_224,SHA3_256,SHA3_384,SHA3_512} hash, BLOB init=0)
new OBJ = digest(ENUM {CRC32,MD5,SHA1,SHA224,SHA256,SHA384,SHA512,SHA3_224,SHA3_256,SHA3_384,SHA3_512} hash, BLOB init=0
, ENUM {TASK,TOP} scope="TASK"
)
Initialize a message digest context for the algorithm ``hash``, and
optionally update it with ``init``. If ``init`` is left out, then an
...
...
@@ -225,6 +225,13 @@ If an ``init`` BLOB is provided, then the message digests computed
from this object result with ``init`` prepended before any BLOBs added
by the ``.update()`` method.
By default, the scope of the message digest context is ``TASK``:
method calls affect separate context states for the client and backend
side.
``TOP`` scope provides a context across all ESI subrequests, but is
available only on the client side.
Example::
import blobdigest;
...
...
src/tests/esi.vtc
0 → 100644
View file @
e2756ace
# looks like -*- vcl -*-
varnishtest "digest scope=TOP"
server s1 {
rxreq
txresp -body {
<html>
Before include
<esi:include
src=
"/body"
sr=
"foo"
/>
After include
</html>
}
rxreq
expect req.url == "/body1"
txresp -body {
Included file
}
} -start
varnish v1 -vcl+backend {
import blobdigest from "${vmod_topbuild}/src/.libs/libvmod_blobdigest.so";
import blob;
sub vcl_init {
new a = blob.blob(IDENTITY, "a");
new dtop = blobdigest.digest(MD5, scope=TOP);
}
sub vcl_recv {
if (req.esi_level > 0) {
dtop.update(blob.decode(encoded=req.esi_level));
set req.url = req.url + req.esi_level;
}
}
sub vcl_backend_response {
set beresp.do_esi = true;
}
sub vcl_deliver {
dtop.update(a.get());
if (req.esi_level > 0) {
# this does not make it into the final response because
# esi level 0 deliver runs before level1 and level1
# response headers are not relevant
set resp.http.hash = blob.encode(HEX, blob=dtop.final());
}
}
} -start
logexpect l1 -v v1 -g request {
expect 0 1001 Begin "^req .* rxreq"
expect * = ReqAcct "^18 0 18 187 75 262$"
expect 0 = End
} -start
logexpect l2 -v v1 -g request {
expect * 1002 Begin "^bereq "
expect * = End
} -start
logexpect l3 -v v1 -g request {
expect * 1003 Begin "^req .* esi"
#echo -n 'a1a'|md5sum
expect * = RespHeader "^hash: 278571846829dfd761550039130ff75f$"
expect * = ReqAcct "^0 0 0 0 18 18$"
expect 0 = End
} -start
logexpect l4 -v v1 -g request {
expect * 1004 Begin "^bereq "
expect * = End
} -start
logexpect l5 -v v1 -g request {
expect * 1005 Begin "^req .* rxreq"
expect * = ReqAcct "^18 0 18 192 75 267$"
expect 0 = End
} -start
client c1 {
txreq
rxresp
expect resp.bodylen == 75
expect resp.status == 200
delay .1
# test that there is no difference on miss/hit
txreq
rxresp
expect resp.bodylen == 75
expect resp.status == 200
}
client c1 -run
varnish v1 -expect esi_errors == 0
logexpect l1 -wait
logexpect l2 -wait
logexpect l3 -wait
logexpect l4 -wait
logexpect l5 -wait
src/tests/usage.vtc
View file @
e2756ace
...
...
@@ -55,6 +55,7 @@ client c1 {
} -run
# Test repeated calls of the digest.final() method
# and TOP scope error on the backend side
server s1 {
rxreq
txresp -hdr "Cache-Control: max-age=0"
...
...
@@ -82,6 +83,13 @@ varnish v1 -vcl+backend {
}
new d2 = blobdigest.digest(MD5);
new dtop = blobdigest.digest(MD5, scope=TOP);
}
sub vcl_backend_fetch {
if (bereq.url == "/fail") {
dtop.update(blob.decode(encoded="illegal"));
}
}
sub vcl_backend_response {
...
...
@@ -120,6 +128,17 @@ client c1 {
expect resp.http.d2_b2 == "F96B697D7CB7938D525A2F31AAF161D0"
expect resp.http.d2_c1 == "0CC175B9C0F1B6A831C399E269772661"
expect resp.http.d2_c2 == "0CC175B9C0F1B6A831C399E269772661"
txreq -url "/fail"
rxresp
expect resp.status == 503
} -run
logexpect l0 -v v1 -d 1 -g vxid -q "VCL_Error" {
expect * * Begin "^bereq"
expect * = BereqURL "^/fail"
expect * = VCL_Error "^vmod blobdigest error: dtop.update..: object has TOP scope - only accessible in client VCL context$"
expect * = End
} -run
# digest.update() may not be called after digest.final()
...
...
@@ -171,6 +190,12 @@ varnish v1 -vcl {
}
}
logexpect l1 -v v1 -g vxid -q "VCL_Error" {
expect 0 * Begin req
expect * = VCL_Error "^vmod blobdigest error: already finalized in d1.update..$"
expect * = End
} -start
client c1 {
txreq
rxresp
...
...
@@ -178,11 +203,7 @@ client c1 {
expect resp.http.empty == "D41D8CD98F00B204E9800998ECF8427E"
} -run
logexpect l1 -v v1 -d 1 -g vxid -q "VCL_Error" {
expect 0 * Begin req
expect * = VCL_Error "^vmod blobdigest error: already finalized in d1.update..$"
expect * = End
} -run
logexpect l1 -wait
# hash() is legal in vcl_init and vcl_fini (as of Varnish 5.0)
varnish v2 -arg "-p debug=+vclrel" -vcl {
...
...
src/vmod_blobdigest.c
View file @
e2756ace
...
...
@@ -62,6 +62,12 @@ struct digest_task {
struct
vmod_priv
*
result
;
};
enum
scope
{
_SCOPE_INVALID
=
0
,
PRIV_TASK
,
PRIV_TOP
};
struct
vmod_blobdigest_digest
{
unsigned
magic
;
#define VMOD_BLOBDIGEST_DIGEST_MAGIC 0xaccb2e25
...
...
@@ -69,6 +75,7 @@ struct vmod_blobdigest_digest {
char
*
vcl_name
;
struct
vmod_priv
*
result
;
enum
algorithm
hash
;
enum
scope
scope
;
};
struct
vmod_blobdigest_hmac
{
...
...
@@ -237,21 +244,49 @@ WS_Contains(struct ws * const restrict ws, const void * const restrict ptr,
static
struct
digest_task
*
get_scope
(
const
struct
vrt_ctx
*
const
restrict
ctx
,
const
struct
vmod_blobdigest_digest
*
const
restrict
h
)
const
struct
vmod_blobdigest_digest
*
const
restrict
h
,
const
char
*
const
restrict
method
)
{
struct
vmod_priv
*
priv
;
struct
digest_task
*
task
;
struct
ws
*
ws
;
switch
(
h
->
scope
)
{
case
PRIV_TASK
:
priv
=
VRT_priv_task
(
ctx
,
(
void
*
)
h
);
ws
=
ctx
->
ws
;
break
;
case
PRIV_TOP
:
{
if
(
ctx
->
req
==
NULL
)
{
VERR
(
ctx
,
"%s.%s(): object has TOP scope - only "
"accessible in client VCL context"
,
h
->
vcl_name
,
method
);
return
NULL
;
}
assert
(
ctx
->
req
->
top
);
priv
=
VRT_priv_top
(
ctx
,
(
void
*
)
h
);
ws
=
ctx
->
req
->
top
->
ws
;
break
;
}
default:
WRONG
(
"invalid scope"
);
}
priv
=
VRT_priv_task
(
ctx
,
(
void
*
)
h
);
AN
(
priv
);
AN
(
ws
);
if
(
priv
->
priv
!=
NULL
)
{
CAST_OBJ
(
task
,
priv
->
priv
,
VMOD_BLOBDIGEST_DIGEST_TASK_MAGIC
);
WS_Contains
(
ctx
->
ws
,
task
,
sizeof
(
struct
digest_task
));
WS_Contains
(
ws
,
task
,
sizeof
(
struct
digest_task
));
}
else
{
if
((
task
=
WS_Alloc
(
ctx
->
ws
,
sizeof
(
struct
digest_task
)))
==
NULL
)
task
=
WS_Alloc
(
ws
,
sizeof
(
struct
digest_task
));
if
(
task
==
NULL
)
{
VERRNOMEM
(
ctx
,
"allocating task data in %s.%s()"
,
h
->
vcl_name
,
method
);
return
NULL
;
}
task
->
magic
=
VMOD_BLOBDIGEST_DIGEST_TASK_MAGIC
;
memcpy
(
&
task
->
ctx
,
&
h
->
ctx
,
sizeof
(
hash_ctx
));
task
->
result
=
NULL
;
...
...
@@ -262,12 +297,26 @@ get_scope(const struct vrt_ctx * const restrict ctx,
return
task
;
}
static
inline
enum
scope
parse_scope
(
const
char
*
const
restrict
p
)
{
assert
(
p
[
0
]
==
'T'
);
if
(
p
[
1
]
==
'O'
)
{
assert
(
p
[
2
]
==
'P'
);
return
PRIV_TOP
;
}
assert
(
p
[
1
]
==
'A'
&&
p
[
2
]
==
'S'
&&
p
[
3
]
==
'K'
);
return
PRIV_TASK
;
}
VCL_VOID
vmod_digest__init
(
VRT_CTX
,
struct
vmod_blobdigest_digest
**
digestp
,
const
char
*
vcl_name
,
VCL_ENUM
hashs
,
VCL_BLOB
initb
)
const
char
*
vcl_name
,
VCL_ENUM
hashs
,
VCL_BLOB
initb
,
VCL_ENUM
scopes
)
{
struct
vmod_blobdigest_digest
*
digest
;
enum
algorithm
hash
=
parse_algorithm
(
hashs
);
enum
scope
scope
=
parse_scope
(
scopes
);
CHECK_OBJ_NOTNULL
(
ctx
,
VRT_CTX_MAGIC
);
AN
(
digestp
);
...
...
@@ -277,6 +326,7 @@ vmod_digest__init(VRT_CTX, struct vmod_blobdigest_digest **digestp,
AN
(
digest
);
*
digestp
=
digest
;
digest
->
scope
=
scope
;
digest
->
hash
=
hash
;
digest
->
vcl_name
=
strdup
(
vcl_name
);
AN
(
digest
->
vcl_name
);
...
...
@@ -320,6 +370,10 @@ vmod_digest_update(VRT_CTX, struct vmod_blobdigest_digest *h, VCL_BLOB b)
return
0
;
}
task
=
get_scope
(
ctx
,
h
,
"update"
);
if
(
task
==
NULL
)
return
0
;
if
(
b
==
NULL
)
{
VERR
(
ctx
,
"null BLOB passed to %s.update()"
,
h
->
vcl_name
);
return
0
;
...
...
@@ -331,12 +385,6 @@ vmod_digest_update(VRT_CTX, struct vmod_blobdigest_digest *h, VCL_BLOB b)
return
1
;
}
task
=
get_scope
(
ctx
,
h
);
if
(
task
==
NULL
)
{
VERRNOMEM
(
ctx
,
"allocating task data in %s.update()"
,
h
->
vcl_name
);
return
0
;
}
if
(
task
->
result
!=
NULL
)
{
VERR
(
ctx
,
"already finalized in %s.update()"
,
h
->
vcl_name
);
return
0
;
...
...
@@ -375,12 +423,10 @@ vmod_digest_final(VRT_CTX, struct vmod_blobdigest_digest *h)
return
b
;
}
task
=
get_scope
(
ctx
,
h
);
if
(
task
==
NULL
)
{
VERRNOMEM
(
ctx
,
"allocating task data in %s.final()"
,
h
->
vcl_name
);
task
=
get_scope
(
ctx
,
h
,
"final"
);
if
(
task
==
NULL
)
return
NULL
;
}
if
(
task
->
result
!=
NULL
)
return
task
->
result
;
...
...
src/vmod_blobdigest.vcc
View file @
e2756ace
...
...
@@ -11,7 +11,7 @@ $Module blobdigest 3 digests, checksums and hmacs for the VCL blob type
::
new OBJECT = blobdigest.digest(ENUM hash [, BLOB init])
new OBJECT = blobdigest.digest(ENUM hash [, BLOB init]
, ["TASK"|"TOP"]
)
BOOL <obj>.update(BLOB)
BLOB <obj>.final()
...
...
@@ -185,7 +185,8 @@ values:
* ``SHA3_512``
$Object digest(ENUM {CRC32, MD5, SHA1, SHA224, SHA256, SHA384, SHA512, SHA3_224,
SHA3_256, SHA3_384, SHA3_512} hash, BLOB init=0)
SHA3_256, SHA3_384, SHA3_512} hash,
BLOB init=0, ENUM {TASK, TOP} scope="TASK")
Initialize a message digest context for the algorithm ``hash``, and
optionally update it with ``init``. If ``init`` is left out, then an
...
...
@@ -195,6 +196,13 @@ If an ``init`` BLOB is provided, then the message digests computed
from this object result with ``init`` prepended before any BLOBs added
by the ``.update()`` method.
By default, the scope of the message digest context is ``TASK``:
method calls affect separate context states for the client and backend
side.
``TOP`` scope provides a context across all ESI subrequests, but is
available only on the client side.
Example::
import blobdigest;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment