diff options
| author | eunhhu <[email protected]> | 2026-09-27 07:30:38 +0100 |
|---|---|---|
| committer | eunhhu <[email protected]> | 2026-09-27 07:30:38 +0100 |
| commit | 194d243165c2b78d64e0263f39f7a63dbe4a1310 (patch) | |
| tree | f05e5cf09eb43ddd44e5ef721675920f64519fe1 /prototypes/connections/test-module.c | |
| parent | 2e7ad9f8488d4f02c688ec24d6d0b571b3fa61ec (diff) | |
| download | pure-194d243165c2b78d64e0263f39f7a63dbe4a1310.tar.gz pure-194d243165c2b78d64e0263f39f7a63dbe4a1310.zip | |
Name message fields by paths and take variable fields where they are
A message field's name may now be a path of identifiers joined by dots
(user.name, a field inside the group user); a module that names both a
field and a group (user and user.name) is refused, as are empty,
leading, trailing or digit-first segments. A module may have 64
message fields instead of 32 (PureModule 11.9 to 13.2 KiB).
pure_app_message_fields takes each variable field's start and size in
the payload, so a host that parsed a request in place passes the
fields' bytes where they are instead of laying them out after the
prefix. The runtime checks them as before: a field past the payload
fails with limit, a text that is not UTF-8 with encoding.
Diffstat (limited to 'prototypes/connections/test-module.c')
| -rw-r--r-- | prototypes/connections/test-module.c | 51 |
1 files changed, 51 insertions, 0 deletions
diff --git a/prototypes/connections/test-module.c b/prototypes/connections/test-module.c index d885c92..ae82c69 100644 --- a/prototypes/connections/test-module.c +++ b/prototypes/connections/test-module.c @@ -2486,6 +2486,57 @@ static void message_fields(void) { CHECK(load(bad, &module_b) == PURE_INVALID && strstr(error, "operand type")); bad.o = bytes_as_text; bad.no = 2; bad.h = two; CHECK(load(bad, &module_b) == PURE_INVALID && strstr(error, "operand type")); + + /* Placed by the host: the variable fields wherever they are in the + * payload (here a JSON body after the prefix), in any order; the + * prefix's lengths are not read. */ + CHECK(pure_app_start(&app, &module_a, (PureData){0}) == PURE_OK); + static const char body[] = "{\"note\":\"xyz\",\"title\":\"\xea\xb0\x80\xeb\x82\x98\"}"; + points = 2.5; + title_size = 999; + memcpy(payload, &title_size, 4); + memcpy(payload + 4, &points, 8); + memcpy(payload + 12, &count, 4); + memcpy(payload + 16, body, sizeof(body) - 1); + size = 16 + sizeof(body) - 1; + uint32_t placed[8] = {16 + 23, 6, 0, 0, 16 + 9, 3, 0, 0}; + CHECK(pure_app_message_fields(&app, 0, NULL, -1, (PureSpan){payload, size}, placed) == PURE_OK); + CHECK(app.values[0] == 5.5 && !strcmp(state_text(&app, 1), "\xea\xb0\x80\xeb\x82\x98") && replied(&app, "xyz")); + pure_app_finish(&app); + /* A field that starts or ends past the payload, or a title that is not UTF-8 there. */ + placed[0] = (uint32_t)size + 1; + CHECK(pure_app_message_fields(&app, 0, NULL, -1, (PureSpan){payload, size}, placed) == PURE_LIMIT); + placed[0] = (uint32_t)size - 2; + placed[1] = 3; + CHECK(pure_app_message_fields(&app, 0, NULL, -1, (PureSpan){payload, size}, placed) == PURE_LIMIT); + placed[0] = 16 + 24; + placed[1] = 2; + CHECK(pure_app_message_fields(&app, 0, NULL, -1, (PureSpan){payload, size}, placed) == PURE_INVALID && + app.fault == PURE_FAULT_ENCODING); + CHECK(app.values[0] == 5.5); + pure_app_stop(&app); + + /* Fields in groups: a name is a path of identifiers (user.name), and + * never both a field and a group. */ + static const F grouped[] = {{"user.name", PURE_FIELD_TEXT}, {"user.age", PURE_FIELD_U32}, {"plan", PURE_FIELD_TEXT}}; + static const I grouped_inputs[] = {{"post", NULL, PURE_KIND_MESSAGE, false, grouped, 3}}; + static const O grouped_code[] = {{FIELD, 1, 0}, {ST, 0, 0}, {FIELD, 0, 0}, {TSET, 1, 0}}; + static const H grouped_handlers[] = {{1, 0, 4}}; + Spec groups = spec; + groups.in = grouped_inputs; groups.o = grouped_code; groups.no = LEN(grouped_code); groups.h = grouped_handlers; + CHECK(load(groups, &module_b) == PURE_OK && !strcmp(module_b.field[0].name, "user.name")); + static const char *const refused_paths[] = {"user..name", ".user", "user.", "user.1st", "user name"}; + for (size_t i = 0; i < LEN(refused_paths); ++i) { + F renamed[3] = {grouped[0], grouped[1], grouped[2]}; + renamed[0].name = refused_paths[i]; + I renamed_inputs[1] = {{"post", NULL, PURE_KIND_MESSAGE, false, renamed, 3}}; + groups.in = renamed_inputs; + CHECK(load(groups, &module_b) == PURE_INVALID && strstr(error, "message field")); + } + F both[3] = {{"user", PURE_FIELD_TEXT}, grouped[1], grouped[2]}; + I both_inputs[1] = {{"post", NULL, PURE_KIND_MESSAGE, false, both, 3}}; + groups.in = both_inputs; + CHECK(load(groups, &module_b) == PURE_INVALID && strstr(error, "field and group")); } /* A timer's tick sees the time the host set; floor and a floored modulo |
