Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
ex_query.c
Go to the documentation of this file.
1/*
2 * Nilorea Library
3 * Copyright (C) 2005-2026 Castagnier Mickael
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14 * implied. See the License for the specific language governing
15 * permissions and limitations under the License.
16 *
17 * SPDX-License-Identifier: Apache-2.0
18 */
19
27#include "nilorea/n_log.h"
28#include "nilorea/n_query.h"
29
30#include <stdio.h>
31#include <string.h>
32
33static int failures = 0;
34
35/* one sample record exposed to the query engine through a field getter */
36typedef struct {
37 const char* host;
38 const char* method;
39 const char* path;
40 const char* status;
41 const char* mime;
42} REC;
43
44static const char* rec_get(const char* field, void* ud) {
45 const REC* r = (const REC*)ud;
46 if (strcmp(field, "host") == 0)
47 return r->host;
48 if (strcmp(field, "method") == 0)
49 return r->method;
50 if (strcmp(field, "path") == 0)
51 return r->path;
52 if (strcmp(field, "status") == 0)
53 return r->status;
54 if (strcmp(field, "mime") == 0)
55 return r->mime;
56 return NULL; /* unknown field */
57}
58
59/* compile + evaluate; returns 1/0, or -1 on a compile error */
60static int run(const char* expr, const REC* r) {
61 char err[160] = "";
62 N_QUERY* q = n_query_compile(expr, err, sizeof(err));
63 int m;
64 if (!q) {
65 n_log(LOG_ERR, "compile '%s' failed: %s", expr, err);
66 return -1;
67 }
68 m = n_query_eval(q, rec_get, (void*)r);
69 n_query_free(&q);
70 return m;
71}
72
73static void expect(const char* label, int got, int want) {
74 if (got != want) {
75 n_log(LOG_ERR, "%s: got %d, expected %d", label, got, want);
76 failures++;
77 }
78}
79
80static void expect_parse_error(const char* expr) {
81 char err[160] = "";
82 N_QUERY* q = n_query_compile(expr, err, sizeof(err));
83 if (q) {
84 n_log(LOG_ERR, "expected '%s' to fail compiling", expr);
85 n_query_free(&q);
86 failures++;
87 }
88}
89
90int main(void) {
91 REC r;
93 r.host = "api.example.com";
94 r.method = "GET";
95 r.path = "/admin/login";
96 r.status = "403";
97 r.mime = "text/html";
98
99 /* equality (case-insensitive) and contains */
100 expect("eq", run("host = api.example.com", &r), 1);
101 expect("eq ci", run("host = API.EXAMPLE.COM", &r), 1);
102 expect("eq no", run("host = other.test", &r), 0);
103 expect("contains", run("host ~ example", &r), 1);
104 expect("contains path", run("path ~ admin", &r), 1);
105 expect("not contains", run("path !~ secret", &r), 1);
106 expect("ne", run("mime != text/html", &r), 0);
107
108 /* numeric comparison */
109 expect("ge", run("status >= 400", &r), 1);
110 expect("gt no", run("status > 500", &r), 0);
111 expect("range", run("status >= 400 AND status < 500", &r), 1);
112
113 /* regex */
114 expect("regex", run("mime =~ ^text/", &r), 1);
115 expect("regex no", run("mime =~ ^json", &r), 0);
116
117 /* boolean composition and precedence (AND binds tighter than OR) */
118 expect("and", run("method = GET AND status >= 400", &r), 1);
119 expect("or", run("method = POST OR status = 403", &r), 1);
120 expect("not", run("NOT (status = 200)", &r), 1);
121 expect("paren", run("(method = POST OR method = GET) AND status = 403", &r), 1);
122 expect("prec", run("method = POST AND status = 200 OR host ~ example", &r), 1);
123
124 /* quoted value, unknown field, empty query */
125 expect("quoted", run("path = \"/admin/login\"", &r), 1);
126 expect("unknown field", run("bogus = x", &r), 0);
127 expect("empty match-all", run("", &r), 1);
128 expect("blank match-all", run(" ", &r), 1);
129
130 /* parse errors */
131 expect_parse_error("host ="); /* missing value */
132 expect_parse_error("host"); /* missing operator */
133 expect_parse_error("( host = a"); /* unbalanced paren */
134 expect_parse_error("host = a AND"); /* dangling AND */
135 expect_parse_error("mime =~ ("); /* invalid regex */
136
137 if (failures) {
138 n_log(LOG_ERR, "ex_query: %d failure(s)", failures);
139 return 1;
140 }
141 n_log(LOG_NOTICE, "ex_query: all checks passed");
142 return 0;
143}
static int failures
int main(void)
int run
Definition ex_kafka.c:56
const char * method
Definition ex_query.c:38
const char * status
Definition ex_query.c:40
static void expect(const char *label, int got, int want)
Definition ex_query.c:73
const char * mime
Definition ex_query.c:41
const char * path
Definition ex_query.c:39
static const char * rec_get(const char *field, void *ud)
Definition ex_query.c:44
static void expect_parse_error(const char *expr)
Definition ex_query.c:80
const char * host
Definition ex_query.c:37
Definition ex_query.c:36
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
Definition n_log.h:89
#define LOG_ERR
error conditions
Definition n_log.h:76
void set_log_level(const int log_level)
Set the global log level value ( static int LOG_LEVEL )
Definition n_log.c:121
#define LOG_NOTICE
normal but significant condition
Definition n_log.h:80
int n_query_eval(const N_QUERY *query, N_QUERY_GET get, void *user_data)
Evaluate a compiled query against one record via get.
Definition n_query.c:468
N_QUERY * n_query_compile(const char *expr, char *errbuf, size_t errlen)
Compile an expression into a query.
Definition n_query.c:375
void n_query_free(N_QUERY **query)
Free a compiled query and set the pointer to NULL.
Definition n_query.c:474
Generic log system.
Opaque compiled query (see n_query_compile / n_query_eval / n_query_free).
Definition n_query.c:62
Small boolean query language over caller-named fields.