Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(212)

Side by Side Diff: service/datastore/serialize/serialize.go

Issue 1286093007: Fix key encoding to be null terminated (Closed) Base URL: https://github.com/luci/gae.git@add_iterator
Patch Set: Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | service/datastore/serialize/serialize_test.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package serialize 5 package serialize
6 6
7 import ( 7 import (
8 "bytes" 8 "bytes"
9 "errors" 9 "errors"
10 "fmt" 10 "fmt"
(...skipping 16 matching lines...) Expand all
27 var WritePropertyMapDeterministic = false 27 var WritePropertyMapDeterministic = false
28 28
29 // ReadPropertyMapReasonableLimit sets a limit on the number of rows and 29 // ReadPropertyMapReasonableLimit sets a limit on the number of rows and
30 // number of properties per row which can be read by ReadPropertyMap. The 30 // number of properties per row which can be read by ReadPropertyMap. The
31 // total number of Property objects readable by this method is this number 31 // total number of Property objects readable by this method is this number
32 // squared (e.g. Limit rows * Limit properties) 32 // squared (e.g. Limit rows * Limit properties)
33 const ReadPropertyMapReasonableLimit uint64 = 30000 33 const ReadPropertyMapReasonableLimit uint64 = 30000
34 34
35 // ReadKeyNumToksReasonableLimit is the maximum number of Key tokens that 35 // ReadKeyNumToksReasonableLimit is the maximum number of Key tokens that
36 // ReadKey is willing to read for a single key. 36 // ReadKey is willing to read for a single key.
37 const ReadKeyNumToksReasonableLimit uint64 = 50 37 const ReadKeyNumToksReasonableLimit = 50
38 38
39 // KeyContext controls whether the various Write and Read serializtion 39 // KeyContext controls whether the various Write and Read serializtion
40 // routines should encode the context of Keys (read: the appid and namespace). 40 // routines should encode the context of Keys (read: the appid and namespace).
41 // Frequently the appid and namespace of keys are known in advance and so there' s 41 // Frequently the appid and namespace of keys are known in advance and so there' s
42 // no reason to redundantly encode them. 42 // no reason to redundantly encode them.
43 type KeyContext bool 43 type KeyContext bool
44 44
45 // With- and WithoutContext indicate if the serialization method should include 45 // With- and WithoutContext indicate if the serialization method should include
46 // context for Keys. See KeyContext for more information. 46 // context for Keys. See KeyContext for more information.
47 const ( 47 const (
48 WithContext KeyContext = true 48 WithContext KeyContext = true
49 WithoutContext = false 49 WithoutContext = false
50 ) 50 )
51 51
52 // WriteKey encodes a key to the buffer. If context is WithContext, then this 52 // WriteKey encodes a key to the buffer. If context is WithContext, then this
53 // encoded value will include the appid and namespace of the key. 53 // encoded value will include the appid and namespace of the key.
54 func WriteKey(buf Buffer, context KeyContext, k ds.Key) (err error) { 54 func WriteKey(buf Buffer, context KeyContext, k ds.Key) (err error) {
55 » // [appid ++ namespace]? ++ #tokens ++ tokens* 55 » // [appid ++ namespace]? ++ [1 ++ token]* ++ NULL
56 defer recoverTo(&err) 56 defer recoverTo(&err)
57 appid, namespace, toks := dskey.Split(k) 57 appid, namespace, toks := dskey.Split(k)
58 if context == WithContext { 58 if context == WithContext {
59 panicIf(buf.WriteByte(1)) 59 panicIf(buf.WriteByte(1))
60 _, e := cmpbin.WriteString(buf, appid) 60 _, e := cmpbin.WriteString(buf, appid)
61 panicIf(e) 61 panicIf(e)
62 _, e = cmpbin.WriteString(buf, namespace) 62 _, e = cmpbin.WriteString(buf, namespace)
63 panicIf(e) 63 panicIf(e)
64 } else { 64 } else {
65 panicIf(buf.WriteByte(0)) 65 panicIf(buf.WriteByte(0))
66 } 66 }
67 _, e := cmpbin.WriteUint(buf, uint64(len(toks)))
68 panicIf(e)
69 for _, tok := range toks { 67 for _, tok := range toks {
68 panicIf(buf.WriteByte(1))
70 panicIf(WriteKeyTok(buf, tok)) 69 panicIf(WriteKeyTok(buf, tok))
71 } 70 }
72 » return nil 71 » return buf.WriteByte(0)
73 } 72 }
74 73
75 // ReadKey deserializes a key from the buffer. The value of context must match 74 // ReadKey deserializes a key from the buffer. The value of context must match
76 // the value of context that was passed to WriteKey when the key was encoded. 75 // the value of context that was passed to WriteKey when the key was encoded.
77 // If context == WithoutContext, then the appid and namespace parameters are 76 // If context == WithoutContext, then the appid and namespace parameters are
78 // used in the decoded Key. Otherwise they're ignored. 77 // used in the decoded Key. Otherwise they're ignored.
79 func ReadKey(buf Buffer, context KeyContext, appid, namespace string) (ret ds.Ke y, err error) { 78 func ReadKey(buf Buffer, context KeyContext, appid, namespace string) (ret ds.Ke y, err error) {
80 defer recoverTo(&err) 79 defer recoverTo(&err)
81 actualCtx, e := buf.ReadByte() 80 actualCtx, e := buf.ReadByte()
82 panicIf(e) 81 panicIf(e)
83 82
84 actualAid, actualNS := "", "" 83 actualAid, actualNS := "", ""
85 if actualCtx == 1 { 84 if actualCtx == 1 {
86 actualAid, _, e = cmpbin.ReadString(buf) 85 actualAid, _, e = cmpbin.ReadString(buf)
87 panicIf(e) 86 panicIf(e)
88 actualNS, _, e = cmpbin.ReadString(buf) 87 actualNS, _, e = cmpbin.ReadString(buf)
89 panicIf(e) 88 panicIf(e)
90 } else if actualCtx != 0 { 89 } else if actualCtx != 0 {
91 err = fmt.Errorf("helper: expected actualCtx to be 0 or 1, got % d", actualCtx) 90 err = fmt.Errorf("helper: expected actualCtx to be 0 or 1, got % d", actualCtx)
92 return 91 return
93 } 92 }
94 93
95 if context == WithoutContext { 94 if context == WithoutContext {
96 // overrwrite with the supplied ones 95 // overrwrite with the supplied ones
97 actualAid = appid 96 actualAid = appid
98 actualNS = namespace 97 actualNS = namespace
99 } 98 }
100 99
101 » numToks, _, e := cmpbin.ReadUint(buf) 100 » toks := []ds.KeyTok{}
102 » panicIf(e) 101 » for {
103 » if numToks > ReadKeyNumToksReasonableLimit { 102 » » ctrlByte, e := buf.ReadByte()
104 » » err = fmt.Errorf("helper: tried to decode huge key of length %d" , numToks) 103 » » panicIf(e)
105 » » return 104 » » if ctrlByte == 0 {
106 » } 105 » » » break
106 » » }
107 » » if len(toks)+1 >= ReadKeyNumToksReasonableLimit {
dnj (Google) 2015/08/15 19:06:55 nit: Why greater-than-or-equal and not greater-tha
108 » » » err = fmt.Errorf(
109 » » » » "helper: tried to decode huge key with >= %d tok ens",
110 » » » » ReadKeyNumToksReasonableLimit)
111 » » » return
112 » » }
107 113
108 » toks := make([]ds.KeyTok, numToks) 114 » » tok, e := ReadKeyTok(buf)
109 » for i := uint64(0); i < numToks; i++ {
110 » » toks[i], e = ReadKeyTok(buf)
111 panicIf(e) 115 panicIf(e)
116
117 toks = append(toks, tok)
112 } 118 }
113 119
114 return dskey.NewToks(actualAid, actualNS, toks), nil 120 return dskey.NewToks(actualAid, actualNS, toks), nil
115 } 121 }
116 122
117 // WriteKeyTok writes a KeyTok to the buffer. You usually want WriteKey 123 // WriteKeyTok writes a KeyTok to the buffer. You usually want WriteKey
118 // instead of this. 124 // instead of this.
119 func WriteKeyTok(buf Buffer, tok ds.KeyTok) (err error) { 125 func WriteKeyTok(buf Buffer, tok ds.KeyTok) (err error) {
120 // tok.kind ++ typ ++ [tok.stringID || tok.intID] 126 // tok.kind ++ typ ++ [tok.stringID || tok.intID]
121 defer recoverTo(&err) 127 defer recoverTo(&err)
(...skipping 429 matching lines...) Expand 10 before | Expand all | Expand 10 after
551 } 557 }
552 } 558 }
553 559
554 func recoverTo(err *error) { 560 func recoverTo(err *error) {
555 if r := recover(); r != nil { 561 if r := recover(); r != nil {
556 if rerr := r.(parseError); rerr != nil { 562 if rerr := r.(parseError); rerr != nil {
557 *err = error(rerr) 563 *err = error(rerr)
558 } 564 }
559 } 565 }
560 } 566 }
OLDNEW
« no previous file with comments | « no previous file | service/datastore/serialize/serialize_test.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698