Aleks,
I have taken a first look. Find my remarks below. Please note that for
the actual source code there might be further remarks by Willy (put in
CC) or so. I might have missed something or might have told you
something incorrect. So maybe before making changes wait for their opinion.
Generally I must say that I don't like the mjson library, because it
uses 'int' for sizes. It doesn't really bring the point home that it is
a safe library. This one looks much better to me:
https://github.com/FreeRTOS/coreJSON. It does not support JSON path,
though. Not sure how much of an issue that would be?
On 4/8/21 10:21 PM, Aleksandar Lazic wrote:
From 7ecb80b1dfe37c013cf79bc5b5b1caa3c0112a6a Mon Sep 17 00:00:00 2001
From: Alekesandar Lazic <[email protected]>
Date: Thu, 8 Apr 2021 21:42:00 +0200
Subject: [PATCH] MINOR: sample: add json_string
I'd add 'converter' to the subject line to make it clear that this is a
conveter.
This sample get's the value of a JSON key
Typo: It should be 'gets'.
---
Makefile | 3 +-
doc/configuration.txt | 15 +
include/import/mjson.h | 213 +++++
reg-tests/sample_fetches/json_string.vtc | 25 +
src/mjson.c | 1052 ++++++++++++++++++++++
src/sample.c | 63 ++
6 files changed, 1370 insertions(+), 1 deletion(-)
create mode 100644 include/import/mjson.h
create mode 100644 reg-tests/sample_fetches/json_string.vtc
create mode 100644 src/mjson.c
diff --git a/doc/configuration.txt b/doc/configuration.txt
index 01a01eccc..7f2732668 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -19043,6 +19043,21 @@ http_first_req : boolean
This is the 'fetch' section. Move the documentation to the 'converter'
section.
from some requests when a request is not the first one, or to help grouping
requests in the logs.
+json_string(<json_path>) : string
I don't like the name. A few suggestions:
- json_query
- json_get
- json_decode
+ Returns the string value of the given json path.
It should be "JSON" (in uppercase) here and everywhere else.
+ The <json_path> is required.
+ This sample uses the mjson library https://github.com/cesanta/mjson
+ The json path syntax is defined in this repo
https://github.com/json-path/JsonPath
Overall the description of the converter does not read nicely / feels
inconsistent compared to other converters / uses colloquial language.
Let me suggest something like:
Extracts the value located at <json_path> from the JSON string in the
input value. <json_path> must be a valid JsonPath string as defined at
https://goessner.net/articles/JsonPath/
I changed the link, because that appears to be the canonical reference.
+ Example :
No space in front of the colon.
+ # get the value from the key kubernetes.io/serviceaccount/namespace
+ # => openshift-logging
+ http-request set-var(sess.json)
req.hdr(Authorization),b64dec,json_string('$.kubernetes\\.io/serviceaccount/namespace')
+
+ # get the value from the key iss
+ # => kubernetes/serviceaccount
+ http-request set-var(sess.json)
req.hdr(Authorization),b64dec,json_string('$.iss')
I don't like that the example is that specific for Kubernetes usage. A
more general example would be preferred, because it makes it easier to
understand the concept.
method : integer + string
Returns an integer value corresponding to the method in the HTTP request. For
example, "GET" equals 1 (check sources to establish the matching). Value 9
diff --git a/include/import/mjson.h b/include/import/mjson.h
new file mode 100644
index 000000000..ff46e7950
--- /dev/null
+++ b/include/import/mjson.h
@@ -0,0 +1,213 @@
[...]
+// Aleksandar Lazic
+// git clone from 2021-08-04 because of this fix
+//
https://github.com/cesanta/mjson/commit/7d8daa8586d2bfd599775f049f26d2645c25a8ee
Please don't edit third party libraries, even if it is just a comment.
This makes updating hard.
diff --git a/reg-tests/sample_fetches/json_string.vtc
b/reg-tests/sample_fetches/json_string.vtc
new file mode 100644
index 000000000..fc387519b
--- /dev/null
+++ b/reg-tests/sample_fetches/json_string.vtc
Again, this is a converter. Move the test into the appropriate folder.
And please make sure you understand the difference between fetches and
converters.
@@ -0,0 +1,25 @@
+varnishtest "Test to get value from json sting"
+#REQUIRE_VERSION=2.4
+
+feature ignore_unknown_macro
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout connect 1s
+ timeout client 1s
+ timeout server 1s
+
+ frontend fe1
+ bind "fd@${fe1}"
+ http-request set-var(sess.iss)
req.hdr(Authorization),b64dec,json_string('$.iss')
+ http-request return status 200 hdr x-var "json-value=%[var(sess.iss)]"
+} -start
+
+client c1 -connect ${h1_fe1_sock} {
+ txreq -req GET -url "/" \
+ -hdr "Authorization:
eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJvcGVuc2hpZnQtbG9nZ2luZyIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJkZXBsb3llci10b2tlbi1tOTh4aCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJkZXBsb3llciIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjM1ZGRkZWZkLTNiNWEtMTFlOS05NDdjLWZhMTYzZTQ4MDkxMCIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpvcGVuc2hpZnQtbG9nZ2luZzpkZXBsb3llciJ9"
The use of base64 makes it hard to check the test for correctness. I
suggest to a simpler input string that can be embedded into the test as-is.
Please also add additional tests for other cases, e.g.:
- If the key cannot be found in the JSON.
- If the value is not a string, but a number or a boolean.
Have a look at the other tests to see how they are structured.
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-var ~ "json-value=kubernetes/serviceaccount"
+} -run
diff --git a/src/mjson.c b/src/mjson.c
new file mode 100644
index 000000000..729d671c6
--- /dev/null
+++ b/src/mjson.c
@@ -0,0 +1,1052 @@
[...]
+// Aleksandar Lazic
+// git clone from 2021-08-04 because of this fix
+//
https://github.com/cesanta/mjson/commit/7d8daa8586d2bfd599775f049f26d2645c25a8ee
Same as above.
diff --git a/src/sample.c b/src/sample.c
index 835a18115..0096de3ae 100644
--- a/src/sample.c
+++ b/src/sample.c
@@ -18,6 +18,7 @@
#include <import/sha1.h>
#include <import/xxhash.h>
+#include <import/mjson.h>
I believe these should be sorted alphabetically.
#include <haproxy/api.h>
#include <haproxy/arg.h>
@@ -3653,6 +3654,65 @@ static int sample_conv_rtrim(const struct arg *arg_p,
struct sample *smp, void *
return 1;
}
+/* This function checks the "json_string" converter's arguments.
+ * This function returns 1 when everything is good else 0
This is very colloquial language. It is also not true: This function
returns 1, even when the JSON path is not a valid JSON path.
+ */
+static int sample_check_json_string(struct arg *arg, struct sample_conv *conv,
+ const char *file, int line, char **err)
+{
+ DPRINTF(stderr, "%s: arg->type=%d, arg->data.str.data=%ld\n",
+ __FUNCTION__,
+ arg->type, arg->data.str.data);
Debug code above.
+
+ if (arg->type != ARGT_STR) {
+ memprintf(err, "unexpected argument type");
+ return 0;
+ }
I believe it should not be necessary to check this, but don't quote me
on that and wait for an authoritative answer.
+ if (arg->data.str.data == 0) { /* empty */
+ memprintf(err, "empty argument");
This error message does not read nicely, because it is overly technical.
Use something like "json_path must not be empty".
+ return 0;
+ }
+
+ DPRINTF(stderr, "%s: check passed\n",
+ __FUNCTION__);
Debug code.
+ return 1;
+}
+
+/* This sample function get the value from a given json string.
+ * The mjson library is used to parse the json struct
+*/
Missing space here.
+static int sample_conv_json_string(const struct arg *args, struct sample *smp,
void *private)
+{
+ struct buffer *trash = get_trash_chunk();
+ char *value = (char*) trash->area;
The cast is useless. The variable is useless as well, use trash->area
directly. That's more readable.
+ int value_len = trash->size;
You are assigning a size_t to an int. Don't do this. I suggest to use
trash->size directly.
+ int rc;
This is useless, see below.
+ DPRINTF(stderr, "%s: smp->data.u.str.area=%s, smp->data.u.str.data=%ld
args[0].data.str.area=%s\n",
+ __FUNCTION__,
+ smp->data.u.str.area,
smp->data.u.str.data, args[0].data.str.area);
Debug code.
+ rc = mjson_get_string(smp->data.u.str.area, smp->data.u.str.data,
args[0].data.str.area, value, value_len);
Directly assign the return value to `trash->data` to get rid of the
intermediate variable. This prevents bugs.
+ DPRINTF(stderr, "%s: rc=%d, value=%s value_len=%d\n",
+ __FUNCTION__,
+ rc, value, value_len);
Debug code.
+ if (rc == -1 ) {
Extra space that should not be there.
+ return 0;
+ }
+
+ trash->data = rc;
+ smp->data.u.str = *trash;
+ smp->data.type = SMP_T_STR;
+ smp->flags &= ~SMP_F_CONST;
+
+ return 1;
+}
+
+
/************************************************************************/
/* All supported sample fetch functions must be declared here */
/************************************************************************/
@@ -4165,6 +4225,9 @@ static struct sample_conv_kw_list sample_conv_kws = {ILH,
{
{ "cut_crlf", sample_conv_cut_crlf, 0, NULL, SMP_T_STR,
SMP_T_STR },
{ "ltrim", sample_conv_ltrim, ARG1(1,STR), NULL, SMP_T_STR,
SMP_T_STR },
{ "rtrim", sample_conv_rtrim, ARG1(1,STR), NULL, SMP_T_STR,
SMP_T_STR },
+
+ { "json_string", sample_conv_json_string, ARG1(1,STR),
sample_check_json_string , SMP_T_STR, SMP_USE_CONST },
+
{ NULL, NULL, 0, 0, 0 },
}};
--
2.25.1
Best regards
Tim Düsterhus