You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

document.go 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. // Copyright (C) MongoDB, Inc. 2017-present.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License"); you may
  4. // not use this file except in compliance with the License. You may obtain
  5. // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
  6. package bsoncore
  7. import (
  8. "bytes"
  9. "errors"
  10. "fmt"
  11. "io"
  12. "strconv"
  13. "github.com/go-stack/stack"
  14. "go.mongodb.org/mongo-driver/bson/bsontype"
  15. )
  16. // DocumentValidationError is an error type returned when attempting to validate a document.
  17. type DocumentValidationError string
  18. func (dve DocumentValidationError) Error() string { return string(dve) }
  19. // NewDocumentLengthError creates and returns an error for when the length of a document exceeds the
  20. // bytes available.
  21. func NewDocumentLengthError(length, rem int) error {
  22. return DocumentValidationError(
  23. fmt.Sprintf("document length exceeds available bytes. length=%d remainingBytes=%d", length, rem),
  24. )
  25. }
  26. // InsufficientBytesError indicates that there were not enough bytes to read the next component.
  27. type InsufficientBytesError struct {
  28. Source []byte
  29. Remaining []byte
  30. Stack stack.CallStack
  31. }
  32. // NewInsufficientBytesError creates a new InsufficientBytesError with the given Document, remaining
  33. // bytes, and the current stack.
  34. func NewInsufficientBytesError(src, rem []byte) InsufficientBytesError {
  35. return InsufficientBytesError{Source: src, Remaining: rem, Stack: stack.Trace().TrimRuntime()}
  36. }
  37. // Error implements the error interface.
  38. func (ibe InsufficientBytesError) Error() string {
  39. return "too few bytes to read next component"
  40. }
  41. // ErrorStack returns a string representing the stack at the point where the error occurred.
  42. func (ibe InsufficientBytesError) ErrorStack() string {
  43. s := bytes.NewBufferString("too few bytes to read next component: [")
  44. for i, call := range ibe.Stack {
  45. if i != 0 {
  46. s.WriteString(", ")
  47. }
  48. // go vet doesn't like %k even though it's part of stack's API, so we move the format
  49. // string so it doesn't complain. (We also can't make it a constant, or go vet still
  50. // complains.)
  51. callFormat := "%k.%n %v"
  52. s.WriteString(fmt.Sprintf(callFormat, call, call, call))
  53. }
  54. s.WriteRune(']')
  55. return s.String()
  56. }
  57. // Equal checks that err2 also is an ErrTooSmall.
  58. func (ibe InsufficientBytesError) Equal(err2 error) bool {
  59. switch err2.(type) {
  60. case InsufficientBytesError:
  61. return true
  62. default:
  63. return false
  64. }
  65. }
  66. // InvalidDepthTraversalError is returned when attempting a recursive Lookup when one component of
  67. // the path is neither an embedded document nor an array.
  68. type InvalidDepthTraversalError struct {
  69. Key string
  70. Type bsontype.Type
  71. }
  72. func (idte InvalidDepthTraversalError) Error() string {
  73. return fmt.Sprintf(
  74. "attempt to traverse into %s, but it's type is %s, not %s nor %s",
  75. idte.Key, idte.Type, bsontype.EmbeddedDocument, bsontype.Array,
  76. )
  77. }
  78. // ErrMissingNull is returned when a document's last byte is not null.
  79. const ErrMissingNull DocumentValidationError = "document end is missing null byte"
  80. // ErrNilReader indicates that an operation was attempted on a nil io.Reader.
  81. var ErrNilReader = errors.New("nil reader")
  82. // ErrInvalidLength indicates that a length in a binary representation of a BSON document is invalid.
  83. var ErrInvalidLength = errors.New("document length is invalid")
  84. // ErrEmptyKey indicates that no key was provided to a Lookup method.
  85. var ErrEmptyKey = errors.New("empty key provided")
  86. // ErrElementNotFound indicates that an Element matching a certain condition does not exist.
  87. var ErrElementNotFound = errors.New("element not found")
  88. // ErrOutOfBounds indicates that an index provided to access something was invalid.
  89. var ErrOutOfBounds = errors.New("out of bounds")
  90. // Document is a raw bytes representation of a BSON document.
  91. type Document []byte
  92. // Array is a raw bytes representation of a BSON array.
  93. type Array = Document
  94. // NewDocumentFromReader reads a document from r. This function will only validate the length is
  95. // correct and that the document ends with a null byte.
  96. func NewDocumentFromReader(r io.Reader) (Document, error) {
  97. if r == nil {
  98. return nil, ErrNilReader
  99. }
  100. var lengthBytes [4]byte
  101. // ReadFull guarantees that we will have read at least len(lengthBytes) if err == nil
  102. _, err := io.ReadFull(r, lengthBytes[:])
  103. if err != nil {
  104. return nil, err
  105. }
  106. length, _, _ := readi32(lengthBytes[:]) // ignore ok since we always have enough bytes to read a length
  107. if length < 0 {
  108. return nil, ErrInvalidLength
  109. }
  110. document := make([]byte, length)
  111. copy(document, lengthBytes[:])
  112. _, err = io.ReadFull(r, document[4:])
  113. if err != nil {
  114. return nil, err
  115. }
  116. if document[length-1] != 0x00 {
  117. return nil, ErrMissingNull
  118. }
  119. return document, nil
  120. }
  121. // Lookup searches the document, potentially recursively, for the given key. If there are multiple
  122. // keys provided, this method will recurse down, as long as the top and intermediate nodes are
  123. // either documents or arrays. If an error occurs or if the value doesn't exist, an empty Value is
  124. // returned.
  125. func (d Document) Lookup(key ...string) Value {
  126. val, _ := d.LookupErr(key...)
  127. return val
  128. }
  129. // LookupErr is the same as Lookup, except it returns an error in addition to an empty Value.
  130. func (d Document) LookupErr(key ...string) (Value, error) {
  131. if len(key) < 1 {
  132. return Value{}, ErrEmptyKey
  133. }
  134. length, rem, ok := ReadLength(d)
  135. if !ok {
  136. return Value{}, NewInsufficientBytesError(d, rem)
  137. }
  138. length -= 4
  139. var elem Element
  140. for length > 1 {
  141. elem, rem, ok = ReadElement(rem)
  142. length -= int32(len(elem))
  143. if !ok {
  144. return Value{}, NewInsufficientBytesError(d, rem)
  145. }
  146. if elem.Key() != key[0] {
  147. continue
  148. }
  149. if len(key) > 1 {
  150. tt := bsontype.Type(elem[0])
  151. switch tt {
  152. case bsontype.EmbeddedDocument:
  153. val, err := elem.Value().Document().LookupErr(key[1:]...)
  154. if err != nil {
  155. return Value{}, err
  156. }
  157. return val, nil
  158. case bsontype.Array:
  159. val, err := elem.Value().Array().LookupErr(key[1:]...)
  160. if err != nil {
  161. return Value{}, err
  162. }
  163. return val, nil
  164. default:
  165. return Value{}, InvalidDepthTraversalError{Key: elem.Key(), Type: tt}
  166. }
  167. }
  168. return elem.ValueErr()
  169. }
  170. return Value{}, ErrElementNotFound
  171. }
  172. // Index searches for and retrieves the element at the given index. This method will panic if
  173. // the document is invalid or if the index is out of bounds.
  174. func (d Document) Index(index uint) Element {
  175. elem, err := d.IndexErr(index)
  176. if err != nil {
  177. panic(err)
  178. }
  179. return elem
  180. }
  181. // IndexErr searches for and retrieves the element at the given index.
  182. func (d Document) IndexErr(index uint) (Element, error) {
  183. length, rem, ok := ReadLength(d)
  184. if !ok {
  185. return nil, NewInsufficientBytesError(d, rem)
  186. }
  187. length -= 4
  188. var current uint
  189. var elem Element
  190. for length > 1 {
  191. elem, rem, ok = ReadElement(rem)
  192. length -= int32(len(elem))
  193. if !ok {
  194. return nil, NewInsufficientBytesError(d, rem)
  195. }
  196. if current != index {
  197. current++
  198. continue
  199. }
  200. return elem, nil
  201. }
  202. return nil, ErrOutOfBounds
  203. }
  204. // DebugString outputs a human readable version of Document. It will attempt to stringify the
  205. // valid components of the document even if the entire document is not valid.
  206. func (d Document) DebugString() string {
  207. if len(d) < 5 {
  208. return "<malformed>"
  209. }
  210. var buf bytes.Buffer
  211. buf.WriteString("Document")
  212. length, rem, _ := ReadLength(d) // We know we have enough bytes to read the length
  213. buf.WriteByte('(')
  214. buf.WriteString(strconv.Itoa(int(length)))
  215. length -= 4
  216. buf.WriteString("){")
  217. var elem Element
  218. var ok bool
  219. for length > 1 {
  220. elem, rem, ok = ReadElement(rem)
  221. length -= int32(len(elem))
  222. if !ok {
  223. buf.WriteString(fmt.Sprintf("<malformed (%d)>", length))
  224. break
  225. }
  226. fmt.Fprintf(&buf, "%s ", elem.DebugString())
  227. }
  228. buf.WriteByte('}')
  229. return buf.String()
  230. }
  231. // String outputs an ExtendedJSON version of Document. If the document is not valid, this method
  232. // returns an empty string.
  233. func (d Document) String() string {
  234. if len(d) < 5 {
  235. return ""
  236. }
  237. var buf bytes.Buffer
  238. buf.WriteByte('{')
  239. length, rem, _ := ReadLength(d) // We know we have enough bytes to read the length
  240. length -= 4
  241. var elem Element
  242. var ok bool
  243. first := true
  244. for length > 1 {
  245. if !first {
  246. buf.WriteByte(',')
  247. }
  248. elem, rem, ok = ReadElement(rem)
  249. length -= int32(len(elem))
  250. if !ok {
  251. return ""
  252. }
  253. fmt.Fprintf(&buf, "%s", elem.String())
  254. first = false
  255. }
  256. buf.WriteByte('}')
  257. return buf.String()
  258. }
  259. // Elements returns this document as a slice of elements. The returned slice will contain valid
  260. // elements. If the document is not valid, the elements up to the invalid point will be returned
  261. // along with an error.
  262. func (d Document) Elements() ([]Element, error) {
  263. length, rem, ok := ReadLength(d)
  264. if !ok {
  265. return nil, NewInsufficientBytesError(d, rem)
  266. }
  267. length -= 4
  268. var elem Element
  269. var elems []Element
  270. for length > 1 {
  271. elem, rem, ok = ReadElement(rem)
  272. length -= int32(len(elem))
  273. if !ok {
  274. return elems, NewInsufficientBytesError(d, rem)
  275. }
  276. if err := elem.Validate(); err != nil {
  277. return elems, err
  278. }
  279. elems = append(elems, elem)
  280. }
  281. return elems, nil
  282. }
  283. // Values returns this document as a slice of values. The returned slice will contain valid values.
  284. // If the document is not valid, the values up to the invalid point will be returned along with an
  285. // error.
  286. func (d Document) Values() ([]Value, error) {
  287. length, rem, ok := ReadLength(d)
  288. if !ok {
  289. return nil, NewInsufficientBytesError(d, rem)
  290. }
  291. length -= 4
  292. var elem Element
  293. var vals []Value
  294. for length > 1 {
  295. elem, rem, ok = ReadElement(rem)
  296. length -= int32(len(elem))
  297. if !ok {
  298. return vals, NewInsufficientBytesError(d, rem)
  299. }
  300. if err := elem.Value().Validate(); err != nil {
  301. return vals, err
  302. }
  303. vals = append(vals, elem.Value())
  304. }
  305. return vals, nil
  306. }
  307. // Validate validates the document and ensures the elements contained within are valid.
  308. func (d Document) Validate() error {
  309. length, rem, ok := ReadLength(d)
  310. if !ok {
  311. return NewInsufficientBytesError(d, rem)
  312. }
  313. if int(length) > len(d) {
  314. return d.lengtherror(int(length), len(d))
  315. }
  316. if d[length-1] != 0x00 {
  317. return ErrMissingNull
  318. }
  319. length -= 4
  320. var elem Element
  321. for length > 1 {
  322. elem, rem, ok = ReadElement(rem)
  323. length -= int32(len(elem))
  324. if !ok {
  325. return NewInsufficientBytesError(d, rem)
  326. }
  327. err := elem.Validate()
  328. if err != nil {
  329. return err
  330. }
  331. }
  332. if len(rem) < 1 || rem[0] != 0x00 {
  333. return ErrMissingNull
  334. }
  335. return nil
  336. }
  337. func (Document) lengtherror(length, rem int) error {
  338. return DocumentValidationError(fmt.Sprintf("document length exceeds available bytes. length=%d remainingBytes=%d", length, rem))
  339. }