OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 } |
OLD | NEW |