| Index: common/experiment_labels.cc
|
| diff --git a/common/experiment_labels.cc b/common/experiment_labels.cc
|
| deleted file mode 100644
|
| index ecf270e12e1a7dabd5f370c2b8f470436a05729d..0000000000000000000000000000000000000000
|
| --- a/common/experiment_labels.cc
|
| +++ /dev/null
|
| @@ -1,286 +0,0 @@
|
| -// 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.
|
| -
|
| -#include "omaha/common/experiment_labels.h"
|
| -
|
| -#include "omaha/base/debug.h"
|
| -#include "omaha/base/safe_format.h"
|
| -#include "omaha/common/app_registry_utils.h"
|
| -
|
| -namespace omaha {
|
| -
|
| -ExperimentLabels::ExperimentLabels() : labels_(), preserve_expired_(false) {}
|
| -
|
| -ExperimentLabels::~ExperimentLabels() {}
|
| -
|
| -int ExperimentLabels::NumLabels() const {
|
| - return labels_.size();
|
| -}
|
| -
|
| -bool ExperimentLabels::ContainsKey(const CString& key) const {
|
| - ASSERT1(!key.IsEmpty());
|
| - return labels_.find(key) != labels_.end();
|
| -}
|
| -
|
| -void ExperimentLabels::GetLabelByIndex(int index, CString* key, CString* value,
|
| - time64* expiration) const {
|
| - ASSERT1(index >= 0);
|
| - ASSERT1(static_cast<LabelMap::size_type>(index) < labels_.size());
|
| -
|
| - LabelMap::const_iterator cit = labels_.begin();
|
| - std::advance(cit, static_cast<LabelMap::size_type>(index));
|
| - if (key) {
|
| - *key = cit->first;
|
| - }
|
| - if (value) {
|
| - *value = cit->second.first;
|
| - }
|
| - if (expiration) {
|
| - *expiration = cit->second.second;
|
| - }
|
| -}
|
| -
|
| -bool ExperimentLabels::FindLabelByKey(const CString& key, CString* value,
|
| - time64* expiration) const {
|
| - ASSERT1(!key.IsEmpty());
|
| - LabelMap::const_iterator cit = labels_.find(key);
|
| - if (labels_.end() == cit) {
|
| - return false;
|
| - }
|
| -
|
| - if (value) {
|
| - *value = cit->second.first;
|
| - }
|
| - if (expiration) {
|
| - *expiration = cit->second.second;
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -bool ExperimentLabels::SetLabel(const CString& key, const CString& value,
|
| - time64 expiration) {
|
| - if (!IsLabelContentValid(key) || !IsLabelContentValid(value)) {
|
| - return false;
|
| - }
|
| - if (expiration < GetCurrent100NSTime() && !preserve_expired_) {
|
| - return false;
|
| - }
|
| - labels_[key] = std::make_pair(value, expiration);
|
| - return true;
|
| -}
|
| -
|
| -bool ExperimentLabels::ClearLabel(const CString& key) {
|
| - LabelMap::iterator it = labels_.find(key);
|
| - if (labels_.end() == it) {
|
| - return false;
|
| - }
|
| - labels_.erase(it);
|
| - return true;
|
| -}
|
| -
|
| -void ExperimentLabels::ExpireLabels() {
|
| - time64 current_time = GetCurrent100NSTime();
|
| - for (LabelMap::iterator it = labels_.begin(); it != labels_.end(); ++it) {
|
| - if (it->second.second < current_time) {
|
| - it = labels_.erase(it);
|
| - if (it == labels_.end()) {
|
| - break;
|
| - }
|
| - }
|
| - }
|
| -}
|
| -
|
| -void ExperimentLabels::ClearAllLabels() {
|
| - labels_.clear();
|
| -}
|
| -
|
| -CString ExperimentLabels::Serialize() const {
|
| - CString serialized;
|
| - time64 current_time = GetCurrent100NSTime();
|
| - for (LabelMap::const_iterator cit = labels_.begin();
|
| - cit != labels_.end();
|
| - ++cit) {
|
| - if (preserve_expired_ || cit->second.second >= current_time) {
|
| - if (!serialized.IsEmpty()) {
|
| - serialized.Append(L";");
|
| - }
|
| - FILETIME ft = {};
|
| - Time64ToFileTime(cit->second.second, &ft);
|
| - SafeCStringAppendFormat(&serialized, L"%s=%s|%s",
|
| - cit->first,
|
| - cit->second.first,
|
| - ConvertTimeToGMTString(&ft));
|
| - }
|
| - }
|
| - return serialized;
|
| -}
|
| -
|
| -bool ExperimentLabels::Deserialize(const CString& label_list) {
|
| - LabelMap new_labels;
|
| - if (DoDeserialize(&new_labels, label_list, preserve_expired_)) {
|
| - std::swap(labels_, new_labels);
|
| - return true;
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -bool ExperimentLabels::DeserializeAndApplyDelta(const CString& label_list) {
|
| - LabelMap merged_labels = labels_;
|
| - if (DoDeserialize(&merged_labels, label_list, false)) {
|
| - std::swap(labels_, merged_labels);
|
| - return true;
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -void ExperimentLabels::SetPreserveExpiredLabels(bool preserve) {
|
| - preserve_expired_ = preserve;
|
| -}
|
| -
|
| -HRESULT ExperimentLabels::WriteToRegistry(bool is_machine,
|
| - const CString& app_id) {
|
| - return app_registry_utils::SetExperimentLabels(is_machine, app_id,
|
| - Serialize());
|
| -}
|
| -
|
| -HRESULT ExperimentLabels::ReadFromRegistry(bool is_machine,
|
| - const CString& app_id) {
|
| - CString label_list;
|
| - HRESULT hr = app_registry_utils::GetExperimentLabels(is_machine, app_id,
|
| - &label_list);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| - return Deserialize(label_list) ? S_OK : E_FAIL;
|
| -}
|
| -
|
| -bool ExperimentLabels::IsStringValidLabelSet(const CString& label_list) {
|
| - ExperimentLabels labels;
|
| - return labels.Deserialize(label_list);
|
| -}
|
| -
|
| -bool ExperimentLabels::IsLabelContentValid(const CString& str) {
|
| - if (str.IsEmpty()) {
|
| - return false;
|
| - }
|
| - for (int i = 0; i < str.GetLength(); ++i) {
|
| - wchar_t ch = str[i];
|
| - if (!((ch >= L'+' && ch <= L'-') ||
|
| - (ch >= L'0' && ch <= L':') ||
|
| - (ch >= L'A' && ch <= L'Z') ||
|
| - (ch >= L'a' && ch <= L'z') ||
|
| - (ch == L'_') || (ch == L' '))) {
|
| - return false;
|
| - }
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -bool ExperimentLabels::SplitCombinedLabel(const CString& combined, CString* key,
|
| - CString* value, time64* expiration) {
|
| - ASSERT1(!combined.IsEmpty());
|
| - ASSERT1(key);
|
| - ASSERT1(value);
|
| - ASSERT1(expiration);
|
| -
|
| - int value_offset = combined.Find(L'=');
|
| - if (value_offset <= 0 || value_offset == combined.GetLength()) {
|
| - return false;
|
| - }
|
| - *key = combined.Left(value_offset);
|
| - if (!IsLabelContentValid(*key)) {
|
| - return false;
|
| - }
|
| - ++value_offset;
|
| -
|
| - int expiration_offset = combined.Find(L'|', value_offset);
|
| - if (expiration_offset <= value_offset ||
|
| - expiration_offset == combined.GetLength()) {
|
| - return false;
|
| - }
|
| - *value = combined.Mid(value_offset, expiration_offset - value_offset);
|
| - if (!IsLabelContentValid(*value)) {
|
| - return false;
|
| - }
|
| - ++expiration_offset;
|
| -
|
| - CString expiration_string = combined.Mid(expiration_offset);
|
| - if (!IsLabelContentValid(expiration_string)) {
|
| - return false;
|
| - }
|
| - SYSTEMTIME system_time = {};
|
| - if (!RFC822DateToSystemTime(expiration_string, &system_time, false)) {
|
| - return false;
|
| - }
|
| - *expiration = SystemTimeToTime64(&system_time);
|
| -
|
| - return true;
|
| -}
|
| -
|
| -bool ExperimentLabels::DoDeserialize(LabelMap* map, const CString& label_list,
|
| - bool accept_expired) {
|
| - ASSERT1(map);
|
| -
|
| - if (label_list.IsEmpty()) {
|
| - return true;
|
| - }
|
| -
|
| - time64 current_time = GetCurrent100NSTime();
|
| -
|
| - for (int offset = 0;;) {
|
| - CString combined_label = label_list.Tokenize(L";", offset);
|
| - if (combined_label.IsEmpty()) {
|
| - if (offset < 0) {
|
| - break; // Natural end-of-string reached.
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - CString key;
|
| - CString value;
|
| - time64 expiration = 0;
|
| - if (!SplitCombinedLabel(combined_label, &key, &value, &expiration)) {
|
| - return false;
|
| - }
|
| -
|
| - // If the label is well-formatted but expired, we accept the input, but
|
| - // do not add it to the map and do not emit an error. If there is already
|
| - // a label in the map with that key, delete it.
|
| - if (accept_expired || expiration > current_time) {
|
| - (*map)[key] = std::make_pair(value, expiration);
|
| - } else {
|
| - map->erase(key);
|
| - }
|
| - }
|
| -
|
| - return true;
|
| -}
|
| -
|
| -} // namespace omaha
|
| -
|
|
|