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