Chromium Code Reviews| 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 |