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 11KB

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