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