OLD | NEW |
(Empty) | |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "chrome/installer/util/experiment_labels.h" |
| 6 |
| 7 #include <vector> |
| 8 |
| 9 #include "base/strings/string_split.h" |
| 10 #include "base/strings/stringprintf.h" |
| 11 |
| 12 namespace installer { |
| 13 |
| 14 namespace { |
| 15 |
| 16 constexpr base::StringPiece16::value_type kNameValueSeparator = L'='; |
| 17 constexpr base::StringPiece16::value_type kValueExpirationSeparator = L'|'; |
| 18 constexpr base::StringPiece16::value_type kLabelSeparator = L';'; |
| 19 |
| 20 // Returns a vector of string pieces, one for each "name=value|expiration" |
| 21 // group in |value|. |
| 22 std::vector<base::StringPiece16> Parse(base::StringPiece16 value) { |
| 23 static constexpr base::char16 kLabelSeparatorString[] = {kLabelSeparator, |
| 24 L'\0'}; |
| 25 return base::SplitStringPiece(value, kLabelSeparatorString, |
| 26 base::TRIM_WHITESPACE, |
| 27 base::SPLIT_WANT_NONEMPTY); |
| 28 } |
| 29 |
| 30 // Returns an abbreviated day name for a zero-based |day_of_week|. |
| 31 const wchar_t* AbbreviatedDayOfWeek(int day_of_week) { |
| 32 // Matches the abbreviated day names from the ICU "en" locale. |
| 33 static constexpr const wchar_t* kDays[] = {L"Sun", L"Mon", L"Tue", L"Wed", |
| 34 L"Thu", L"Fri", L"Sat"}; |
| 35 return kDays[day_of_week]; |
| 36 } |
| 37 |
| 38 // Returns an abbreviated month name for a one-based |month|. |
| 39 const wchar_t* AbbreviatedMonth(int month) { |
| 40 // Matches the abbreviated month names from the ICU "en" locale. |
| 41 static constexpr const wchar_t* kMonths[] = {L"Jan", L"Feb", L"Mar", L"Apr", |
| 42 L"May", L"Jun", L"Jul", L"Aug", |
| 43 L"Sep", L"Oct", L"Nov", L"Dec"}; |
| 44 return kMonths[month - 1]; |
| 45 } |
| 46 |
| 47 // Returns a formatted string given a date that is compatible with Omaha (see |
| 48 // https://github.com/google/omaha/blob/master/omaha/base/time.cc#L132). |
| 49 base::string16 FormatDate(base::Time date) { |
| 50 base::Time::Exploded exploded_time; |
| 51 date.UTCExplode(&exploded_time); |
| 52 |
| 53 // "Fri, 14 Aug 2015 16:13:03 GMT" |
| 54 return base::StringPrintf(L"%ls, %02d %ls %04d %02d:%02d:%02d GMT", |
| 55 AbbreviatedDayOfWeek(exploded_time.day_of_week), |
| 56 exploded_time.day_of_month, |
| 57 AbbreviatedMonth(exploded_time.month), |
| 58 exploded_time.year, exploded_time.hour, |
| 59 exploded_time.minute, exploded_time.second); |
| 60 } |
| 61 |
| 62 // Appends "label_name=label_value|expiration" to |label|. |
| 63 void AppendLabel(base::StringPiece16 label_name, |
| 64 base::StringPiece16 label_value, |
| 65 base::Time expiration, |
| 66 base::string16* label) { |
| 67 // 29 characters for the expiration date plus the two separators makes 31. |
| 68 label->reserve(label->size() + label_name.size() + label_value.size() + 31); |
| 69 label_name.AppendToString(label); |
| 70 label->push_back(kNameValueSeparator); |
| 71 label_value.AppendToString(label); |
| 72 label->push_back(kValueExpirationSeparator); |
| 73 label->append(FormatDate(expiration)); |
| 74 } |
| 75 |
| 76 } // namespace |
| 77 |
| 78 ExperimentLabels::ExperimentLabels(const base::string16& value) |
| 79 : value_(value) {} |
| 80 |
| 81 base::StringPiece16 ExperimentLabels::GetValueForLabel( |
| 82 base::StringPiece16 label_name) const { |
| 83 DCHECK(!label_name.empty()); |
| 84 |
| 85 return FindLabel(label_name).second; |
| 86 } |
| 87 |
| 88 void ExperimentLabels::SetValueForLabel(base::StringPiece16 label_name, |
| 89 base::StringPiece16 label_value, |
| 90 base::TimeDelta lifetime) { |
| 91 DCHECK(!label_name.empty()); |
| 92 DCHECK(!label_value.empty()); |
| 93 DCHECK(!lifetime.is_zero()); |
| 94 |
| 95 SetValueForLabel(label_name, label_value, base::Time::Now() + lifetime); |
| 96 } |
| 97 |
| 98 void ExperimentLabels::SetValueForLabel(base::StringPiece16 label_name, |
| 99 base::StringPiece16 label_value, |
| 100 base::Time expiration) { |
| 101 DCHECK(!label_name.empty()); |
| 102 DCHECK(!label_value.empty()); |
| 103 |
| 104 LabelAndValue label_and_value = FindLabel(label_name); |
| 105 if (label_and_value.first.empty()) { |
| 106 // This label doesn't already exist -- append it to the raw value. |
| 107 if (!value_.empty()) |
| 108 value_.push_back(kLabelSeparator); |
| 109 AppendLabel(label_name, label_value, expiration, &value_); |
| 110 } else { |
| 111 // Replace the existing value and expiration. |
| 112 // Get the stuff before the old label. |
| 113 base::string16 new_label(value_, 0, |
| 114 label_and_value.first.data() - value_.data()); |
| 115 // Append the new label. |
| 116 AppendLabel(label_name, label_value, expiration, &new_label); |
| 117 // Find the stuff after the old label and append it. |
| 118 size_t next_separator = value_.find( |
| 119 kLabelSeparator, |
| 120 (label_and_value.second.data() + label_and_value.second.size()) - |
| 121 value_.data()); |
| 122 if (next_separator != base::string16::npos) |
| 123 new_label.append(value_, next_separator, base::string16::npos); |
| 124 // Presto. |
| 125 new_label.swap(value_); |
| 126 } |
| 127 } |
| 128 |
| 129 ExperimentLabels::LabelAndValue ExperimentLabels::FindLabel( |
| 130 base::StringPiece16 label_name) const { |
| 131 DCHECK(!label_name.empty()); |
| 132 |
| 133 std::vector<base::StringPiece16> labels = Parse(value_); |
| 134 for (const auto& label : labels) { |
| 135 if (label.size() < label_name.size() + 2 || |
| 136 !label.starts_with(label_name) || |
| 137 label[label_name.size()] != kNameValueSeparator) { |
| 138 continue; |
| 139 } |
| 140 size_t value_start = label_name.size() + 1; |
| 141 size_t value_end = label.find(kValueExpirationSeparator, value_start); |
| 142 if (value_end == base::StringPiece16::npos) |
| 143 break; |
| 144 return std::make_pair(label, |
| 145 label.substr(value_start, value_end - value_start)); |
| 146 } |
| 147 return LabelAndValue(); |
| 148 } |
| 149 |
| 150 } // namespace installer |
OLD | NEW |