patch.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697
  1. package jsonpatch
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "strconv"
  7. "strings"
  8. )
  9. const (
  10. eRaw = iota
  11. eDoc
  12. eAry
  13. )
  14. var (
  15. // SupportNegativeIndices decides whether to support non-standard practice of
  16. // allowing negative indices to mean indices starting at the end of an array.
  17. // Default to true.
  18. SupportNegativeIndices bool = true
  19. // AccumulatedCopySizeLimit limits the total size increase in bytes caused by
  20. // "copy" operations in a patch.
  21. AccumulatedCopySizeLimit int64 = 0
  22. )
  23. type lazyNode struct {
  24. raw *json.RawMessage
  25. doc partialDoc
  26. ary partialArray
  27. which int
  28. }
  29. type operation map[string]*json.RawMessage
  30. // Patch is an ordered collection of operations.
  31. type Patch []operation
  32. type partialDoc map[string]*lazyNode
  33. type partialArray []*lazyNode
  34. type container interface {
  35. get(key string) (*lazyNode, error)
  36. set(key string, val *lazyNode) error
  37. add(key string, val *lazyNode) error
  38. remove(key string) error
  39. }
  40. func newLazyNode(raw *json.RawMessage) *lazyNode {
  41. return &lazyNode{raw: raw, doc: nil, ary: nil, which: eRaw}
  42. }
  43. func (n *lazyNode) MarshalJSON() ([]byte, error) {
  44. switch n.which {
  45. case eRaw:
  46. return json.Marshal(n.raw)
  47. case eDoc:
  48. return json.Marshal(n.doc)
  49. case eAry:
  50. return json.Marshal(n.ary)
  51. default:
  52. return nil, fmt.Errorf("Unknown type")
  53. }
  54. }
  55. func (n *lazyNode) UnmarshalJSON(data []byte) error {
  56. dest := make(json.RawMessage, len(data))
  57. copy(dest, data)
  58. n.raw = &dest
  59. n.which = eRaw
  60. return nil
  61. }
  62. func deepCopy(src *lazyNode) (*lazyNode, int, error) {
  63. if src == nil {
  64. return nil, 0, nil
  65. }
  66. a, err := src.MarshalJSON()
  67. if err != nil {
  68. return nil, 0, err
  69. }
  70. sz := len(a)
  71. ra := make(json.RawMessage, sz)
  72. copy(ra, a)
  73. return newLazyNode(&ra), sz, nil
  74. }
  75. func (n *lazyNode) intoDoc() (*partialDoc, error) {
  76. if n.which == eDoc {
  77. return &n.doc, nil
  78. }
  79. if n.raw == nil {
  80. return nil, fmt.Errorf("Unable to unmarshal nil pointer as partial document")
  81. }
  82. err := json.Unmarshal(*n.raw, &n.doc)
  83. if err != nil {
  84. return nil, err
  85. }
  86. n.which = eDoc
  87. return &n.doc, nil
  88. }
  89. func (n *lazyNode) intoAry() (*partialArray, error) {
  90. if n.which == eAry {
  91. return &n.ary, nil
  92. }
  93. if n.raw == nil {
  94. return nil, fmt.Errorf("Unable to unmarshal nil pointer as partial array")
  95. }
  96. err := json.Unmarshal(*n.raw, &n.ary)
  97. if err != nil {
  98. return nil, err
  99. }
  100. n.which = eAry
  101. return &n.ary, nil
  102. }
  103. func (n *lazyNode) compact() []byte {
  104. buf := &bytes.Buffer{}
  105. if n.raw == nil {
  106. return nil
  107. }
  108. err := json.Compact(buf, *n.raw)
  109. if err != nil {
  110. return *n.raw
  111. }
  112. return buf.Bytes()
  113. }
  114. func (n *lazyNode) tryDoc() bool {
  115. if n.raw == nil {
  116. return false
  117. }
  118. err := json.Unmarshal(*n.raw, &n.doc)
  119. if err != nil {
  120. return false
  121. }
  122. n.which = eDoc
  123. return true
  124. }
  125. func (n *lazyNode) tryAry() bool {
  126. if n.raw == nil {
  127. return false
  128. }
  129. err := json.Unmarshal(*n.raw, &n.ary)
  130. if err != nil {
  131. return false
  132. }
  133. n.which = eAry
  134. return true
  135. }
  136. func (n *lazyNode) equal(o *lazyNode) bool {
  137. if n.which == eRaw {
  138. if !n.tryDoc() && !n.tryAry() {
  139. if o.which != eRaw {
  140. return false
  141. }
  142. return bytes.Equal(n.compact(), o.compact())
  143. }
  144. }
  145. if n.which == eDoc {
  146. if o.which == eRaw {
  147. if !o.tryDoc() {
  148. return false
  149. }
  150. }
  151. if o.which != eDoc {
  152. return false
  153. }
  154. for k, v := range n.doc {
  155. ov, ok := o.doc[k]
  156. if !ok {
  157. return false
  158. }
  159. if v == nil && ov == nil {
  160. continue
  161. }
  162. if !v.equal(ov) {
  163. return false
  164. }
  165. }
  166. return true
  167. }
  168. if o.which != eAry && !o.tryAry() {
  169. return false
  170. }
  171. if len(n.ary) != len(o.ary) {
  172. return false
  173. }
  174. for idx, val := range n.ary {
  175. if !val.equal(o.ary[idx]) {
  176. return false
  177. }
  178. }
  179. return true
  180. }
  181. func (o operation) kind() string {
  182. if obj, ok := o["op"]; ok && obj != nil {
  183. var op string
  184. err := json.Unmarshal(*obj, &op)
  185. if err != nil {
  186. return "unknown"
  187. }
  188. return op
  189. }
  190. return "unknown"
  191. }
  192. func (o operation) path() string {
  193. if obj, ok := o["path"]; ok && obj != nil {
  194. var op string
  195. err := json.Unmarshal(*obj, &op)
  196. if err != nil {
  197. return "unknown"
  198. }
  199. return op
  200. }
  201. return "unknown"
  202. }
  203. func (o operation) from() string {
  204. if obj, ok := o["from"]; ok && obj != nil {
  205. var op string
  206. err := json.Unmarshal(*obj, &op)
  207. if err != nil {
  208. return "unknown"
  209. }
  210. return op
  211. }
  212. return "unknown"
  213. }
  214. func (o operation) value() *lazyNode {
  215. if obj, ok := o["value"]; ok {
  216. return newLazyNode(obj)
  217. }
  218. return nil
  219. }
  220. func isArray(buf []byte) bool {
  221. Loop:
  222. for _, c := range buf {
  223. switch c {
  224. case ' ':
  225. case '\n':
  226. case '\t':
  227. continue
  228. case '[':
  229. return true
  230. default:
  231. break Loop
  232. }
  233. }
  234. return false
  235. }
  236. func findObject(pd *container, path string) (container, string) {
  237. doc := *pd
  238. split := strings.Split(path, "/")
  239. if len(split) < 2 {
  240. return nil, ""
  241. }
  242. parts := split[1 : len(split)-1]
  243. key := split[len(split)-1]
  244. var err error
  245. for _, part := range parts {
  246. next, ok := doc.get(decodePatchKey(part))
  247. if next == nil || ok != nil {
  248. return nil, ""
  249. }
  250. if isArray(*next.raw) {
  251. doc, err = next.intoAry()
  252. if err != nil {
  253. return nil, ""
  254. }
  255. } else {
  256. doc, err = next.intoDoc()
  257. if err != nil {
  258. return nil, ""
  259. }
  260. }
  261. }
  262. return doc, decodePatchKey(key)
  263. }
  264. func (d *partialDoc) set(key string, val *lazyNode) error {
  265. (*d)[key] = val
  266. return nil
  267. }
  268. func (d *partialDoc) add(key string, val *lazyNode) error {
  269. (*d)[key] = val
  270. return nil
  271. }
  272. func (d *partialDoc) get(key string) (*lazyNode, error) {
  273. return (*d)[key], nil
  274. }
  275. func (d *partialDoc) remove(key string) error {
  276. _, ok := (*d)[key]
  277. if !ok {
  278. return fmt.Errorf("Unable to remove nonexistent key: %s", key)
  279. }
  280. delete(*d, key)
  281. return nil
  282. }
  283. // set should only be used to implement the "replace" operation, so "key" must
  284. // be an already existing index in "d".
  285. func (d *partialArray) set(key string, val *lazyNode) error {
  286. idx, err := strconv.Atoi(key)
  287. if err != nil {
  288. return err
  289. }
  290. (*d)[idx] = val
  291. return nil
  292. }
  293. func (d *partialArray) add(key string, val *lazyNode) error {
  294. if key == "-" {
  295. *d = append(*d, val)
  296. return nil
  297. }
  298. idx, err := strconv.Atoi(key)
  299. if err != nil {
  300. return err
  301. }
  302. sz := len(*d) + 1
  303. ary := make([]*lazyNode, sz)
  304. cur := *d
  305. if idx >= len(ary) {
  306. return fmt.Errorf("Unable to access invalid index: %d", idx)
  307. }
  308. if SupportNegativeIndices {
  309. if idx < -len(ary) {
  310. return fmt.Errorf("Unable to access invalid index: %d", idx)
  311. }
  312. if idx < 0 {
  313. idx += len(ary)
  314. }
  315. }
  316. copy(ary[0:idx], cur[0:idx])
  317. ary[idx] = val
  318. copy(ary[idx+1:], cur[idx:])
  319. *d = ary
  320. return nil
  321. }
  322. func (d *partialArray) get(key string) (*lazyNode, error) {
  323. idx, err := strconv.Atoi(key)
  324. if err != nil {
  325. return nil, err
  326. }
  327. if idx >= len(*d) {
  328. return nil, fmt.Errorf("Unable to access invalid index: %d", idx)
  329. }
  330. return (*d)[idx], nil
  331. }
  332. func (d *partialArray) remove(key string) error {
  333. idx, err := strconv.Atoi(key)
  334. if err != nil {
  335. return err
  336. }
  337. cur := *d
  338. if idx >= len(cur) {
  339. return fmt.Errorf("Unable to access invalid index: %d", idx)
  340. }
  341. if SupportNegativeIndices {
  342. if idx < -len(cur) {
  343. return fmt.Errorf("Unable to access invalid index: %d", idx)
  344. }
  345. if idx < 0 {
  346. idx += len(cur)
  347. }
  348. }
  349. ary := make([]*lazyNode, len(cur)-1)
  350. copy(ary[0:idx], cur[0:idx])
  351. copy(ary[idx:], cur[idx+1:])
  352. *d = ary
  353. return nil
  354. }
  355. func (p Patch) add(doc *container, op operation) error {
  356. path := op.path()
  357. con, key := findObject(doc, path)
  358. if con == nil {
  359. return fmt.Errorf("jsonpatch add operation does not apply: doc is missing path: \"%s\"", path)
  360. }
  361. return con.add(key, op.value())
  362. }
  363. func (p Patch) remove(doc *container, op operation) error {
  364. path := op.path()
  365. con, key := findObject(doc, path)
  366. if con == nil {
  367. return fmt.Errorf("jsonpatch remove operation does not apply: doc is missing path: \"%s\"", path)
  368. }
  369. return con.remove(key)
  370. }
  371. func (p Patch) replace(doc *container, op operation) error {
  372. path := op.path()
  373. con, key := findObject(doc, path)
  374. if con == nil {
  375. return fmt.Errorf("jsonpatch replace operation does not apply: doc is missing path: %s", path)
  376. }
  377. _, ok := con.get(key)
  378. if ok != nil {
  379. return fmt.Errorf("jsonpatch replace operation does not apply: doc is missing key: %s", path)
  380. }
  381. return con.set(key, op.value())
  382. }
  383. func (p Patch) move(doc *container, op operation) error {
  384. from := op.from()
  385. con, key := findObject(doc, from)
  386. if con == nil {
  387. return fmt.Errorf("jsonpatch move operation does not apply: doc is missing from path: %s", from)
  388. }
  389. val, err := con.get(key)
  390. if err != nil {
  391. return err
  392. }
  393. err = con.remove(key)
  394. if err != nil {
  395. return err
  396. }
  397. path := op.path()
  398. con, key = findObject(doc, path)
  399. if con == nil {
  400. return fmt.Errorf("jsonpatch move operation does not apply: doc is missing destination path: %s", path)
  401. }
  402. return con.add(key, val)
  403. }
  404. func (p Patch) test(doc *container, op operation) error {
  405. path := op.path()
  406. con, key := findObject(doc, path)
  407. if con == nil {
  408. return fmt.Errorf("jsonpatch test operation does not apply: is missing path: %s", path)
  409. }
  410. val, err := con.get(key)
  411. if err != nil {
  412. return err
  413. }
  414. if val == nil {
  415. if op.value().raw == nil {
  416. return nil
  417. }
  418. return fmt.Errorf("Testing value %s failed", path)
  419. } else if op.value() == nil {
  420. return fmt.Errorf("Testing value %s failed", path)
  421. }
  422. if val.equal(op.value()) {
  423. return nil
  424. }
  425. return fmt.Errorf("Testing value %s failed", path)
  426. }
  427. func (p Patch) copy(doc *container, op operation, accumulatedCopySize *int64) error {
  428. from := op.from()
  429. con, key := findObject(doc, from)
  430. if con == nil {
  431. return fmt.Errorf("jsonpatch copy operation does not apply: doc is missing from path: %s", from)
  432. }
  433. val, err := con.get(key)
  434. if err != nil {
  435. return err
  436. }
  437. path := op.path()
  438. con, key = findObject(doc, path)
  439. if con == nil {
  440. return fmt.Errorf("jsonpatch copy operation does not apply: doc is missing destination path: %s", path)
  441. }
  442. valCopy, sz, err := deepCopy(val)
  443. if err != nil {
  444. return err
  445. }
  446. (*accumulatedCopySize) += int64(sz)
  447. if AccumulatedCopySizeLimit > 0 && *accumulatedCopySize > AccumulatedCopySizeLimit {
  448. return NewAccumulatedCopySizeError(AccumulatedCopySizeLimit, *accumulatedCopySize)
  449. }
  450. return con.add(key, valCopy)
  451. }
  452. // Equal indicates if 2 JSON documents have the same structural equality.
  453. func Equal(a, b []byte) bool {
  454. ra := make(json.RawMessage, len(a))
  455. copy(ra, a)
  456. la := newLazyNode(&ra)
  457. rb := make(json.RawMessage, len(b))
  458. copy(rb, b)
  459. lb := newLazyNode(&rb)
  460. return la.equal(lb)
  461. }
  462. // DecodePatch decodes the passed JSON document as an RFC 6902 patch.
  463. func DecodePatch(buf []byte) (Patch, error) {
  464. var p Patch
  465. err := json.Unmarshal(buf, &p)
  466. if err != nil {
  467. return nil, err
  468. }
  469. return p, nil
  470. }
  471. // Apply mutates a JSON document according to the patch, and returns the new
  472. // document.
  473. func (p Patch) Apply(doc []byte) ([]byte, error) {
  474. return p.ApplyIndent(doc, "")
  475. }
  476. // ApplyIndent mutates a JSON document according to the patch, and returns the new
  477. // document indented.
  478. func (p Patch) ApplyIndent(doc []byte, indent string) ([]byte, error) {
  479. var pd container
  480. if doc[0] == '[' {
  481. pd = &partialArray{}
  482. } else {
  483. pd = &partialDoc{}
  484. }
  485. err := json.Unmarshal(doc, pd)
  486. if err != nil {
  487. return nil, err
  488. }
  489. err = nil
  490. var accumulatedCopySize int64
  491. for _, op := range p {
  492. switch op.kind() {
  493. case "add":
  494. err = p.add(&pd, op)
  495. case "remove":
  496. err = p.remove(&pd, op)
  497. case "replace":
  498. err = p.replace(&pd, op)
  499. case "move":
  500. err = p.move(&pd, op)
  501. case "test":
  502. err = p.test(&pd, op)
  503. case "copy":
  504. err = p.copy(&pd, op, &accumulatedCopySize)
  505. default:
  506. err = fmt.Errorf("Unexpected kind: %s", op.kind())
  507. }
  508. if err != nil {
  509. return nil, err
  510. }
  511. }
  512. if indent != "" {
  513. return json.MarshalIndent(pd, "", indent)
  514. }
  515. return json.Marshal(pd)
  516. }
  517. // From http://tools.ietf.org/html/rfc6901#section-4 :
  518. //
  519. // Evaluation of each reference token begins by decoding any escaped
  520. // character sequence. This is performed by first transforming any
  521. // occurrence of the sequence '~1' to '/', and then transforming any
  522. // occurrence of the sequence '~0' to '~'.
  523. var (
  524. rfc6901Decoder = strings.NewReplacer("~1", "/", "~0", "~")
  525. )
  526. func decodePatchKey(k string) string {
  527. return rfc6901Decoder.Replace(k)
  528. }