OLD | NEW |
| (Empty) |
1 // Copyright 2011 Google Inc. | |
2 // | |
3 // Licensed under the Apache License, Version 2.0 (the "License"); | |
4 // you may not use this file except in compliance with the License. | |
5 // You may obtain a copy of the License at | |
6 // | |
7 // http://www.apache.org/licenses/LICENSE-2.0 | |
8 // | |
9 // Unless required by applicable law or agreed to in writing, software | |
10 // distributed under the License is distributed on an "AS IS" BASIS, | |
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
12 // See the License for the specific language governing permissions and | |
13 // limitations under the License. | |
14 // ======================================================================== | |
15 | |
16 // Utility class to manage a set of experiment labels. Experiment labels | |
17 // are a set of key/value pairs used to track an install's "membership" in | |
18 // A/B experiment groups issued by the Omaha server. Keys are strings with | |
19 // a limited character set (Perl \w, plus a few characters), while values | |
20 // consist of a string and an expiration date. Label sets are stored per-app | |
21 // and transmitted to the server as part of requests (pings / update checks), | |
22 // and a delta is potentially returned from the server with each response. | |
23 // | |
24 // Experiment labels are serialized with key/value separated by an equals, and | |
25 // value/expiration by a pipe symbol; the expiration is represented in RFC822 | |
26 // format. For example: "test_key=test_value|Fri, 14 Aug 2015 16:13:03 GMT". | |
27 // If an app participates in multiple experiments simultaneously, labels are | |
28 // concatenated with semicolon delimiters. | |
29 | |
30 #ifndef OMAHA_COMMON_EXPERIMENT_LABELS_H_ | |
31 #define OMAHA_COMMON_EXPERIMENT_LABELS_H_ | |
32 | |
33 #include <atlstr.h> | |
34 | |
35 #include <map> | |
36 #include <utility> | |
37 | |
38 #include "base/basictypes.h" | |
39 #include "omaha/base/time.h" | |
40 | |
41 namespace omaha { | |
42 | |
43 class ExperimentLabels { | |
44 public: | |
45 ExperimentLabels(); | |
46 ~ExperimentLabels(); | |
47 | |
48 // Returns the number of labels in the store. | |
49 int NumLabels() const; | |
50 | |
51 // Returns true if a label with this key exists in the store. | |
52 bool ContainsKey(const CString& key) const; | |
53 | |
54 // Returns the contents of the Nth label in the experiment set. Output | |
55 // parameters are allowed to be NULL. If index is out of range, asserts | |
56 // on a debug build. | |
57 // | |
58 // NOTE: This method is O(n), and indexes are not stable with respect to | |
59 // insertion order; it should not be called from any hot path. Unit tests | |
60 // and diagnostic tools should use this to enumerate keys. | |
61 void GetLabelByIndex(int index, | |
62 CString* key, | |
63 CString* value, | |
64 time64* expiration) const; | |
65 | |
66 // If a label with this key exists, returns true and writes the value and | |
67 // expiration to the output parameters. Output parameters are allowed | |
68 // to be NULL. If no such key exists, returns false and leaves the outputs | |
69 // unchanged. | |
70 bool FindLabelByKey(const CString& key, | |
71 CString* value, | |
72 time64* expiration) const; | |
73 | |
74 // Attempts to set a label in the store, either adding a new one or updating | |
75 // the value/expiration of an existing one. Returns true on success. | |
76 bool SetLabel(const CString& key, const CString& value, time64 expiration); | |
77 | |
78 // Clears a label in the store. Returns true if a label with that key exists | |
79 // (it is removed); returns false if no label with that key exists. | |
80 bool ClearLabel(const CString& key); | |
81 | |
82 // Removes any labels from the store whose expiration dates have passed. | |
83 void ExpireLabels(); | |
84 | |
85 // Removes all labels from the store. | |
86 void ClearAllLabels(); | |
87 | |
88 // Concatenates and emits all labels in the store in an XML-friendly format. | |
89 CString Serialize() const; | |
90 | |
91 // Replaces the current contents of the store with new labels from an | |
92 // XML-friendly string. On success, returns true; the store reflects the | |
93 // input exactly, with all prior contents are lost. On failure, returns | |
94 // false and the store's contents are unchanged. | |
95 bool Deserialize(const CString& label_list); | |
96 | |
97 // Applies the contents of a label list as a delta against the current | |
98 // contents of the store. On success, returns true, and: | |
99 // * Any expired labels in the list are deleted from the store. | |
100 // * Unexpired labels in the list will be added to the store. If any keys | |
101 // already exist in the store, they are overwritten with the input. | |
102 // * Labels that are in the store but not in the input are left unmodified. | |
103 // On failure, returns false, and the store's contents are unchanged. | |
104 // This function's behavior is not modified by SetPreserveExpiredLabels()! | |
105 bool DeserializeAndApplyDelta(const CString& label_list); | |
106 | |
107 // Modifies the store's handling of labels with expiration dates in the past. | |
108 // By default, SetLabel() will fail to add expired labels, Deserialize() will | |
109 // silently discard them, and Serialize() will not emit them. Following a | |
110 // call to SetPreserveExpiredLabels(true), these functions will accept and/or | |
111 // include expired labels. | |
112 void SetPreserveExpiredLabels(bool preserve); | |
113 | |
114 // Serializes a set of experiment labels to application data in the Registry. | |
115 HRESULT WriteToRegistry(bool is_machine, const CString& app_id); | |
116 | |
117 // Deserializes a set of experiment labels from the Registry. | |
118 HRESULT ReadFromRegistry(bool is_machine, const CString& app_id); | |
119 | |
120 // Returns true if the supplied string is a valid experiment label set. | |
121 static bool IsStringValidLabelSet(const CString& label_list); | |
122 | |
123 private: | |
124 typedef std::map<CString, std::pair<CString, time64> > LabelMap; | |
125 | |
126 // Returns true if all characters are in the range [a-zA-Z0-9_\-+,: ]. | |
127 // (Perl \w, plus the punctuation necessary for RFC822 dates.) | |
128 static bool IsLabelContentValid(const CString& str); | |
129 | |
130 // Given an input string of the form "key=value|rfc822_date", converts it | |
131 // into separate key, value, and integer expiration dates. | |
132 static bool SplitCombinedLabel(const CString& combined, | |
133 CString* key, | |
134 CString* value, | |
135 time64* expiration); | |
136 | |
137 // Splits an input string and applies it against an existing internal map. | |
138 static bool DoDeserialize(LabelMap* map, | |
139 const CString& label_list, | |
140 bool accept_expired); | |
141 | |
142 LabelMap labels_; | |
143 bool preserve_expired_; | |
144 | |
145 DISALLOW_COPY_AND_ASSIGN(ExperimentLabels); | |
146 }; | |
147 | |
148 } // namespace omaha | |
149 | |
150 #endif // OMAHA_COMMON_EXPERIMENT_LABELS_H_ | |
151 | |
OLD | NEW |