Skip to content

Commit 2597f6d

Browse files
jmikolakevinAlbs
andauthored
CDRIVER-3895: Remove dots/dollars validation for insert/replace docs (#801)
* CDRIVER-3895: Update CRUD, transactions, and unified spec tests Also replaces CRUD legacy/v2 tests with unified equivalents for CDRIVER-3960. Synced with mongodb/specifications@a124e21 * Skip unified CRUD tests related to CDRIVER-3630 * Ensure upsertedIds is always present in BulkWriteResult * Allow array or document for updateOne/Many update arg * Remove dot/dollar restrictions for insert/replace validation This adds top-level key validation to _mongoc_validate_replace, similar to what existed in _mongoc_validate_update. * Remove redundant replace doc validation for legacy updates Replacement docs will already be validated by _mongoc_validate_replace before this function is reached. This adds logic to ensure "q" and "u" documents are present, similar to what existed in _mongoc_write_command_delete_legacy. * Test success and failure for legacy update code path The failure code path is testing that arguments are still validated by mongoc-util.c, despite replacement validation being removed in a previous commit. * Revert "Skip tests with dots and dollars in field names on 5.0+ (#795)" This reverts commit bd014ee. * Revise bulk and collection tests for allowing dots/dollars Empty keys can be used as a reliable BSON validation error, since insert, replace, and update all specify BSON_VALIDATE_EMPTY_KEYS in their vflags. Error message expectations are adjusted accordingly. An _id document with a dollar-prefixed key is also used as a reliable server-side validation error. * Allow methods in bulk_op_append to fail so expectError can be evaluated * Skip unified tests due to schema version and outstanding issues Allow entire files to be skipped to preempt schema version errors. * Ensure WC is set on database and collection entities Co-authored-by: Kevin Albertson <[email protected]>
1 parent a6b3d5e commit 2597f6d

File tree

142 files changed

+16121
-8472
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

142 files changed

+16121
-8472
lines changed

src/libmongoc/src/mongoc/mongoc-util.c

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,11 @@
2828

2929
const bson_validate_flags_t _mongoc_default_insert_vflags =
3030
BSON_VALIDATE_UTF8 | BSON_VALIDATE_UTF8_ALLOW_NULL |
31-
BSON_VALIDATE_EMPTY_KEYS | BSON_VALIDATE_DOT_KEYS |
32-
BSON_VALIDATE_DOLLAR_KEYS;
31+
BSON_VALIDATE_EMPTY_KEYS;
3332

3433
const bson_validate_flags_t _mongoc_default_replace_vflags =
3534
BSON_VALIDATE_UTF8 | BSON_VALIDATE_UTF8_ALLOW_NULL |
36-
BSON_VALIDATE_EMPTY_KEYS | BSON_VALIDATE_DOT_KEYS |
37-
BSON_VALIDATE_DOLLAR_KEYS;
35+
BSON_VALIDATE_EMPTY_KEYS;
3836

3937
const bson_validate_flags_t _mongoc_default_update_vflags =
4038
BSON_VALIDATE_UTF8 | BSON_VALIDATE_UTF8_ALLOW_NULL |
@@ -324,6 +322,8 @@ _mongoc_validate_replace (const bson_t *doc,
324322
bson_error_t *error)
325323
{
326324
bson_error_t validate_err;
325+
bson_iter_t iter;
326+
const char *key;
327327

328328
if (vflags == BSON_VALIDATE_NONE) {
329329
return true;
@@ -338,6 +338,27 @@ _mongoc_validate_replace (const bson_t *doc,
338338
return false;
339339
}
340340

341+
if (!bson_iter_init (&iter, doc)) {
342+
bson_set_error (error,
343+
MONGOC_ERROR_BSON,
344+
MONGOC_ERROR_BSON_INVALID,
345+
"replace document is corrupt");
346+
return false;
347+
}
348+
349+
while (bson_iter_next (&iter)) {
350+
key = bson_iter_key (&iter);
351+
if (key[0] == '$') {
352+
bson_set_error (error,
353+
MONGOC_ERROR_COMMAND,
354+
MONGOC_ERROR_COMMAND_INVALID_ARG,
355+
"Invalid key '%s': replace prohibits $ operators",
356+
key);
357+
358+
return false;
359+
}
360+
}
361+
341362
return true;
342363
}
343364

src/libmongoc/src/mongoc/mongoc-write-command-legacy.c

Lines changed: 18 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -380,16 +380,13 @@ _mongoc_write_command_update_legacy (mongoc_write_command_t *command,
380380
int32_t max_bson_obj_size;
381381
mongoc_rpc_t rpc;
382382
uint32_t request_id = 0;
383-
bson_iter_t subiter, subsubiter;
384-
bson_t doc;
383+
bson_iter_t subiter;
385384
bson_t update, selector;
386385
const uint8_t *data = NULL;
387386
uint32_t len = 0;
388-
size_t err_offset;
389387
bool val = false;
390388
char *ns;
391-
int vflags = (BSON_VALIDATE_UTF8 | BSON_VALIDATE_UTF8_ALLOW_NULL |
392-
BSON_VALIDATE_DOLLAR_KEYS | BSON_VALIDATE_DOT_KEYS);
389+
bool r;
393390
bson_reader_t *reader;
394391
const bson_t *bson;
395392
bool eof;
@@ -406,45 +403,19 @@ _mongoc_write_command_update_legacy (mongoc_write_command_t *command,
406403

407404
max_bson_obj_size = mongoc_server_stream_max_bson_obj_size (server_stream);
408405

409-
reader =
410-
bson_reader_new_from_data (command->payload.data, command->payload.len);
411-
while ((bson = bson_reader_read (reader, &eof))) {
412-
if (bson_iter_init (&subiter, bson) && bson_iter_find (&subiter, "u") &&
413-
BSON_ITER_HOLDS_DOCUMENT (&subiter)) {
414-
bson_iter_document (&subiter, &len, &data);
415-
BSON_ASSERT (bson_init_static (&doc, data, len));
416-
417-
if (bson_iter_init (&subsubiter, &doc) &&
418-
bson_iter_next (&subsubiter) &&
419-
(bson_iter_key (&subsubiter)[0] != '$') &&
420-
!bson_validate (
421-
&doc, (bson_validate_flags_t) vflags, &err_offset)) {
422-
result->failed = true;
423-
bson_set_error (error,
424-
MONGOC_ERROR_BSON,
425-
MONGOC_ERROR_BSON_INVALID,
426-
"update document is corrupt or contains "
427-
"invalid keys including $ or .");
428-
bson_reader_destroy (reader);
429-
EXIT;
430-
}
431-
} else {
432-
result->failed = true;
433-
bson_set_error (error,
434-
MONGOC_ERROR_BSON,
435-
MONGOC_ERROR_BSON_INVALID,
436-
"updates is malformed.");
437-
bson_reader_destroy (reader);
438-
EXIT;
439-
}
440-
}
441-
442406
ns = bson_strdup_printf ("%s.%s", database, collection);
443407

444-
bson_reader_destroy (reader);
445408
reader =
446409
bson_reader_new_from_data (command->payload.data, command->payload.len);
447410
while ((bson = bson_reader_read (reader, &eof))) {
411+
/* ensure the document has "q" and "u" document fields in that order */
412+
r = (bson_iter_init (&subiter, bson) && bson_iter_find (&subiter, "q") &&
413+
BSON_ITER_HOLDS_DOCUMENT (&subiter) &&
414+
bson_iter_find (&subiter, "u") &&
415+
BSON_ITER_HOLDS_DOCUMENT (&subiter));
416+
417+
BSON_ASSERT (r);
418+
448419
request_id = ++client->cluster.request_id;
449420

450421
rpc.header.msg_len = 0;
@@ -459,6 +430,10 @@ _mongoc_write_command_update_legacy (mongoc_write_command_t *command,
459430
while (bson_iter_next (&subiter)) {
460431
if (strcmp (bson_iter_key (&subiter), "u") == 0) {
461432
bson_iter_document (&subiter, &len, &data);
433+
434+
BSON_ASSERT (data);
435+
BSON_ASSERT (len >= 5);
436+
462437
if (len > max_bson_obj_size) {
463438
_mongoc_write_command_too_large_error (
464439
error, 0, len, max_bson_obj_size);
@@ -472,6 +447,10 @@ _mongoc_write_command_update_legacy (mongoc_write_command_t *command,
472447
BSON_ASSERT (bson_init_static (&update, data, len));
473448
} else if (strcmp (bson_iter_key (&subiter), "q") == 0) {
474449
bson_iter_document (&subiter, &len, &data);
450+
451+
BSON_ASSERT (data);
452+
BSON_ASSERT (len >= 5);
453+
475454
if (len > max_bson_obj_size) {
476455
_mongoc_write_command_too_large_error (
477456
error, 0, len, max_bson_obj_size);

src/libmongoc/tests/bsonutil/bson-parser.c

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ typedef enum {
2727
BSON_PARSER_BOOL,
2828
BSON_PARSER_DOC,
2929
BSON_PARSER_ARRAY,
30+
BSON_PARSER_ARRAY_OR_DOC,
3031
BSON_PARSER_ANY,
3132
BSON_PARSER_WRITE_CONCERN,
3233
BSON_PARSER_READ_CONCERN,
@@ -62,6 +63,8 @@ parser_type_to_string (bson_parser_type_t ptype)
6263
return "DOC";
6364
case BSON_PARSER_ARRAY:
6465
return "ARRAY";
66+
case BSON_PARSER_ARRAY_OR_DOC:
67+
return "ARRAY or DOC";
6568
case BSON_PARSER_ANY:
6669
return "ANY";
6770
case BSON_PARSER_WRITE_CONCERN:
@@ -240,7 +243,8 @@ bson_parser_entry_destroy (bson_parser_entry_t *entry, bool with_parsed_fields)
240243
{
241244
if (with_parsed_fields) {
242245
if (entry->ptype == BSON_PARSER_DOC ||
243-
entry->ptype == BSON_PARSER_ARRAY) {
246+
entry->ptype == BSON_PARSER_ARRAY ||
247+
entry->ptype == BSON_PARSER_ARRAY_OR_DOC) {
244248
bson_t **out;
245249

246250
out = (bson_t **) entry->out;
@@ -399,6 +403,23 @@ bson_parser_array_optional (bson_parser_t *parser,
399403
bson_parser_add_entry (parser, key, (void *) out, BSON_PARSER_ARRAY, true);
400404
}
401405

406+
void
407+
bson_parser_array_or_doc (bson_parser_t *parser, const char *key, bson_t **out)
408+
{
409+
*out = NULL;
410+
bson_parser_add_entry (
411+
parser, key, (void *) out, BSON_PARSER_ARRAY_OR_DOC, false);
412+
}
413+
void
414+
bson_parser_array_or_doc_optional (bson_parser_t *parser,
415+
const char *key,
416+
bson_t **out)
417+
{
418+
*out = NULL;
419+
bson_parser_add_entry (
420+
parser, key, (void *) out, BSON_PARSER_ARRAY_OR_DOC, true);
421+
}
422+
402423
void
403424
bson_parser_bool (bson_parser_t *parser, const char *key, bool **out)
404425
{
@@ -579,6 +600,19 @@ entry_marshal (bson_parser_entry_t *entry,
579600
*out = bson_copy (&tmp);
580601
}
581602

603+
else if (ptype == BSON_PARSER_ARRAY_OR_DOC) {
604+
bson_t tmp;
605+
bson_t **out = (bson_t **) entry->out;
606+
607+
if (btype != BSON_TYPE_ARRAY && btype != BSON_TYPE_DOCUMENT) {
608+
marshal_error (key, btype, ptype, error);
609+
goto done;
610+
}
611+
612+
bson_iter_bson (iter, &tmp);
613+
*out = bson_copy (&tmp);
614+
}
615+
582616
else if (ptype == BSON_PARSER_ANY) {
583617
bson_val_t **out = (bson_val_t **) entry->out;
584618

src/libmongoc/tests/bsonutil/bson-parser.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,13 @@ bson_parser_array (bson_parser_t *bp, const char *key, bson_t **out);
8181
void
8282
bson_parser_array_optional (bson_parser_t *bp, const char *key, bson_t **out);
8383

84+
void
85+
bson_parser_array_or_doc (bson_parser_t *bp, const char *key, bson_t **out);
86+
void
87+
bson_parser_array_or_doc_optional (bson_parser_t *bp,
88+
const char *key,
89+
bson_t **out);
90+
8491
void
8592
bson_parser_bool (bson_parser_t *bp, const char *key, bool **out);
8693
void

0 commit comments

Comments
 (0)