1BSON_VISITOR_T(3) libbson BSON_VISITOR_T(3)
2
3
4
6 #include <bson/bson.h>
7
8 typedef struct {
9 /* run before / after descending into a document */
10 bool (*visit_before) (const bson_iter_t *iter, const char *key, void *data);
11 bool (*visit_after) (const bson_iter_t *iter, const char *key, void *data);
12 /* corrupt BSON, or unsupported type and visit_unsupported_type not set */
13 void (*visit_corrupt) (const bson_iter_t *iter, void *data);
14 /* normal bson field callbacks */
15 bool (*visit_double) (const bson_iter_t *iter,
16 const char *key,
17 double v_double,
18 void *data);
19 bool (*visit_utf8) (const bson_iter_t *iter,
20 const char *key,
21 size_t v_utf8_len,
22 const char *v_utf8,
23 void *data);
24 bool (*visit_document) (const bson_iter_t *iter,
25 const char *key,
26 const bson_t *v_document,
27 void *data);
28 bool (*visit_array) (const bson_iter_t *iter,
29 const char *key,
30 const bson_t *v_array,
31 void *data);
32 bool (*visit_binary) (const bson_iter_t *iter,
33 const char *key,
34 bson_subtype_t v_subtype,
35 size_t v_binary_len,
36 const uint8_t *v_binary,
37 void *data);
38 /* normal field with deprecated "Undefined" BSON type */
39 bool (*visit_undefined) (const bson_iter_t *iter,
40 const char *key,
41 void *data);
42 bool (*visit_oid) (const bson_iter_t *iter,
43 const char *key,
44 const bson_oid_t *v_oid,
45 void *data);
46 bool (*visit_bool) (const bson_iter_t *iter,
47 const char *key,
48 bool v_bool,
49 void *data);
50 bool (*visit_date_time) (const bson_iter_t *iter,
51 const char *key,
52 int64_t msec_since_epoch,
53 void *data);
54 bool (*visit_null) (const bson_iter_t *iter, const char *key, void *data);
55 bool (*visit_regex) (const bson_iter_t *iter,
56 const char *key,
57 const char *v_regex,
58 const char *v_options,
59 void *data);
60 bool (*visit_dbpointer) (const bson_iter_t *iter,
61 const char *key,
62 size_t v_collection_len,
63 const char *v_collection,
64 const bson_oid_t *v_oid,
65 void *data);
66 bool (*visit_code) (const bson_iter_t *iter,
67 const char *key,
68 size_t v_code_len,
69 const char *v_code,
70 void *data);
71 bool (*visit_symbol) (const bson_iter_t *iter,
72 const char *key,
73 size_t v_symbol_len,
74 const char *v_symbol,
75 void *data);
76 bool (*visit_codewscope) (const bson_iter_t *iter,
77 const char *key,
78 size_t v_code_len,
79 const char *v_code,
80 const bson_t *v_scope,
81 void *data);
82 bool (*visit_int32) (const bson_iter_t *iter,
83 const char *key,
84 int32_t v_int32,
85 void *data);
86 bool (*visit_timestamp) (const bson_iter_t *iter,
87 const char *key,
88 uint32_t v_timestamp,
89 uint32_t v_increment,
90 void *data);
91 bool (*visit_int64) (const bson_iter_t *iter,
92 const char *key,
93 int64_t v_int64,
94 void *data);
95 bool (*visit_maxkey) (const bson_iter_t *iter, const char *key, void *data);
96 bool (*visit_minkey) (const bson_iter_t *iter, const char *key, void *data);
97 /* if set, called instead of visit_corrupt when an apparently valid BSON
98 * includes an unrecognized field type (reading future version of BSON) */
99 void (*visit_unsupported_type) (const bson_iter_t *iter,
100 const char *key,
101 uint32_t type_code,
102 void *data);
103 bool (*visit_decimal128) (const bson_iter_t *iter,
104 const char *key,
105 const bson_decimal128_t *v_decimal128,
106 void *data);
107
108 void *padding[7];
109 } bson_visitor_t bson_visitor_t;
110
112 The bson_visitor_t structure provides a series of callbacks that can be
113 called while iterating a BSON document. This may simplify the converā
114 sion of a bson_t to a higher level language structure.
115
116 If the optional callback visit_unsupported_type is set, it is called
117 instead of visit_corrupt in the specific case of an unrecognized field
118 type. (Parsing is aborted in either case.) Use this callback to report
119 an error like "unrecognized type" instead of simply "corrupt BSON".
120 This future-proofs code that may use an older version of libbson to
121 parse future BSON formats.
122
124 #include <bson/bson.h>
125 #include <stdio.h>
126
127 static bool
128 my_visit_before (const bson_iter_t *iter, const char *key, void *data)
129 {
130 int *count = (int *) data;
131
132 (*count)++;
133
134 /* returning true stops further iteration of the document */
135
136 return false;
137 }
138
139 static void
140 count_fields (bson_t *doc)
141 {
142 bson_visitor_t visitor = {0};
143 bson_iter_t iter;
144 int count = 0;
145
146 visitor.visit_before = my_visit_before;
147
148 if (bson_iter_init (&iter, doc)) {
149 bson_iter_visit_all (&iter, &visitor, &count);
150 }
151
152 printf ("Found %d fields.\n", count);
153 }
154
155 The example below demonstrates how to set your own callbacks to provide
156 information about the location of corrupt or unsupported BSON document
157 entries.
158
160 #include <bson/bson.h>
161 #include <stdio.h>
162
163 typedef struct {
164 ssize_t *err_offset;
165 } my_state_t;
166
167 static void
168 my_visit_corrupt (const bson_iter_t *iter, void *data)
169 {
170 *(((my_state_t *) data)->err_offset) = iter->off;
171 }
172
173 static void
174 my_visit_unsupported_type (const bson_iter_t *iter,
175 const char *key,
176 uint32_t type_code,
177 void *data)
178 {
179 *(((my_state_t *) data)->err_offset) = iter->off;
180 }
181
182 static void
183 find_error_location (bson_t *doc)
184 {
185 bson_visitor_t visitors = {0};
186 bson_iter_t iter;
187 my_state_t state;
188 ssize_t err_offset = -1;
189
190 visitors.visit_corrupt = my_visit_corrupt;
191 visitors.visit_unsupported_type = my_visit_unsupported_type;
192 /* provide additional visitors as needed based on your requirements */
193 state.err_offset = &err_offset;
194
195 if (!bson_iter_init (&iter, doc)) {
196 printf ("Could not initialize iterator!");
197 exit (1);
198 }
199
200 if (bson_iter_visit_all (&iter, &visitors, &state) ||
201 err_offset != -1) {
202 printf ("Found error at offset %d.\n", err_offset);
203 } else {
204 printf ("BSON document had no errors.\n");
205 }
206 }
207
208 The example below demonstrates how to use a visitor to validate a BSON
209 document's maximum depth.
210
212 bson-check-depth.c
213
214 /* Reports the maximum nested depth of a BSON document. */
215 #include <bson/bson.h>
216
217 #include <assert.h>
218 #include <inttypes.h>
219 #include <stdio.h>
220 #include <stdlib.h>
221
222 typedef struct {
223 uint32_t depth;
224 uint32_t max_depth;
225 bool valid;
226 } check_depth_t;
227
228 bool
229 _check_depth_document (const bson_iter_t *iter,
230 const char *key,
231 const bson_t *v_document,
232 void *data);
233
234 static const bson_visitor_t check_depth_funcs = {
235 NULL,
236 NULL,
237 NULL,
238 NULL,
239 NULL,
240 _check_depth_document,
241 _check_depth_document,
242 NULL,
243 };
244
245 bool
246 _check_depth_document (const bson_iter_t *iter,
247 const char *key,
248 const bson_t *v_document,
249 void *data)
250 {
251 check_depth_t *state = (check_depth_t *) data;
252 bson_iter_t child;
253
254 BSON_UNUSED (iter);
255 BSON_UNUSED (key);
256
257 if (!bson_iter_init (&child, v_document)) {
258 fprintf (stderr, "corrupt\n");
259 return true; /* cancel */
260 }
261
262 state->depth++;
263 if (state->depth > state->max_depth) {
264 state->valid = false;
265 return true; /* cancel */
266 }
267
268 bson_iter_visit_all (&child, &check_depth_funcs, state);
269 state->depth--;
270 return false; /* continue */
271 }
272
273 void
274 check_depth (const bson_t *bson, uint32_t max_depth)
275 {
276 bson_iter_t iter;
277 check_depth_t state = {0};
278
279 if (!bson_iter_init (&iter, bson)) {
280 fprintf (stderr, "corrupt\n");
281 }
282
283 state.valid = true;
284 state.max_depth = max_depth;
285 _check_depth_document (&iter, NULL, bson, &state);
286 if (!state.valid) {
287 printf ("document exceeds maximum depth of %" PRIu32 "\n",
288 state.max_depth);
289 } else {
290 char *as_json = bson_as_canonical_extended_json (bson, NULL);
291 printf ("document %s ", as_json);
292 printf ("is valid\n");
293 bson_free (as_json);
294 }
295 }
296
297 int
298 main (int argc, char **argv)
299 {
300 bson_reader_t *bson_reader;
301 const bson_t *bson;
302 bool reached_eof;
303 bson_error_t error;
304
305 if (argc != 3) {
306 fprintf (stderr, "usage: %s FILE MAX_DEPTH\n", argv[0]);
307 fprintf (stderr, "Checks that the depth of the BSON contained in FILE\n");
308 fprintf (stderr, "does not exceed MAX_DEPTH\n");
309 }
310
311 const char *const filename = argv[1];
312 const int max_depth = atoi (argv[2]);
313
314 bson_reader = bson_reader_new_from_file (filename, &error);
315 if (!bson_reader) {
316 printf ("could not read %s: %s\n", filename, error.message);
317 return 1;
318 }
319
320 BSON_ASSERT (bson_in_range_signed (uint32_t, max_depth));
321
322 while ((bson = bson_reader_read (bson_reader, &reached_eof))) {
323 check_depth (bson, (uint32_t) max_depth);
324 }
325
326 if (!reached_eof) {
327 printf ("error reading BSON\n");
328 }
329
330 bson_reader_destroy (bson_reader);
331 return 0;
332 }
333
334
336 MongoDB, Inc
337
339 2017-present, MongoDB, Inc
340
341
342
343
3441.25.1 Nov 08, 2023 BSON_VISITOR_T(3)