-
Notifications
You must be signed in to change notification settings - Fork 455
CDRIVER-3895: Remove dots/dollars validation for insert/replace docs #801
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
95bcb21
fc62d89
2dddab2
f9f5dde
b30fa08
63e5118
c48e538
e4324be
29c50fb
e86d47c
3891867
52c2954
6441b0e
16488d6
e025cb0
798a71a
ad17e84
253045f
e870d34
985f830
fb67cdf
931a8f7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,13 +28,11 @@ | |
|
||
const bson_validate_flags_t _mongoc_default_insert_vflags = | ||
BSON_VALIDATE_UTF8 | BSON_VALIDATE_UTF8_ALLOW_NULL | | ||
BSON_VALIDATE_EMPTY_KEYS | BSON_VALIDATE_DOT_KEYS | | ||
BSON_VALIDATE_DOLLAR_KEYS; | ||
BSON_VALIDATE_EMPTY_KEYS; | ||
|
||
const bson_validate_flags_t _mongoc_default_replace_vflags = | ||
BSON_VALIDATE_UTF8 | BSON_VALIDATE_UTF8_ALLOW_NULL | | ||
BSON_VALIDATE_EMPTY_KEYS | BSON_VALIDATE_DOT_KEYS | | ||
BSON_VALIDATE_DOLLAR_KEYS; | ||
BSON_VALIDATE_EMPTY_KEYS; | ||
|
||
const bson_validate_flags_t _mongoc_default_update_vflags = | ||
BSON_VALIDATE_UTF8 | BSON_VALIDATE_UTF8_ALLOW_NULL | | ||
|
@@ -324,6 +322,8 @@ _mongoc_validate_replace (const bson_t *doc, | |
bson_error_t *error) | ||
{ | ||
bson_error_t validate_err; | ||
bson_iter_t iter; | ||
const char *key; | ||
|
||
if (vflags == BSON_VALIDATE_NONE) { | ||
return true; | ||
|
@@ -338,6 +338,27 @@ _mongoc_validate_replace (const bson_t *doc, | |
return false; | ||
} | ||
|
||
if (!bson_iter_init (&iter, doc)) { | ||
bson_set_error (error, | ||
MONGOC_ERROR_BSON, | ||
MONGOC_ERROR_BSON_INVALID, | ||
"replace document is corrupt"); | ||
return false; | ||
} | ||
|
||
while (bson_iter_next (&iter)) { | ||
key = bson_iter_key (&iter); | ||
if (key[0] == '$') { | ||
bson_set_error (error, | ||
MONGOC_ERROR_COMMAND, | ||
MONGOC_ERROR_COMMAND_INVALID_ARG, | ||
"Invalid key '%s': replace prohibits $ operators", | ||
key); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is basically the inverse of the existing logic in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The only reason I can see not to validate all fields is performance. But the previous behavior was checking for all fields (including nested fields) with |
||
|
||
return false; | ||
} | ||
} | ||
|
||
return true; | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -380,16 +380,13 @@ _mongoc_write_command_update_legacy (mongoc_write_command_t *command, | |
int32_t max_bson_obj_size; | ||
mongoc_rpc_t rpc; | ||
uint32_t request_id = 0; | ||
bson_iter_t subiter, subsubiter; | ||
bson_t doc; | ||
bson_iter_t subiter; | ||
bson_t update, selector; | ||
const uint8_t *data = NULL; | ||
uint32_t len = 0; | ||
size_t err_offset; | ||
bool val = false; | ||
char *ns; | ||
int vflags = (BSON_VALIDATE_UTF8 | BSON_VALIDATE_UTF8_ALLOW_NULL | | ||
BSON_VALIDATE_DOLLAR_KEYS | BSON_VALIDATE_DOT_KEYS); | ||
bool r; | ||
bson_reader_t *reader; | ||
const bson_t *bson; | ||
bool eof; | ||
|
@@ -406,45 +403,19 @@ _mongoc_write_command_update_legacy (mongoc_write_command_t *command, | |
|
||
max_bson_obj_size = mongoc_server_stream_max_bson_obj_size (server_stream); | ||
|
||
reader = | ||
bson_reader_new_from_data (command->payload.data, command->payload.len); | ||
while ((bson = bson_reader_read (reader, &eof))) { | ||
if (bson_iter_init (&subiter, bson) && bson_iter_find (&subiter, "u") && | ||
BSON_ITER_HOLDS_DOCUMENT (&subiter)) { | ||
bson_iter_document (&subiter, &len, &data); | ||
BSON_ASSERT (bson_init_static (&doc, data, len)); | ||
|
||
if (bson_iter_init (&subsubiter, &doc) && | ||
bson_iter_next (&subsubiter) && | ||
(bson_iter_key (&subsubiter)[0] != '$') && | ||
!bson_validate ( | ||
&doc, (bson_validate_flags_t) vflags, &err_offset)) { | ||
result->failed = true; | ||
bson_set_error (error, | ||
MONGOC_ERROR_BSON, | ||
MONGOC_ERROR_BSON_INVALID, | ||
"update document is corrupt or contains " | ||
"invalid keys including $ or ."); | ||
bson_reader_destroy (reader); | ||
EXIT; | ||
} | ||
} else { | ||
result->failed = true; | ||
bson_set_error (error, | ||
MONGOC_ERROR_BSON, | ||
MONGOC_ERROR_BSON_INVALID, | ||
"updates is malformed."); | ||
bson_reader_destroy (reader); | ||
EXIT; | ||
} | ||
} | ||
|
||
ns = bson_strdup_printf ("%s.%s", database, collection); | ||
|
||
bson_reader_destroy (reader); | ||
reader = | ||
bson_reader_new_from_data (command->payload.data, command->payload.len); | ||
while ((bson = bson_reader_read (reader, &eof))) { | ||
/* ensure the document has "q" and "u" document fields in that order */ | ||
r = (bson_iter_init (&subiter, bson) && bson_iter_find (&subiter, "q") && | ||
BSON_ITER_HOLDS_DOCUMENT (&subiter) && | ||
bson_iter_find (&subiter, "u") && | ||
BSON_ITER_HOLDS_DOCUMENT (&subiter)); | ||
|
||
BSON_ASSERT (r); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Checking that both fields exist is necessary since we don't explicitly fetch the fields later. For whatever reason, Note: I opted not to test for this assert failure, since it really isn't possible to trigger it from the public API. |
||
|
||
request_id = ++client->cluster.request_id; | ||
|
||
rpc.header.msg_len = 0; | ||
|
@@ -459,6 +430,10 @@ _mongoc_write_command_update_legacy (mongoc_write_command_t *command, | |
while (bson_iter_next (&subiter)) { | ||
if (strcmp (bson_iter_key (&subiter), "u") == 0) { | ||
bson_iter_document (&subiter, &len, &data); | ||
|
||
BSON_ASSERT (data); | ||
BSON_ASSERT (len >= 5); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice. Asserting the document is at least as large as an empty document is a good safety check. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shamelessly copied from |
||
|
||
if (len > max_bson_obj_size) { | ||
_mongoc_write_command_too_large_error ( | ||
error, 0, len, max_bson_obj_size); | ||
|
@@ -472,6 +447,10 @@ _mongoc_write_command_update_legacy (mongoc_write_command_t *command, | |
BSON_ASSERT (bson_init_static (&update, data, len)); | ||
} else if (strcmp (bson_iter_key (&subiter), "q") == 0) { | ||
bson_iter_document (&subiter, &len, &data); | ||
|
||
BSON_ASSERT (data); | ||
BSON_ASSERT (len >= 5); | ||
|
||
if (len > max_bson_obj_size) { | ||
_mongoc_write_command_too_large_error ( | ||
error, 0, len, max_bson_obj_size); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,6 +27,7 @@ typedef enum { | |
BSON_PARSER_BOOL, | ||
BSON_PARSER_DOC, | ||
BSON_PARSER_ARRAY, | ||
BSON_PARSER_ARRAY_OR_DOC, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was necessary for accepting documents or pipeline arrays for update operations. |
||
BSON_PARSER_ANY, | ||
BSON_PARSER_WRITE_CONCERN, | ||
BSON_PARSER_READ_CONCERN, | ||
|
@@ -62,6 +63,8 @@ parser_type_to_string (bson_parser_type_t ptype) | |
return "DOC"; | ||
case BSON_PARSER_ARRAY: | ||
return "ARRAY"; | ||
case BSON_PARSER_ARRAY_OR_DOC: | ||
return "ARRAY or DOC"; | ||
case BSON_PARSER_ANY: | ||
return "ANY"; | ||
case BSON_PARSER_WRITE_CONCERN: | ||
|
@@ -240,7 +243,8 @@ bson_parser_entry_destroy (bson_parser_entry_t *entry, bool with_parsed_fields) | |
{ | ||
if (with_parsed_fields) { | ||
if (entry->ptype == BSON_PARSER_DOC || | ||
entry->ptype == BSON_PARSER_ARRAY) { | ||
entry->ptype == BSON_PARSER_ARRAY || | ||
entry->ptype == BSON_PARSER_ARRAY_OR_DOC) { | ||
bson_t **out; | ||
|
||
out = (bson_t **) entry->out; | ||
|
@@ -399,6 +403,23 @@ bson_parser_array_optional (bson_parser_t *parser, | |
bson_parser_add_entry (parser, key, (void *) out, BSON_PARSER_ARRAY, true); | ||
} | ||
|
||
void | ||
bson_parser_array_or_doc (bson_parser_t *parser, const char *key, bson_t **out) | ||
{ | ||
*out = NULL; | ||
bson_parser_add_entry ( | ||
parser, key, (void *) out, BSON_PARSER_ARRAY_OR_DOC, false); | ||
} | ||
void | ||
bson_parser_array_or_doc_optional (bson_parser_t *parser, | ||
const char *key, | ||
bson_t **out) | ||
{ | ||
*out = NULL; | ||
bson_parser_add_entry ( | ||
parser, key, (void *) out, BSON_PARSER_ARRAY_OR_DOC, true); | ||
} | ||
|
||
void | ||
bson_parser_bool (bson_parser_t *parser, const char *key, bool **out) | ||
{ | ||
|
@@ -579,6 +600,19 @@ entry_marshal (bson_parser_entry_t *entry, | |
*out = bson_copy (&tmp); | ||
} | ||
|
||
else if (ptype == BSON_PARSER_ARRAY_OR_DOC) { | ||
bson_t tmp; | ||
bson_t **out = (bson_t **) entry->out; | ||
|
||
if (btype != BSON_TYPE_ARRAY && btype != BSON_TYPE_DOCUMENT) { | ||
marshal_error (key, btype, ptype, error); | ||
goto done; | ||
} | ||
|
||
bson_iter_bson (iter, &tmp); | ||
*out = bson_copy (&tmp); | ||
} | ||
|
||
else if (ptype == BSON_PARSER_ANY) { | ||
bson_val_t **out = (bson_val_t **) entry->out; | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With this change all three vflags are identical. The vflags aren't part of the public API, so we could have consolidated them into one value; however, I think leaving them as-is is fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, leaving them as-is seems OK.