1
2 /**
3 * Copyright (C) 2018-present MongoDB, Inc.
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the Server Side Public License, version 1,
7 * as published by MongoDB, Inc.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * Server Side Public License for more details.
13 *
14 * You should have received a copy of the Server Side Public License
15 * along with this program. If not, see
16 * <http://www.mongodb.com/licensing/server-side-public-license>.
17 *
18 * As a special exception, the copyright holders give permission to link the
19 * code of portions of this program with the OpenSSL library under certain
20 * conditions as described in each individual source file and distribute
21 * linked combinations including the program with the OpenSSL library. You
22 * must comply with the Server Side Public License in all respects for
23 * all of the code used other than as permitted herein. If you modify file(s)
24 * with this exception, you may extend this exception to your version of the
25 * file(s), but you are not obligated to do so. If you do not wish to do so,
26 * delete this exception statement from your version. If you delete this
27 * exception statement from all source files in the program, then also delete
28 * it in the license file.
29 */
30
31 #define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kDefault
32
33 #include "mongo/db/jsobj.h"
34
35 #include "mongo/base/data_range.h"
36 #include "mongo/bson/bson_validate.h"
37 #include "mongo/bson/bsonelement_comparator_interface.h"
38 #include "mongo/db/json.h"
39 #include "mongo/util/allocator.h"
40 #include "mongo/util/hex.h"
41 #include "mongo/util/log.h"
42 #include "mongo/util/mongoutils/str.h"
43 #include "mongo/util/stringutils.h"
44
45 namespace mongo {
46
47 namespace {
48
49 template <class ObjectIterator>
compareObjects(const BSONObj & firstObj,const BSONObj & secondObj,const BSONObj & idxKey,BSONObj::ComparisonRulesSet rules,const StringData::ComparatorInterface * comparator)50 int compareObjects(const BSONObj& firstObj,
51 const BSONObj& secondObj,
52 const BSONObj& idxKey,
53 BSONObj::ComparisonRulesSet rules,
54 const StringData::ComparatorInterface* comparator) {
55 if (firstObj.isEmpty())
56 return secondObj.isEmpty() ? 0 : -1;
57 if (secondObj.isEmpty())
58 return 1;
59
60 ObjectIterator firstIter(firstObj);
61 ObjectIterator secondIter(secondObj);
62 ObjectIterator idxKeyIter(idxKey);
63
64 while (true) {
65 BSONElement l = firstIter.next();
66 BSONElement r = secondIter.next();
67
68 if (l.eoo())
69 return r.eoo() ? 0 : -1;
70 if (r.eoo())
71 return 1;
72
73 auto x = l.woCompare(r, rules, comparator);
74
75 if (idxKeyIter.more() && idxKeyIter.next().number() < 0)
76 x = -x;
77
78 if (x != 0)
79 return x;
80 }
81
82 MONGO_UNREACHABLE;
83 }
84
85 } // namespace
86
87 using namespace std;
88
89 /* BSONObj ------------------------------------------------------------*/
90
_assertInvalid(int maxSize) const91 void BSONObj::_assertInvalid(int maxSize) const {
92 StringBuilder ss;
93 int os = objsize();
94 ss << "BSONObj size: " << os << " (0x" << integerToHex(os) << ") is invalid. "
95 << "Size must be between 0 and " << BSONObjMaxInternalSize << "("
96 << (maxSize / (1024 * 1024)) << "MB)";
97 try {
98 BSONElement e = firstElement();
99 ss << " First element: " << e.toString();
100 } catch (...) {
101 }
102 massert(10334, ss.str(), 0);
103 }
104
copy() const105 BSONObj BSONObj::copy() const {
106 auto storage = SharedBuffer::allocate(objsize());
107 memcpy(storage.get(), objdata(), objsize());
108 return BSONObj(std::move(storage));
109 }
110
getOwned() const111 BSONObj BSONObj::getOwned() const {
112 if (isOwned())
113 return *this;
114 return copy();
115 }
116
jsonString(JsonStringFormat format,int pretty,bool isArray) const117 string BSONObj::jsonString(JsonStringFormat format, int pretty, bool isArray) const {
118 if (isEmpty())
119 return isArray ? "[]" : "{}";
120
121 StringBuilder s;
122 s << (isArray ? "[ " : "{ ");
123 BSONObjIterator i(*this);
124 BSONElement e = i.next();
125 if (!e.eoo())
126 while (1) {
127 s << e.jsonString(format, !isArray, pretty ? pretty + 1 : 0);
128 e = i.next();
129 if (e.eoo())
130 break;
131 s << ",";
132 if (pretty) {
133 s << '\n';
134 for (int x = 0; x < pretty; x++)
135 s << " ";
136 } else {
137 s << " ";
138 }
139 }
140 s << (isArray ? " ]" : " }");
141 return s.str();
142 }
143
valid(BSONVersion version) const144 bool BSONObj::valid(BSONVersion version) const {
145 return validateBSON(objdata(), objsize(), version).isOK();
146 }
147
woCompare(const BSONObj & r,const Ordering & o,ComparisonRulesSet rules,const StringData::ComparatorInterface * comparator) const148 int BSONObj::woCompare(const BSONObj& r,
149 const Ordering& o,
150 ComparisonRulesSet rules,
151 const StringData::ComparatorInterface* comparator) const {
152 if (isEmpty())
153 return r.isEmpty() ? 0 : -1;
154 if (r.isEmpty())
155 return 1;
156
157 BSONObjIterator i(*this);
158 BSONObjIterator j(r);
159 unsigned mask = 1;
160 while (1) {
161 // so far, equal...
162
163 BSONElement l = i.next();
164 BSONElement r = j.next();
165 if (l.eoo())
166 return r.eoo() ? 0 : -1;
167 if (r.eoo())
168 return 1;
169
170 int x;
171 {
172 x = l.woCompare(r, rules, comparator);
173 if (o.descending(mask))
174 x = -x;
175 }
176 if (x != 0)
177 return x;
178 mask <<= 1;
179 }
180 return -1;
181 }
182
183 /* well ordered compare */
woCompare(const BSONObj & r,const BSONObj & idxKey,ComparisonRulesSet rules,const StringData::ComparatorInterface * comparator) const184 int BSONObj::woCompare(const BSONObj& r,
185 const BSONObj& idxKey,
186 ComparisonRulesSet rules,
187 const StringData::ComparatorInterface* comparator) const {
188 return (rules & ComparisonRules::kIgnoreFieldOrder)
189 ? compareObjects<BSONObjIteratorSorted>(*this, r, idxKey, rules, comparator)
190 : compareObjects<BSONObjIterator>(*this, r, idxKey, rules, comparator);
191 }
192
isPrefixOf(const BSONObj & otherObj,const BSONElement::ComparatorInterface & eltCmp) const193 bool BSONObj::isPrefixOf(const BSONObj& otherObj,
194 const BSONElement::ComparatorInterface& eltCmp) const {
195 BSONObjIterator a(*this);
196 BSONObjIterator b(otherObj);
197
198 while (a.more() && b.more()) {
199 BSONElement x = a.next();
200 BSONElement y = b.next();
201 if (eltCmp.evaluate(x != y))
202 return false;
203 }
204
205 return !a.more();
206 }
207
isFieldNamePrefixOf(const BSONObj & otherObj) const208 bool BSONObj::isFieldNamePrefixOf(const BSONObj& otherObj) const {
209 BSONObjIterator a(*this);
210 BSONObjIterator b(otherObj);
211
212 while (a.more() && b.more()) {
213 BSONElement x = a.next();
214 BSONElement y = b.next();
215 if (!str::equals(x.fieldName(), y.fieldName())) {
216 return false;
217 }
218 }
219
220 return !a.more();
221 }
222
extractFieldsUnDotted(const BSONObj & pattern) const223 BSONObj BSONObj::extractFieldsUnDotted(const BSONObj& pattern) const {
224 BSONObjBuilder b;
225 BSONObjIterator i(pattern);
226 while (i.moreWithEOO()) {
227 BSONElement e = i.next();
228 if (e.eoo())
229 break;
230 BSONElement x = getField(e.fieldName());
231 if (!x.eoo())
232 b.appendAs(x, "");
233 }
234 return b.obj();
235 }
236
filterFieldsUndotted(const BSONObj & filter,bool inFilter) const237 BSONObj BSONObj::filterFieldsUndotted(const BSONObj& filter, bool inFilter) const {
238 BSONObjBuilder b;
239 BSONObjIterator i(*this);
240 while (i.moreWithEOO()) {
241 BSONElement e = i.next();
242 if (e.eoo())
243 break;
244 BSONElement x = filter.getField(e.fieldName());
245 if ((x.eoo() && !inFilter) || (!x.eoo() && inFilter))
246 b.append(e);
247 }
248 return b.obj();
249 }
250
getFieldUsingIndexNames(StringData fieldName,const BSONObj & indexKey) const251 BSONElement BSONObj::getFieldUsingIndexNames(StringData fieldName, const BSONObj& indexKey) const {
252 BSONObjIterator i(indexKey);
253 int j = 0;
254 while (i.moreWithEOO()) {
255 BSONElement f = i.next();
256 if (f.eoo())
257 return BSONElement();
258 if (f.fieldName() == fieldName)
259 break;
260 ++j;
261 }
262 BSONObjIterator k(*this);
263 while (k.moreWithEOO()) {
264 BSONElement g = k.next();
265 if (g.eoo())
266 return BSONElement();
267 if (j == 0) {
268 return g;
269 }
270 --j;
271 }
272 return BSONElement();
273 }
274
275 /* grab names of all the fields in this object */
getFieldNames(set<string> & fields) const276 int BSONObj::getFieldNames(set<string>& fields) const {
277 int n = 0;
278 BSONObjIterator i(*this);
279 while (i.moreWithEOO()) {
280 BSONElement e = i.next();
281 if (e.eoo())
282 break;
283 fields.insert(e.fieldName());
284 n++;
285 }
286 return n;
287 }
288
289 /* note: addFields always adds _id even if not specified
290 returns n added not counting _id unless requested.
291 */
addFields(BSONObj & from,set<string> & fields)292 int BSONObj::addFields(BSONObj& from, set<string>& fields) {
293 verify(isEmpty() && !isOwned()); /* partial implementation for now... */
294
295 BSONObjBuilder b;
296
297 int N = fields.size();
298 int n = 0;
299 BSONObjIterator i(from);
300 bool gotId = false;
301 while (i.moreWithEOO()) {
302 BSONElement e = i.next();
303 const char* fname = e.fieldName();
304 if (fields.count(fname)) {
305 b.append(e);
306 ++n;
307 gotId = gotId || strcmp(fname, "_id") == 0;
308 if (n == N && gotId)
309 break;
310 } else if (strcmp(fname, "_id") == 0) {
311 b.append(e);
312 gotId = true;
313 if (n == N && gotId)
314 break;
315 }
316 }
317
318 if (n) {
319 *this = b.obj();
320 }
321
322 return n;
323 }
324
couldBeArray() const325 bool BSONObj::couldBeArray() const {
326 BSONObjIterator i(*this);
327 int index = 0;
328 while (i.moreWithEOO()) {
329 BSONElement e = i.next();
330 if (e.eoo())
331 break;
332
333 // TODO: If actually important, may be able to do int->char* much faster
334 if (strcmp(e.fieldName(), ((string)(str::stream() << index)).c_str()) != 0)
335 return false;
336 index++;
337 }
338 return true;
339 }
340
clientReadable() const341 BSONObj BSONObj::clientReadable() const {
342 BSONObjBuilder b;
343 BSONObjIterator i(*this);
344 while (i.moreWithEOO()) {
345 BSONElement e = i.next();
346 if (e.eoo())
347 break;
348 switch (e.type()) {
349 case MinKey: {
350 BSONObjBuilder m;
351 m.append("$minElement", 1);
352 b.append(e.fieldName(), m.done());
353 break;
354 }
355 case MaxKey: {
356 BSONObjBuilder m;
357 m.append("$maxElement", 1);
358 b.append(e.fieldName(), m.done());
359 break;
360 }
361 default:
362 b.append(e);
363 }
364 }
365 return b.obj();
366 }
367
replaceFieldNames(const BSONObj & names) const368 BSONObj BSONObj::replaceFieldNames(const BSONObj& names) const {
369 BSONObjBuilder b;
370 BSONObjIterator i(*this);
371 BSONObjIterator j(names);
372 BSONElement f = j.moreWithEOO() ? j.next() : BSONObj().firstElement();
373 while (i.moreWithEOO()) {
374 BSONElement e = i.next();
375 if (e.eoo())
376 break;
377 if (!f.eoo()) {
378 b.appendAs(e, f.fieldName());
379 f = j.next();
380 } else {
381 b.append(e);
382 }
383 }
384 return b.obj();
385 }
386
storageValidEmbedded() const387 Status BSONObj::storageValidEmbedded() const {
388 BSONObjIterator i(*this);
389
390 // The first field is special in the case of a DBRef where the first field must be $ref
391 bool first = true;
392 while (i.more()) {
393 BSONElement e = i.next();
394 const char* name = e.fieldName();
395
396 // Cannot start with "$", unless dbref which must start with ($ref, $id)
397 if (str::startsWith(name, '$')) {
398 if (first &&
399 // $ref is a collection name and must be a String
400 str::equals(name, "$ref") &&
401 e.type() == String && str::equals(i.next().fieldName(), "$id")) {
402 first = false;
403 // keep inspecting fields for optional "$db"
404 e = i.next();
405 name = e.fieldName(); // "" if eoo()
406
407 // optional $db field must be a String
408 if (str::equals(name, "$db") && e.type() == String) {
409 continue; // this element is fine, so continue on to siblings (if any more)
410 }
411
412 // Can't start with a "$", all other checks are done below (outside if blocks)
413 if (str::startsWith(name, '$')) {
414 return Status(ErrorCodes::DollarPrefixedFieldName,
415 str::stream() << name << " is not valid for storage.");
416 }
417 } else {
418 // not an okay, $ prefixed field name.
419 return Status(ErrorCodes::DollarPrefixedFieldName,
420 str::stream() << name << " is not valid for storage.");
421 }
422 }
423
424 if (e.mayEncapsulate()) {
425 switch (e.type()) {
426 case Object:
427 case Array: {
428 Status s = e.embeddedObject().storageValidEmbedded();
429 // TODO: combine field names for better error messages
430 if (!s.isOK())
431 return s;
432 } break;
433 case CodeWScope: {
434 Status s = e.codeWScopeObject().storageValidEmbedded();
435 // TODO: combine field names for better error messages
436 if (!s.isOK())
437 return s;
438 } break;
439 default:
440 uassert(12579, "unhandled cases in BSONObj storageValidEmbedded", 0);
441 }
442 }
443
444 // After we have processed one field, we are no longer on the first field
445 first = false;
446 }
447 return Status::OK();
448 }
449
dump() const450 void BSONObj::dump() const {
451 LogstreamBuilder builder = log();
452 builder << hex;
453 const char* p = objdata();
454 for (int i = 0; i < objsize(); i++) {
455 builder << i << '\t' << (0xff & ((unsigned)*p));
456 if (*p >= 'A' && *p <= 'z')
457 builder << '\t' << *p;
458 p++;
459 }
460 }
461
getFields(unsigned n,const char ** fieldNames,BSONElement * fields) const462 void BSONObj::getFields(unsigned n, const char** fieldNames, BSONElement* fields) const {
463 BSONObjIterator i(*this);
464 while (i.more()) {
465 BSONElement e = i.next();
466 const char* p = e.fieldName();
467 for (unsigned i = 0; i < n; i++) {
468 if (strcmp(p, fieldNames[i]) == 0) {
469 fields[i] = e;
470 break;
471 }
472 }
473 }
474 }
475
getField(StringData name) const476 BSONElement BSONObj::getField(StringData name) const {
477 BSONObjIterator i(*this);
478 while (i.more()) {
479 BSONElement e = i.next();
480 // We know that e has a cached field length since BSONObjIterator::next internally
481 // called BSONElement::size on the BSONElement that it returned, so it is more
482 // efficient to re-use that information by obtaining the field name as a
483 // StringData, which will be pre-populated with the cached length.
484 if (name == e.fieldNameStringData())
485 return e;
486 }
487 return BSONElement();
488 }
489
getIntField(StringData name) const490 int BSONObj::getIntField(StringData name) const {
491 BSONElement e = getField(name);
492 return e.isNumber() ? (int)e.number() : std::numeric_limits<int>::min();
493 }
494
getBoolField(StringData name) const495 bool BSONObj::getBoolField(StringData name) const {
496 BSONElement e = getField(name);
497 return e.type() == Bool ? e.boolean() : false;
498 }
499
getStringField(StringData name) const500 const char* BSONObj::getStringField(StringData name) const {
501 BSONElement e = getField(name);
502 return e.type() == String ? e.valuestr() : "";
503 }
504
getObjectID(BSONElement & e) const505 bool BSONObj::getObjectID(BSONElement& e) const {
506 BSONElement f = getField("_id");
507 if (!f.eoo()) {
508 e = f;
509 return true;
510 }
511 return false;
512 }
513
addField(const BSONElement & field) const514 BSONObj BSONObj::addField(const BSONElement& field) const {
515 if (!field.ok())
516 return copy();
517 BSONObjBuilder b;
518 StringData name = field.fieldNameStringData();
519 bool added = false;
520 for (auto e : *this) {
521 if (e.fieldNameStringData() == name) {
522 if (!added)
523 b.append(field);
524 added = true;
525 } else {
526 b.append(e);
527 }
528 }
529 if (!added)
530 b.append(field);
531 return b.obj();
532 }
533
removeField(StringData name) const534 BSONObj BSONObj::removeField(StringData name) const {
535 BSONObjBuilder b;
536 BSONObjIterator i(*this);
537 while (i.more()) {
538 BSONElement e = i.next();
539 const char* fname = e.fieldName();
540 if (name != fname)
541 b.append(e);
542 }
543 return b.obj();
544 }
545
hexDump() const546 std::string BSONObj::hexDump() const {
547 std::stringstream ss;
548 const char* d = objdata();
549 int size = objsize();
550 for (int i = 0; i < size; ++i) {
551 ss.width(2);
552 ss.fill('0');
553 ss << std::hex << (unsigned)(unsigned char)(d[i]) << std::dec;
554 if ((d[i] >= '0' && d[i] <= '9') || (d[i] >= 'A' && d[i] <= 'z'))
555 ss << '\'' << d[i] << '\'';
556 if (i != size - 1)
557 ss << ' ';
558 }
559 return ss.str();
560 }
561
562
elems(std::vector<BSONElement> & v) const563 void BSONObj::elems(std::vector<BSONElement>& v) const {
564 BSONObjIterator i(*this);
565 while (i.more())
566 v.push_back(i.next());
567 }
568
elems(std::list<BSONElement> & v) const569 void BSONObj::elems(std::list<BSONElement>& v) const {
570 BSONObjIterator i(*this);
571 while (i.more())
572 v.push_back(i.next());
573 }
574
getObjectField(StringData name) const575 BSONObj BSONObj::getObjectField(StringData name) const {
576 BSONElement e = getField(name);
577 BSONType t = e.type();
578 return t == Object || t == Array ? e.embeddedObject() : BSONObj();
579 }
580
nFields() const581 int BSONObj::nFields() const {
582 int n = 0;
583 BSONObjIterator i(*this);
584 while (i.moreWithEOO()) {
585 BSONElement e = i.next();
586 if (e.eoo())
587 break;
588 n++;
589 }
590 return n;
591 }
592
toString(bool redactValues) const593 std::string BSONObj::toString(bool redactValues) const {
594 if (isEmpty())
595 return "{}";
596 StringBuilder s;
597 toString(s, false, false, redactValues);
598 return s.str();
599 }
toString(StringBuilder & s,bool isArray,bool full,bool redactValues,int depth) const600 void BSONObj::toString(
601 StringBuilder& s, bool isArray, bool full, bool redactValues, int depth) const {
602 if (isEmpty()) {
603 s << (isArray ? "[]" : "{}");
604 return;
605 }
606
607 s << (isArray ? "[ " : "{ ");
608 BSONObjIterator i(*this);
609 bool first = true;
610 while (1) {
611 massert(10327, "Object does not end with EOO", i.moreWithEOO());
612 BSONElement e = i.next();
613 massert(10328, "Invalid element size", e.size() > 0);
614 massert(10329, "Element too large", e.size() < (1 << 30));
615 int offset = (int)(e.rawdata() - this->objdata());
616 massert(10330, "Element extends past end of object", e.size() + offset <= this->objsize());
617 bool end = (e.size() + offset == this->objsize());
618 if (e.eoo()) {
619 massert(10331, "EOO Before end of object", end);
620 break;
621 }
622 if (first)
623 first = false;
624 else
625 s << ", ";
626 e.toString(s, !isArray, full, redactValues, depth);
627 }
628 s << (isArray ? " ]" : " }");
629 }
630
store(const BSONObj & bson,char * ptr,size_t length,size_t * advanced,std::ptrdiff_t debug_offset)631 Status DataType::Handler<BSONObj>::store(
632 const BSONObj& bson, char* ptr, size_t length, size_t* advanced, std::ptrdiff_t debug_offset) {
633 if (bson.objsize() > static_cast<int>(length)) {
634 mongoutils::str::stream ss;
635 ss << "buffer too small to write bson of size (" << bson.objsize()
636 << ") at offset: " << debug_offset;
637 return Status(ErrorCodes::Overflow, ss);
638 }
639
640 if (ptr) {
641 std::memcpy(ptr, bson.objdata(), bson.objsize());
642 }
643
644 if (advanced) {
645 *advanced = bson.objsize();
646 }
647
648 return Status::OK();
649 }
650
operator <<(std::ostream & s,const BSONObj & o)651 std::ostream& operator<<(std::ostream& s, const BSONObj& o) {
652 return s << o.toString();
653 }
654
operator <<(StringBuilder & s,const BSONObj & o)655 StringBuilder& operator<<(StringBuilder& s, const BSONObj& o) {
656 o.toString(s);
657 return s;
658 }
659
660 /** Compare two bson elements, provided as const char *'s, by field name. */
661 class BSONIteratorSorted::ElementFieldCmp {
662 public:
663 ElementFieldCmp(bool isArray);
664 bool operator()(const char* s1, const char* s2) const;
665
666 private:
667 LexNumCmp _cmp;
668 };
669
ElementFieldCmp(bool isArray)670 BSONIteratorSorted::ElementFieldCmp::ElementFieldCmp(bool isArray) : _cmp(!isArray) {}
671
operator ()(const char * s1,const char * s2) const672 bool BSONIteratorSorted::ElementFieldCmp::operator()(const char* s1, const char* s2) const {
673 // Skip the type byte and compare field names.
674 return _cmp(s1 + 1, s2 + 1);
675 }
676
BSONIteratorSorted(const BSONObj & o,const ElementFieldCmp & cmp)677 BSONIteratorSorted::BSONIteratorSorted(const BSONObj& o, const ElementFieldCmp& cmp)
678 : _nfields(o.nFields()), _fields(new const char*[_nfields]) {
679 int x = 0;
680 BSONObjIterator i(o);
681 while (i.more()) {
682 _fields[x++] = i.next().rawdata();
683 verify(_fields[x - 1]);
684 }
685 verify(x == _nfields);
686 std::sort(_fields.get(), _fields.get() + _nfields, cmp);
687 _cur = 0;
688 }
689
BSONObjIteratorSorted(const BSONObj & object)690 BSONObjIteratorSorted::BSONObjIteratorSorted(const BSONObj& object)
691 : BSONIteratorSorted(object, ElementFieldCmp(false)) {}
692
BSONArrayIteratorSorted(const BSONArray & array)693 BSONArrayIteratorSorted::BSONArrayIteratorSorted(const BSONArray& array)
694 : BSONIteratorSorted(array, ElementFieldCmp(true)) {}
695
696 } // namespace mongo
697