| // Copyright 2011 Google Inc. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // ======================================================================== |
| |
| // Utility class to manage a set of experiment labels. Experiment labels |
| // are a set of key/value pairs used to track an install's "membership" in |
| // A/B experiment groups issued by the Omaha server. Keys are strings with |
| // a limited character set (Perl \w, plus a few characters), while values |
| // consist of a string and an expiration date. Label sets are stored per-app |
| // and transmitted to the server as part of requests (pings / update checks), |
| // and a delta is potentially returned from the server with each response. |
| // |
| // Experiment labels are serialized with key/value separated by an equals, and |
| // value/expiration by a pipe symbol; the expiration is represented in RFC822 |
| // format. For example: "test_key=test_value|Fri, 14 Aug 2015 16:13:03 GMT". |
| // If an app participates in multiple experiments simultaneously, labels are |
| // concatenated with semicolon delimiters. |
| |
| #ifndef OMAHA_COMMON_EXPERIMENT_LABELS_H_ |
| #define OMAHA_COMMON_EXPERIMENT_LABELS_H_ |
| |
| #include <atlstr.h> |
| |
| #include <map> |
| #include <utility> |
| |
| #include "base/basictypes.h" |
| #include "omaha/base/time.h" |
| |
| namespace omaha { |
| |
| class ExperimentLabels { |
| public: |
| ExperimentLabels(); |
| ~ExperimentLabels(); |
| |
| // Returns the number of labels in the store. |
| int NumLabels() const; |
| |
| // Returns true if a label with this key exists in the store. |
| bool ContainsKey(const CString& key) const; |
| |
| // Returns the contents of the Nth label in the experiment set. Output |
| // parameters are allowed to be NULL. If index is out of range, asserts |
| // on a debug build. |
| // |
| // NOTE: This method is O(n), and indexes are not stable with respect to |
| // insertion order; it should not be called from any hot path. Unit tests |
| // and diagnostic tools should use this to enumerate keys. |
| void GetLabelByIndex(int index, |
| CString* key, |
| CString* value, |
| time64* expiration) const; |
| |
| // If a label with this key exists, returns true and writes the value and |
| // expiration to the output parameters. Output parameters are allowed |
| // to be NULL. If no such key exists, returns false and leaves the outputs |
| // unchanged. |
| bool FindLabelByKey(const CString& key, |
| CString* value, |
| time64* expiration) const; |
| |
| // Attempts to set a label in the store, either adding a new one or updating |
| // the value/expiration of an existing one. Returns true on success. |
| bool SetLabel(const CString& key, const CString& value, time64 expiration); |
| |
| // Clears a label in the store. Returns true if a label with that key exists |
| // (it is removed); returns false if no label with that key exists. |
| bool ClearLabel(const CString& key); |
| |
| // Removes any labels from the store whose expiration dates have passed. |
| void ExpireLabels(); |
| |
| // Removes all labels from the store. |
| void ClearAllLabels(); |
| |
| // Concatenates and emits all labels in the store in an XML-friendly format. |
| CString Serialize() const; |
| |
| // Replaces the current contents of the store with new labels from an |
| // XML-friendly string. On success, returns true; the store reflects the |
| // input exactly, with all prior contents are lost. On failure, returns |
| // false and the store's contents are unchanged. |
| bool Deserialize(const CString& label_list); |
| |
| // Applies the contents of a label list as a delta against the current |
| // contents of the store. On success, returns true, and: |
| // * Any expired labels in the list are deleted from the store. |
| // * Unexpired labels in the list will be added to the store. If any keys |
| // already exist in the store, they are overwritten with the input. |
| // * Labels that are in the store but not in the input are left unmodified. |
| // On failure, returns false, and the store's contents are unchanged. |
| // This function's behavior is not modified by SetPreserveExpiredLabels()! |
| bool DeserializeAndApplyDelta(const CString& label_list); |
| |
| // Modifies the store's handling of labels with expiration dates in the past. |
| // By default, SetLabel() will fail to add expired labels, Deserialize() will |
| // silently discard them, and Serialize() will not emit them. Following a |
| // call to SetPreserveExpiredLabels(true), these functions will accept and/or |
| // include expired labels. |
| void SetPreserveExpiredLabels(bool preserve); |
| |
| // Serializes a set of experiment labels to application data in the Registry. |
| HRESULT WriteToRegistry(bool is_machine, const CString& app_id); |
| |
| // Deserializes a set of experiment labels from the Registry. |
| HRESULT ReadFromRegistry(bool is_machine, const CString& app_id); |
| |
| // Returns true if the supplied string is a valid experiment label set. |
| static bool IsStringValidLabelSet(const CString& label_list); |
| |
| private: |
| typedef std::map<CString, std::pair<CString, time64> > LabelMap; |
| |
| // Returns true if all characters are in the range [a-zA-Z0-9_\-+,: ]. |
| // (Perl \w, plus the punctuation necessary for RFC822 dates.) |
| static bool IsLabelContentValid(const CString& str); |
| |
| // Given an input string of the form "key=value|rfc822_date", converts it |
| // into separate key, value, and integer expiration dates. |
| static bool SplitCombinedLabel(const CString& combined, |
| CString* key, |
| CString* value, |
| time64* expiration); |
| |
| // Splits an input string and applies it against an existing internal map. |
| static bool DoDeserialize(LabelMap* map, |
| const CString& label_list, |
| bool accept_expired); |
| |
| LabelMap labels_; |
| bool preserve_expired_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ExperimentLabels); |
| }; |
| |
| } // namespace omaha |
| |
| #endif // OMAHA_COMMON_EXPERIMENT_LABELS_H_ |
| |