Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
libvmod-zipflow
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
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-zipflow
Commits
3d299460
Unverified
Commit
3d299460
authored
Aug 22, 2023
by
Nils Goroll
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
subreqs_from_body - simplified and memory-saving request creation
parent
7d378554
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
641 additions
and
26 deletions
+641
-26
.gitignore
.gitignore
+1
-0
Makefile.am
src/Makefile.am
+13
-2
flint.lnt
src/flint.lnt
+1
-0
vmod_zipflow.c
src/vmod_zipflow.c
+155
-23
vmod_zipflow.vcc
src/vmod_zipflow.vcc
+42
-1
sub-body.vtc
src/vtc/sub-body.vtc
+62
-0
zfr_iter.c
src/zfr_iter.c
+321
-0
zfr_iter.h
src/zfr_iter.h
+46
-0
No files found.
.gitignore
View file @
3d299460
...
@@ -24,6 +24,7 @@ stamp-h1
...
@@ -24,6 +24,7 @@ stamp-h1
# test suite
# test suite
zfr_iter_test
*.log
*.log
*.trs
*.trs
...
...
src/Makefile.am
View file @
3d299460
...
@@ -7,12 +7,21 @@ vmod_LTLIBRARIES = \
...
@@ -7,12 +7,21 @@ vmod_LTLIBRARIES = \
libvmod_zipflow_la_LDFLAGS
=
$(VMOD_LDFLAGS)
$(ZLIB_LIBS)
libvmod_zipflow_la_LDFLAGS
=
$(VMOD_LDFLAGS)
$(ZLIB_LIBS)
libvmod_zipflow_la_SOURCES
=
\
libvmod_zipflow_la_SOURCES
=
\
vmod_zipflow.c
vmod_zipflow.c
\
zfr_iter.c
\
zfr_iter.h
nodist_libvmod_zipflow_la_SOURCES
=
\
nodist_libvmod_zipflow_la_SOURCES
=
\
../foreign/zipflow/zipflow.c
\
../foreign/zipflow/zipflow.c
\
vcc_zipflow_if.c
\
vcc_zipflow_if.c
\
vcc_zipflow_if.h
vcc_zipflow_if.h
noinst_PROGRAMS
=
zfr_iter_test
zfr_iter_test_SOURCES
=
zfr_iter.c zfr_iter.h
zfr_iter_test_CFLAGS
=
$(AM_CFLAGS)
-DTEST_DRIVER
zfr_iter_test_LDFLAGS
=
$(VMOD_LDFLAGS)
$(ZLIB_LIBS)
\
$(VARNISHSRC)
/lib/libvarnish/libvarnish.la
@BUILD_VMOD_ZIPFLOW@
@BUILD_VMOD_ZIPFLOW@
# Test suite
# Test suite
...
@@ -27,11 +36,13 @@ AM_VTC_LOG_FLAGS = \
...
@@ -27,11 +36,13 @@ AM_VTC_LOG_FLAGS = \
-p
vmod_path
=
"
$(abs_builddir)
/.libs:
$(vmoddir)
:
$(VARNISHAPI_VMODDIR)
"
-p
vmod_path
=
"
$(abs_builddir)
/.libs:
$(vmoddir)
:
$(VARNISHAPI_VMODDIR)
"
TESTS
=
\
TESTS
=
\
zfr_iter_test
\
vtc/vmod_zipflow.vtc
\
vtc/vmod_zipflow.vtc
\
vtc/empty.vtc
\
vtc/empty.vtc
\
vtc/coverage.vtc
\
vtc/coverage.vtc
\
vtc/sub.vtc
\
vtc/sub.vtc
\
vtc/sub-coalesce.vtc
vtc/sub-coalesce.vtc
\
vtc/sub-body.vtc
# Documentation
# Documentation
...
...
src/flint.lnt
View file @
3d299460
...
@@ -13,6 +13,7 @@
...
@@ -13,6 +13,7 @@
// we can not change external interfaces / code
// we can not change external interfaces / code
-efile(766, *_if.c)
-efile(766, *_if.c)
-emacro(776, RUP2) // macro is not for int
-emacro(776, RUP2) // macro is not for int
-emacro(835, VCT*)
// must always be included to ensure sanity
// must always be included to ensure sanity
-efile(766, config.h)
-efile(766, config.h)
...
...
src/vmod_zipflow.c
View file @
3d299460
...
@@ -38,11 +38,12 @@
...
@@ -38,11 +38,12 @@
#include <vtim.h>
#include <vtim.h>
#include <VSC_main.h>
#include <VSC_main.h>
#include "vcc_zipflow_if.h"
#include "zlib.h"
#include "zlib.h"
#include "zipflow.h"
#include "zipflow.h"
#include "vcc_zipflow_if.h"
#include "zfr_iter.h"
static
void
__attribute__
((
constructor
))
static
void
__attribute__
((
constructor
))
assert_zlib
(
void
)
assert_zlib
(
void
)
{
{
...
@@ -88,6 +89,9 @@ VSTAILQ_HEAD(zipflow_head, zipflow_request);
...
@@ -88,6 +89,9 @@ VSTAILQ_HEAD(zipflow_head, zipflow_request);
struct
zipflow_top
{
struct
zipflow_top
{
unsigned
magic
;
unsigned
magic
;
#define ZIPFLOW_TOP_MAGIC 0x5743145e
#define ZIPFLOW_TOP_MAGIC 0x5743145e
unsigned
body_req
:
1
;
unsigned
body_resp
:
1
;
struct
zfr_iter_s
*
zis
;
struct
zipflow_head
head
;
struct
zipflow_head
head
;
ZIP
*
zip
;
ZIP
*
zip
;
struct
req
*
req
;
struct
req
*
req
;
...
@@ -146,14 +150,12 @@ static const struct vdp vdp_zipsub[1] = {{
...
@@ -146,14 +150,12 @@ static const struct vdp vdp_zipsub[1] = {{
.
priv1
=
NULL
.
priv1
=
NULL
}};
}};
static
struct
zipflow_request
*
static
void
new_zipflow_request
(
VRT_CTX
,
struct
zipflow_top
*
zft
)
init_zipflow_request
(
struct
zipflow_request
*
zfr
,
struct
zipflow_top
*
zft
)
{
{
struct
zipflow_request
*
zfr
;
WS_TOP_ALLOC_OBJ
(
ctx
,
zfr
,
ZIPFLOW_REQUEST_MAGIC
);
CHECK_OBJ_NOTNULL
(
zfr
,
ZIPFLOW_REQUEST_MAGIC
);
if
(
zfr
==
NULL
)
CHECK_OBJ_NOTNULL
(
zft
,
ZIPFLOW_TOP_MAGIC
);
return
(
NULL
);
VSTAILQ_INSERT_TAIL
(
&
zft
->
head
,
zfr
,
list
);
VSTAILQ_INSERT_TAIL
(
&
zft
->
head
,
zfr
,
list
);
...
@@ -164,6 +166,18 @@ new_zipflow_request(VRT_CTX, struct zipflow_top *zft)
...
@@ -164,6 +166,18 @@ new_zipflow_request(VRT_CTX, struct zipflow_top *zft)
zfr
->
atime
=
-
1
;
zfr
->
atime
=
-
1
;
zfr
->
mtime
=
-
1
;
zfr
->
mtime
=
-
1
;
zfr
->
top
=
zft
;
zfr
->
top
=
zft
;
}
static
struct
zipflow_request
*
new_zipflow_request
(
VRT_CTX
,
struct
zipflow_top
*
zft
)
{
struct
zipflow_request
*
zfr
;
WS_TOP_ALLOC_OBJ
(
ctx
,
zfr
,
ZIPFLOW_REQUEST_MAGIC
);
if
(
zfr
==
NULL
)
return
(
NULL
);
init_zipflow_request
(
zfr
,
zft
);
return
(
zfr
);
return
(
zfr
);
}
}
...
@@ -227,6 +241,45 @@ vmod_subreq(VRT_CTX, VCL_STRING uri, VCL_STRING host)
...
@@ -227,6 +241,45 @@ vmod_subreq(VRT_CTX, VCL_STRING uri, VCL_STRING host)
zfr
->
uri
=
uri
;
zfr
->
uri
=
uri
;
}
}
VCL_VOID
vmod_subreqs_from_body
(
VRT_CTX
,
VCL_ENUM
which
)
{
struct
zipflow_request
*
zfr
;
struct
zipflow_top
*
zft
;
CHECK_OBJ_NOTNULL
(
ctx
,
VRT_CTX_MAGIC
);
if
(
vmod_is_subreq
(
ctx
))
{
VRT_fail
(
ctx
,
"subreqs_from_body can not be "
"called from a subrequest"
);
return
;
}
zfr
=
get_zipflow_request
(
ctx
);
if
(
zfr
==
NULL
)
return
;
zft
=
zfr
->
top
;
CHECK_OBJ_NOTNULL
(
zft
,
ZIPFLOW_TOP_MAGIC
);
// because $Restrict
AN
(
ctx
->
req
);
if
(
which
==
VENUM
(
req_body
))
{
if
(
ctx
->
req
->
req_body_status
!=
BS_CACHED
)
{
VRT_fail
(
ctx
,
"subreqs_from_body can only "
"be used with a cached request body "
"(see std.cache_req_body())"
);
return
;
}
zft
->
body_req
=
1
;
}
else
if
(
which
==
VENUM
(
resp_body
))
{
zft
->
body_resp
=
1
;
zfr
->
bundle
=
0
;
}
else
WRONG
(
"which"
);
}
VCL_BOOL
VCL_BOOL
vmod_is_subreq
(
VRT_CTX
)
vmod_is_subreq
(
VRT_CTX
)
{
{
...
@@ -418,6 +471,57 @@ vmod_event(VRT_CTX, struct vmod_priv *priv, enum vcl_event_e e)
...
@@ -418,6 +471,57 @@ vmod_event(VRT_CTX, struct vmod_priv *priv, enum vcl_event_e e)
return
(
0
);
return
(
0
);
}
}
/*
* ============================================================
* Iterators: Iterate over a body to create sub requests
*/
static
void
zfr_include
(
struct
req
*
preq
,
struct
zipflow_request
*
zfr
);
static
void
zfr_iter_include
(
void
*
priv
,
const
char
*
u
,
const
char
*
h
)
{
struct
zipflow_top
*
zft
;
struct
zipflow_request
*
zfr
,
this
[
1
];
CAST_OBJ_NOTNULL
(
zft
,
priv
,
ZIPFLOW_TOP_MAGIC
);
while
((
zfr
=
VSTAILQ_FIRST
(
&
zft
->
head
))
!=
NULL
)
zfr_include
(
zft
->
req
,
zfr
);
INIT_OBJ
(
this
,
ZIPFLOW_REQUEST_MAGIC
);
init_zipflow_request
(
this
,
zft
);
this
->
host
=
h
;
this
->
uri
=
u
;
assert
(
this
==
VSTAILQ_FIRST
(
&
zft
->
head
));
while
((
zfr
=
VSTAILQ_FIRST
(
&
zft
->
head
))
!=
NULL
)
zfr_include
(
zft
->
req
,
zfr
);
}
static
void
zft_iter_req_body
(
struct
zipflow_top
*
zft
)
{
struct
zfr_iter_s
zis
[
1
];
struct
req
*
req
;
CHECK_OBJ_NOTNULL
(
zft
,
ZIPFLOW_TOP_MAGIC
);
req
=
zft
->
req
;
CHECK_OBJ_NOTNULL
(
req
,
REQ_MAGIC
);
INIT_OBJ
(
zis
,
ZFR_ITER_MAGIC
);
zis
->
zft
=
zft
;
zis
->
func
=
zfr_iter_include
;
zis
->
priv
=
zft
;
if
(
zft
->
body_req
)
{
(
void
)
VRB_Iterate
(
req
->
wrk
,
req
->
vsl
,
req
,
zfr_iter
,
(
void
*
)
zis
);
zfr_iter_fini
(
zis
);
}
}
/*
/*
* ============================================================
* ============================================================
* VDP
* VDP
...
@@ -499,6 +603,19 @@ vdp_zipflow_init(VRT_CTX, struct vdp_ctx *vdc, void **priv, struct objcore *oc)
...
@@ -499,6 +603,19 @@ vdp_zipflow_init(VRT_CTX, struct vdp_ctx *vdc, void **priv, struct objcore *oc)
return
(
1
);
return
(
1
);
}
}
if
(
zft
->
body_resp
)
{
zfr
->
bundle
=
0
;
WS_TOP_ALLOC_OBJ
(
ctx
,
zft
->
zis
,
ZFR_ITER_MAGIC
);
if
(
zft
->
zis
==
NULL
)
{
VSLb
(
vdc
->
vsl
,
SLT_Error
,
"zipflow: workspace "
"overflow for body_resp"
);
return
(
1
);
}
zft
->
zis
->
zft
=
zft
;
zft
->
zis
->
func
=
zfr_iter_include
;
zft
->
zis
->
priv
=
zft
;
}
AZ
(
zft
->
req
);
AZ
(
zft
->
req
);
zft
->
req
=
vdc
->
req
;
zft
->
req
=
vdc
->
req
;
AZ
(
zft
->
zip
);
AZ
(
zft
->
zip
);
...
@@ -544,15 +661,17 @@ vdp_zipflow_fini(struct vdp_ctx *vdc, void **priv)
...
@@ -544,15 +661,17 @@ vdp_zipflow_fini(struct vdp_ctx *vdc, void **priv)
AN
(
priv
);
AN
(
priv
);
zfr
=
*
priv
;
zfr
=
*
priv
;
*
priv
=
NULL
;
*
priv
=
NULL
;
if
(
zfr
!=
NULL
)
{
if
(
zfr
==
NULL
)
CHECK_OBJ
(
zfr
,
ZIPFLOW_REQUEST_MAGIC
);
return
(
0
);
zft
=
zfr
->
top
;
CHECK_OBJ_NOTNULL
(
zft
,
ZIPFLOW_TOP_MAGIC
);
CHECK_OBJ
(
zfr
,
ZIPFLOW_REQUEST_MAGIC
);
r
=
zip_close
(
zft
->
zip
);
zft
=
zfr
->
top
;
if
(
r
)
CHECK_OBJ_NOTNULL
(
zft
,
ZIPFLOW_TOP_MAGIC
);
VSLb
(
vdc
->
vsl
,
SLT_Error
,
"zip_close returned %d"
,
r
);
r
=
zip_close
(
zft
->
zip
);
memset
(
zfr
,
0
,
sizeof
*
zfr
);
if
(
r
)
}
VSLb
(
vdc
->
vsl
,
SLT_Error
,
"zip_close returned %d"
,
r
);
memset
(
zfr
,
0
,
sizeof
*
zfr
);
return
(
0
);
return
(
0
);
}
}
...
@@ -583,9 +702,6 @@ vdp_zipsub_bytes(struct vdp_ctx *vdc, enum vdp_action act, void **priv,
...
@@ -583,9 +702,6 @@ vdp_zipsub_bytes(struct vdp_ctx *vdc, enum vdp_action act, void **priv,
return
(
0
);
return
(
0
);
}
}
static
void
zfr_include
(
struct
req
*
preq
,
struct
zipflow_request
*
zfr
);
static
int
static
int
vdp_zipflow_bytes
(
struct
vdp_ctx
*
vdc
,
enum
vdp_action
act
,
void
**
priv
,
vdp_zipflow_bytes
(
struct
vdp_ctx
*
vdc
,
enum
vdp_action
act
,
void
**
priv
,
const
void
*
ptr
,
ssize_t
len
)
const
void
*
ptr
,
ssize_t
len
)
...
@@ -594,12 +710,26 @@ vdp_zipflow_bytes(struct vdp_ctx *vdc, enum vdp_action act, void **priv,
...
@@ -594,12 +710,26 @@ vdp_zipflow_bytes(struct vdp_ctx *vdc, enum vdp_action act, void **priv,
struct
zipflow_top
*
zft
;
struct
zipflow_top
*
zft
;
int
r
,
c
;
int
r
,
c
;
r
=
vdp_zipsub_bytes
(
vdc
,
act
,
priv
,
ptr
,
len
);
AN
(
priv
);
CAST_OBJ_NOTNULL
(
zfr
,
*
priv
,
ZIPFLOW_REQUEST_MAGIC
);
zft
=
zfr
->
top
;
if
(
zft
->
zis
!=
NULL
)
{
r
=
zfr_iter
(
zft
->
zis
,
(
act
==
VDP_END
)
?
OBJ_ITER_END
:
0
,
ptr
,
len
);
}
else
r
=
vdp_zipsub_bytes
(
vdc
,
act
,
priv
,
ptr
,
len
);
if
(
r
==
0
&&
act
!=
VDP_END
)
if
(
r
==
0
&&
act
!=
VDP_END
)
return
(
r
);
return
(
r
);
TAKE_OBJ_NOTNULL
(
zfr
,
priv
,
ZIPFLOW_REQUEST_MAGIC
);
*
priv
=
NULL
;
zft
=
zfr
->
top
;
if
(
zft
->
zis
!=
NULL
)
{
zfr_iter_fini
(
zft
->
zis
);
zft
->
zis
=
NULL
;
}
memset
(
zfr
,
0
,
sizeof
*
zfr
);
memset
(
zfr
,
0
,
sizeof
*
zfr
);
CHECK_OBJ_NOTNULL
(
zft
,
ZIPFLOW_TOP_MAGIC
);
CHECK_OBJ_NOTNULL
(
zft
,
ZIPFLOW_TOP_MAGIC
);
...
@@ -608,6 +738,8 @@ vdp_zipflow_bytes(struct vdp_ctx *vdc, enum vdp_action act, void **priv,
...
@@ -608,6 +738,8 @@ vdp_zipflow_bytes(struct vdp_ctx *vdc, enum vdp_action act, void **priv,
zfr_include
(
zft
->
req
,
zfr
);
zfr_include
(
zft
->
req
,
zfr
);
}
}
zft_iter_req_body
(
zft
);
c
=
zip_close
(
zft
->
zip
);
c
=
zip_close
(
zft
->
zip
);
if
(
c
)
if
(
c
)
VSLb
(
vdc
->
vsl
,
SLT_Error
,
"zip_close returned %d"
,
r
);
VSLb
(
vdc
->
vsl
,
SLT_Error
,
"zip_close returned %d"
,
r
);
...
...
src/vmod_zipflow.vcc
View file @
3d299460
...
@@ -47,7 +47,7 @@ processing.
...
@@ -47,7 +47,7 @@ processing.
If *host* is omitted (default), it is taken from the parent request.
If *host* is omitted (default), it is taken from the parent request.
This function can be called any number of times to add multiple
This function can be called any number of times to add multiple
files, it can e
b
en be called from a sub request, which is to say that
files, it can e
v
en be called from a sub request, which is to say that
more files can be added while requests for files are processed.
more files can be added while requests for files are processed.
The sub request can be identified using `zipflow.is_subreq()`_. In the
The sub request can be identified using `zipflow.is_subreq()`_. In the
...
@@ -57,6 +57,47 @@ used to control how zipflow handles the body.
...
@@ -57,6 +57,47 @@ used to control how zipflow handles the body.
Only sub requests with reponse status 200 will be included in the
Only sub requests with reponse status 200 will be included in the
resulting zip file.
resulting zip file.
$Function VOID subreqs_from_body(ENUM {req_body, resp_body } which)
$Restrict client
*Note* this function should eventually be superseded with something
more versatile.
Parse the given body for tokens in one of the following formats,
separated by any whitespace (``\\r\\n\\t\\s``)
* ``http://``\ *host*\ *url*
* ``https://``\ *host*\ *url*
* ``//``\ *host*\ *url*
* ``url``
with *host* containing any non-whitespace character except for ``/``
and *url* starting with ``/`` and run a sub request for each token as
if ``subreq(``\ *url*\ ``, ``\ *host*\ ``)`` was invoced, but not
using any workspace memory.
This function can only be called from the top level, that is, not from
a sub request.
For ``which = resp_body``, bundling of the current body is turned
off.
For ``which = req_body``, ``std.cache_req_body()`` must have been
called earlier.
The order of subrequests is:
* `zipflow.subreq()`_ initiated by the top level request
* ``resp_body``
* each subreq followed by any `zipflow.subreq()`_ initiated from it
* ``req_body``
* each subreq followed by any `zipflow.subreq()`_ initiated from it
$Function BOOL is_subreq()
$Function BOOL is_subreq()
$Restrict client
$Restrict client
...
...
src/vtc/sub-body.vtc
0 → 100644
View file @
3d299460
varnishtest "vmod-zipflow sub requests from bodies"
feature cmd "type curl && type unzip"
varnish v1 -vcl {
import zipflow;
import std;
backend proforma none;
sub vcl_recv {
std.cache_req_body(1M);
return (synth(200));
}
sub synth_top {
zipflow.subreq("/fromvcl");
synthetic(" /FIRST/FROM/RESP/file /file1");
zipflow.subreqs_from_body(resp_body);
zipflow.subreqs_from_body(req_body);
set resp.filters += " zipflow";
}
sub synth_sub {
synthetic("sub " + req.url);
}
sub vcl_synth {
if (zipflow.is_subreq()) {
call synth_sub;
zipflow.meta(name=req.url);
if (req.url ~ "/file1") {
zipflow.meta(name="file1.changed");
zipflow.subreq("/file3");
} else
if (req.url ~ "/file3") {
zipflow.subreq("/file4");
}
} else {
call synth_top;
}
return (deliver);
}
} -start
client c1 {
txreq -body {
/REQ/first/file
http://thishost/path/file1
https://thishost/another/file2
//thishost/file3
}
rxresp
expect resp.status == 200
txreq
rxresp
expect resp.status == 500
} -run
# all default
shell "curl --data-raw \"/REQ/CURL/first http://thishost/path/file1 https://thishost/another/file2 //thishost/xxx/file3\" -so t.zip -H 'Host: ${v1_addr}' http://${v1_addr}:${v1_port}/ && unzip -Z t.zip"
src/zfr_iter.c
0 → 100644
View file @
3d299460
/*-
* Copyright 2022,2023 UPLEX Nils Goroll Systemoptimierung
* All rights reserved
*
* Author: Nils Goroll <nils.goroll@uplex.de>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* iterate over a body and call callback for anything which looks like a url
*/
#include "config.h"
#include <string.h> // memset() for INIT_OBJ()
#include <stdlib.h> // strtoul()
#include <stdio.h>
#include <cache/cache.h>
#include <vct.h>
#include "zfr_iter.h"
/* This function exists because flexelint does not understand (p += strlen(s))
* in place
*/
static
inline
int
pincr
(
const
char
**
p
,
size_t
l
)
{
*
p
+=
l
;
return
(
1
);
}
#define tok(p, e, s) ( \
pdiff(p,e) >= strlen(s) && \
strncmp(p, s, strlen(s)) == 0 && \
pincr(&p, strlen(s)) \
)
int
zfr_iter
(
void
*
priv
,
unsigned
flush
,
const
void
*
ptr
,
ssize_t
alen
)
{
const
char
*
pp
,
*
p
,
*
e
,
*
h
,
*
u
;
struct
zfr_iter_s
*
zis
;
char
*
hh
,
*
uu
;
size_t
l
;
CAST_OBJ_NOTNULL
(
zis
,
priv
,
ZFR_ITER_MAGIC
);
AZ
(
zis
->
end_seen
);
zis
->
end_seen
=
((
flush
&
OBJ_ITER_END
)
!=
0
);
#ifdef DEBUG
printf
(
"buf %zu >%.*s<
\t
"
"ptr %zu >%.*s<
\n
"
,
zis
->
len
,
(
int
)
zis
->
len
,
zis
->
buf
,
len
,
(
int
)
len
,
(
const
char
*
)
ptr
);
#endif
if
(
zis
->
len
>
0
)
AN
(
zis
->
buf
);
if
(
alen
==
0
&&
zis
->
len
==
0
)
return
(
0
);
assert
(
alen
>=
0
);
l
=
(
size_t
)
alen
;
if
(
zis
->
len
==
0
)
p
=
ptr
;
else
{
zis
->
buf
=
realloc
(
zis
->
buf
,
zis
->
len
+
l
);
AN
(
zis
->
buf
);
memcpy
(
zis
->
buf
+
zis
->
len
,
ptr
,
l
);
zis
->
len
+=
l
;
p
=
zis
->
buf
;
l
=
zis
->
len
;
}
AN
(
p
);
pp
=
p
;
e
=
p
+
l
;
while
(
p
<
e
)
{
if
(
vct_islws
(
*
p
))
{
p
++
;
continue
;
}
if
(
tok
(
p
,
e
,
"https://"
)
||
tok
(
p
,
e
,
"http://"
))
{
p
-=
2
;
// no need to keep this prefix in the buffer
pp
=
p
;
}
h
=
NULL
;
if
(
tok
(
p
,
e
,
"//"
))
{
h
=
u
=
p
;
p
-=
2
;
while
(
u
<
e
&&
*
u
!=
'/'
)
u
++
;
}
else
u
=
p
;
while
(
p
<
e
&&
!
vct_islws
(
*
p
))
p
++
;
if
(
*
u
!=
'/'
)
break
;
if
(
p
<
e
||
flush
&
OBJ_ITER_END
)
{
/* match! */
hh
=
NULL
;
if
(
h
)
{
assert
(
u
>
h
);
hh
=
strndup
(
h
,
pdiff
(
h
,
u
));
AN
(
hh
);
}
assert
(
p
>
u
);
uu
=
strndup
(
u
,
pdiff
(
u
,
p
));
AN
(
uu
);
AN
(
zis
->
func
);
zis
->
func
(
zis
->
priv
,
uu
,
hh
);
free
(
hh
);
free
(
uu
);
pp
=
p
;
}
}
assert
(
e
>=
pp
);
l
=
pdiff
(
pp
,
e
);
if
(
flush
&
OBJ_ITER_END
||
l
==
0
)
{
zis
->
len
=
0
;
return
(
0
);
}
if
(
zis
->
len
)
memmove
(
zis
->
buf
,
pp
,
l
);
else
{
zis
->
buf
=
realloc
(
zis
->
buf
,
l
);
memcpy
(
zis
->
buf
,
pp
,
l
);
}
zis
->
len
=
l
;
return
(
0
);
}
void
zfr_iter_fini
(
struct
zfr_iter_s
*
zis
)
{
CHECK_OBJ_NOTNULL
(
zis
,
ZFR_ITER_MAGIC
);
if
(
zis
->
len
>
0
&&
zis
->
end_seen
==
0
)
(
void
)
zfr_iter
(
zis
,
OBJ_ITER_END
,
""
,
(
ssize_t
)
0
);
free
(
zis
->
buf
);
zis
->
buf
=
NULL
;
zis
->
len
=
0
;
}
#ifdef TEST_DRIVER
#include <stdio.h>
struct
expect
{
const
char
*
u
,
*
h
,
**
pfx
;
};
const
char
*
pfx_host
[
7
]
=
{
"https://"
,
"http://"
,
"//"
,
" https://"
,
" http://"
,
" //"
,
NULL
};
const
char
*
pfx_nohost
[
2
]
=
{
""
,
NULL
};
static
struct
expect
testcase
[
7
]
=
{
{
.
u
=
"/url"
,
.
h
=
"host"
,
.
pfx
=
pfx_host
},
{
.
u
=
"/"
,
.
h
=
"host"
,
.
pfx
=
pfx_host
},
{
.
u
=
"///"
,
.
h
=
"ho-t"
,
.
pfx
=
pfx_host
},
{
.
u
=
"/url"
,
.
h
=
NULL
,
.
pfx
=
pfx_nohost
},
{
.
u
=
"/"
,
.
h
=
NULL
,
.
pfx
=
pfx_nohost
},
{
.
u
=
"/a"
,
.
h
=
NULL
,
.
pfx
=
pfx_nohost
},
{
NULL
}
};
struct
cb_want_priv
{
unsigned
magic
;
#define CBW_MAGIC 0x79d8b905
unsigned
count
;
const
struct
expect
*
e
;
};
static
void
cb_not
(
void
*
priv
,
const
char
*
u
,
const
char
*
h
)
{
WRONG
(
"not to be called"
);
}
static
void
cb_want
(
void
*
priv
,
const
char
*
u
,
const
char
*
h
)
{
struct
cb_want_priv
*
p
;
const
struct
expect
*
e
;
CAST_OBJ_NOTNULL
(
p
,
priv
,
CBW_MAGIC
);
e
=
p
->
e
;
if
(
e
->
u
==
NULL
)
AZ
(
u
);
else
AZ
(
strcmp
(
e
->
u
,
u
));
if
(
e
->
h
==
NULL
)
AZ
(
h
);
else
AZ
(
strcmp
(
e
->
h
,
h
));
p
->
count
++
;
}
static
void
t_steps
(
const
struct
expect
*
want
,
unsigned
n
,
const
char
*
s
)
{
struct
cb_want_priv
wp
[
1
];
struct
zfr_iter_s
zis
[
1
];
size_t
l
,
step
;
const
char
*
t
;
INIT_OBJ
(
zis
,
ZFR_ITER_MAGIC
);
INIT_OBJ
(
wp
,
CBW_MAGIC
);
wp
->
e
=
want
;
zis
->
priv
=
wp
;
zis
->
func
=
cb_want
;
for
(
step
=
1
;
step
<
strlen
(
s
);
step
++
)
{
wp
->
count
=
0
;
zis
->
end_seen
=
0
;
for
(
t
=
s
,
l
=
strlen
(
t
);
l
>
step
;
l
-=
step
,
t
+=
step
)
zfr_iter
(
zis
,
0
,
t
,
step
);
AN
(
l
);
zfr_iter
(
zis
,
OBJ_ITER_END
,
t
,
l
);
AN
(
zis
->
end_seen
);
assert
(
wp
->
count
==
n
);
}
}
int
main
(
void
)
{
const
struct
expect
*
want
;
struct
zfr_iter_s
zis
[
1
];
const
char
**
p
,
*
t
;
char
s
[
256
],
u
[
64
];
unsigned
n
;
size_t
l
;
// base test of tok()
strcpy
(
s
,
"https://"
);
t
=
s
;
assert
(
tok
(
t
,
strchr
(
s
,
'\0'
),
"https://"
));
for
(
want
=
testcase
;
want
->
u
!=
NULL
;
want
++
)
{
INIT_OBJ
(
zis
,
ZFR_ITER_MAGIC
);
zis
->
priv
=
NULL
;
zis
->
func
=
cb_not
;
zfr_iter
(
zis
,
0
,
""
,
0
);
n
=
0
;
*
s
=
'\0'
;
for
(
p
=
want
->
pfx
;
*
p
!=
NULL
;
p
++
)
{
AN
(
p
);
AN
(
*
p
);
if
(
**
p
==
'\0'
)
l
=
snprintf
(
u
,
sizeof
u
,
"
\t
%s"
,
want
->
u
);
else
{
l
=
snprintf
(
u
,
sizeof
u
,
"
\t
%s%s%s"
,
*
p
,
want
->
h
,
want
->
u
);
}
assert
(
l
<
sizeof
u
);
if
(
sizeof
s
-
strlen
(
s
)
-
1
<
l
)
break
;
(
void
)
strcat
(
s
,
u
);
n
++
;
t_steps
(
want
,
n
,
s
);
}
}
zfr_iter_fini
(
zis
);
printf
(
"OK
\n
"
);
return
(
0
);
}
#endif
src/zfr_iter.h
0 → 100644
View file @
3d299460
/*-
* Copyright 2022,2023 UPLEX Nils Goroll Systemoptimierung
* All rights reserved
*
* Author: Nils Goroll <nils.goroll@uplex.de>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* iterate over a body and call callback for anything which looks like a url
*/
typedef
void
zfr_iter_f
(
void
*
priv
,
const
char
*
u
,
const
char
*
h
);
struct
zfr_iter_s
{
unsigned
magic
;
#define ZFR_ITER_MAGIC 0x2d560bd8
unsigned
end_seen
;
struct
zipflow_top
*
zft
;
char
*
buf
;
size_t
len
;
zfr_iter_f
*
func
;
void
*
priv
;
};
void
zfr_iter_fini
(
struct
zfr_iter_s
*
zis
);
int
zfr_iter
(
void
*
,
unsigned
flush
,
const
void
*
ptr
,
ssize_t
len
);
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