OLD | NEW |
(Empty) | |
| 1 // Copyright 2013 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 "chromeos/network/shill_property_util.h" |
| 6 |
| 7 #include "base/i18n/icu_encoding_detection.h" |
| 8 #include "base/i18n/icu_string_conversions.h" |
| 9 #include "base/json/json_writer.h" |
| 10 #include "base/strings/string_number_conversions.h" |
| 11 #include "base/strings/string_util.h" |
| 12 #include "base/strings/stringprintf.h" |
| 13 #include "base/strings/utf_string_conversion_utils.h" |
| 14 #include "base/values.h" |
| 15 #include "chromeos/network/network_event_log.h" |
| 16 #include "chromeos/network/network_ui_data.h" |
| 17 #include "chromeos/network/onc/onc_utils.h" |
| 18 #include "third_party/cros_system_api/dbus/service_constants.h" |
| 19 |
| 20 namespace chromeos { |
| 21 |
| 22 namespace shill_property_util { |
| 23 |
| 24 namespace { |
| 25 |
| 26 // Replace non UTF8 characters in |str| with a replacement character. |
| 27 std::string ValidateUTF8(const std::string& str) { |
| 28 std::string result; |
| 29 for (int32 index = 0; index < static_cast<int32>(str.size()); ++index) { |
| 30 uint32 code_point_out; |
| 31 bool is_unicode_char = base::ReadUnicodeCharacter( |
| 32 str.c_str(), str.size(), &index, &code_point_out); |
| 33 const uint32 kFirstNonControlChar = 0x20; |
| 34 if (is_unicode_char && (code_point_out >= kFirstNonControlChar)) { |
| 35 base::WriteUnicodeCharacter(code_point_out, &result); |
| 36 } else { |
| 37 const uint32 kReplacementChar = 0xFFFD; |
| 38 // Puts kReplacementChar if character is a control character [0,0x20) |
| 39 // or is not readable UTF8. |
| 40 base::WriteUnicodeCharacter(kReplacementChar, &result); |
| 41 } |
| 42 } |
| 43 return result; |
| 44 } |
| 45 |
| 46 void CopyStringFromDictionary(const base::DictionaryValue& source, |
| 47 const std::string& key, |
| 48 base::DictionaryValue* dest) { |
| 49 std::string string_value; |
| 50 if (source.GetStringWithoutPathExpansion(key, &string_value)) |
| 51 dest->SetStringWithoutPathExpansion(key, string_value); |
| 52 } |
| 53 |
| 54 } // namespace |
| 55 |
| 56 std::string GetNameFromProperties(const std::string& service_path, |
| 57 const base::DictionaryValue& properties) { |
| 58 std::string name, hex_ssid; |
| 59 properties.GetStringWithoutPathExpansion(flimflam::kNameProperty, &name); |
| 60 properties.GetStringWithoutPathExpansion(flimflam::kWifiHexSsid, &hex_ssid); |
| 61 |
| 62 if (hex_ssid.empty()) { |
| 63 if (name.empty()) |
| 64 return name; |
| 65 // Validate name for UTF8. |
| 66 std::string valid_ssid = ValidateUTF8(name); |
| 67 if (valid_ssid != name) { |
| 68 NET_LOG_DEBUG( |
| 69 "GetNameFromProperties", |
| 70 base::StringPrintf( |
| 71 "%s: UTF8: %s", service_path.c_str(), valid_ssid.c_str())); |
| 72 } |
| 73 return valid_ssid; |
| 74 } |
| 75 |
| 76 std::string ssid; |
| 77 std::vector<uint8> raw_ssid_bytes; |
| 78 if (base::HexStringToBytes(hex_ssid, &raw_ssid_bytes)) { |
| 79 ssid = std::string(raw_ssid_bytes.begin(), raw_ssid_bytes.end()); |
| 80 NET_LOG_DEBUG("GetNameFromProperties", |
| 81 base::StringPrintf("%s: %s, SSID: %s", |
| 82 service_path.c_str(), |
| 83 hex_ssid.c_str(), |
| 84 ssid.c_str())); |
| 85 } else { |
| 86 NET_LOG_ERROR("GetNameFromProperties", |
| 87 base::StringPrintf("%s: Error processing: %s", |
| 88 service_path.c_str(), |
| 89 hex_ssid.c_str())); |
| 90 return name; |
| 91 } |
| 92 |
| 93 if (IsStringUTF8(ssid)) { |
| 94 if (ssid != name) { |
| 95 NET_LOG_DEBUG("GetNameFromProperties", |
| 96 base::StringPrintf( |
| 97 "%s: UTF8: %s", service_path.c_str(), ssid.c_str())); |
| 98 } |
| 99 return ssid; |
| 100 } |
| 101 |
| 102 // Detect encoding and convert to UTF-8. |
| 103 std::string country_code; |
| 104 properties.GetStringWithoutPathExpansion(flimflam::kCountryProperty, |
| 105 &country_code); |
| 106 std::string encoding; |
| 107 if (!base::DetectEncoding(ssid, &encoding)) { |
| 108 // TODO(stevenjb): This is currently experimental. If we find a case where |
| 109 // base::DetectEncoding() fails, we need to figure out whether we can use |
| 110 // country_code with ConvertToUtf8(). crbug.com/233267. |
| 111 encoding = country_code; |
| 112 } |
| 113 if (!encoding.empty()) { |
| 114 std::string utf8_ssid; |
| 115 if (base::ConvertToUtf8AndNormalize(ssid, encoding, &utf8_ssid)) { |
| 116 if (utf8_ssid != name) { |
| 117 NET_LOG_DEBUG("GetNameFromProperties", |
| 118 base::StringPrintf("%s: Encoding=%s: %s", |
| 119 service_path.c_str(), |
| 120 encoding.c_str(), |
| 121 utf8_ssid.c_str())); |
| 122 } |
| 123 return utf8_ssid; |
| 124 } |
| 125 } |
| 126 |
| 127 // Unrecognized encoding. Only use raw bytes if name_ is empty. |
| 128 NET_LOG_DEBUG("GetNameFromProperties", |
| 129 base::StringPrintf("%s: Unrecognized Encoding=%s: %s", |
| 130 service_path.c_str(), |
| 131 encoding.c_str(), |
| 132 ssid.c_str())); |
| 133 if (name.empty() && !ssid.empty()) |
| 134 return ssid; |
| 135 return name; |
| 136 } |
| 137 |
| 138 scoped_ptr<NetworkUIData> GetUIDataFromValue(const base::Value& ui_data_value) { |
| 139 std::string ui_data_str; |
| 140 if (!ui_data_value.GetAsString(&ui_data_str)) |
| 141 return scoped_ptr<NetworkUIData>(); |
| 142 if (ui_data_str.empty()) |
| 143 return make_scoped_ptr(new NetworkUIData()); |
| 144 scoped_ptr<base::DictionaryValue> ui_data_dict( |
| 145 chromeos::onc::ReadDictionaryFromJson(ui_data_str)); |
| 146 if (!ui_data_dict) |
| 147 return scoped_ptr<NetworkUIData>(); |
| 148 return make_scoped_ptr(new NetworkUIData(*ui_data_dict)); |
| 149 } |
| 150 |
| 151 scoped_ptr<NetworkUIData> GetUIDataFromProperties( |
| 152 const base::DictionaryValue& shill_dictionary) { |
| 153 const base::Value* ui_data_value = NULL; |
| 154 shill_dictionary.GetWithoutPathExpansion(flimflam::kUIDataProperty, |
| 155 &ui_data_value); |
| 156 if (!ui_data_value) { |
| 157 VLOG(2) << "Dictionary has no UIData entry."; |
| 158 return scoped_ptr<NetworkUIData>(); |
| 159 } |
| 160 scoped_ptr<NetworkUIData> ui_data = GetUIDataFromValue(*ui_data_value); |
| 161 if (!ui_data) |
| 162 LOG(ERROR) << "UIData is not a valid JSON dictionary."; |
| 163 return ui_data.Pass(); |
| 164 } |
| 165 |
| 166 void SetUIData(const NetworkUIData& ui_data, |
| 167 base::DictionaryValue* shill_dictionary) { |
| 168 base::DictionaryValue ui_data_dict; |
| 169 ui_data.FillDictionary(&ui_data_dict); |
| 170 std::string ui_data_blob; |
| 171 base::JSONWriter::Write(&ui_data_dict, &ui_data_blob); |
| 172 shill_dictionary->SetStringWithoutPathExpansion(flimflam::kUIDataProperty, |
| 173 ui_data_blob); |
| 174 } |
| 175 |
| 176 bool CopyIdentifyingProperties(const base::DictionaryValue& service_properties, |
| 177 base::DictionaryValue* dest) { |
| 178 CopyStringFromDictionary(service_properties, flimflam::kGuidProperty, dest); |
| 179 |
| 180 std::string type; |
| 181 service_properties.GetStringWithoutPathExpansion(flimflam::kTypeProperty, |
| 182 &type); |
| 183 dest->SetStringWithoutPathExpansion(flimflam::kTypeProperty, type); |
| 184 if (type == flimflam::kTypeWifi) { |
| 185 CopyStringFromDictionary( |
| 186 service_properties, flimflam::kSecurityProperty, dest); |
| 187 CopyStringFromDictionary(service_properties, flimflam::kSSIDProperty, dest); |
| 188 CopyStringFromDictionary(service_properties, flimflam::kModeProperty, dest); |
| 189 } else if (type == flimflam::kTypeVPN) { |
| 190 CopyStringFromDictionary(service_properties, flimflam::kNameProperty, dest); |
| 191 // VPN Provider values are read from the "Provider" dictionary, but written |
| 192 // with the keys "Provider.Type" and "Provider.Host". |
| 193 const base::DictionaryValue* provider_properties; |
| 194 if (!service_properties.GetDictionaryWithoutPathExpansion( |
| 195 flimflam::kProviderProperty, &provider_properties)) { |
| 196 LOG(ERROR) << "Incomplete Shill dictionary missing VPN provider dict."; |
| 197 return false; |
| 198 } |
| 199 std::string vpn_provider_type; |
| 200 provider_properties->GetStringWithoutPathExpansion(flimflam::kTypeProperty, |
| 201 &vpn_provider_type); |
| 202 dest->SetStringWithoutPathExpansion(flimflam::kProviderTypeProperty, |
| 203 vpn_provider_type); |
| 204 |
| 205 std::string vpn_provider_host; |
| 206 provider_properties->GetStringWithoutPathExpansion(flimflam::kHostProperty, |
| 207 &vpn_provider_host); |
| 208 dest->SetStringWithoutPathExpansion(flimflam::kProviderHostProperty, |
| 209 vpn_provider_host); |
| 210 } else if (type == flimflam::kTypeEthernet || |
| 211 type == shill::kTypeEthernetEap) { |
| 212 // Ethernet and EthernetEAP don't have any additional identifying |
| 213 // properties. |
| 214 } else { |
| 215 NOTREACHED() << "Unsupported network type " << type; |
| 216 } |
| 217 return true; |
| 218 } |
| 219 |
| 220 } // namespace shill_property_util |
| 221 |
| 222 } // namespace chromeos |
OLD | NEW |