Chromium Code Reviews| 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 bool GetUIDataFromValue(const base::Value& ui_data_value, NetworkUIData* out) { | |
| 139 std::string ui_data_str; | |
| 140 if (!ui_data_value.GetAsString(&ui_data_str)) | |
| 141 return false; | |
| 142 if (ui_data_str.empty()) { | |
| 143 *out = NetworkUIData(); | |
| 144 return true; | |
| 145 } | |
| 146 scoped_ptr<base::DictionaryValue> ui_data_dict( | |
| 147 chromeos::onc::ReadDictionaryFromJson(ui_data_str)); | |
| 148 if (!ui_data_dict) | |
| 149 return false; | |
| 150 *out = NetworkUIData(*ui_data_dict); | |
| 151 return true; | |
| 152 } | |
| 153 | |
| 154 scoped_ptr<NetworkUIData> GetUIData( | |
| 155 const base::DictionaryValue& shill_dictionary) { | |
| 156 const base::Value* ui_data_value = NULL; | |
| 157 shill_dictionary.GetWithoutPathExpansion(flimflam::kUIDataProperty, | |
| 158 &ui_data_value); | |
| 159 if (ui_data_value) { | |
| 160 scoped_ptr<NetworkUIData> ui_data(new NetworkUIData); | |
| 161 if (GetUIDataFromValue(*ui_data_value, ui_data.get())) | |
| 162 return ui_data.Pass(); | |
| 163 else | |
|
stevenjb
2013/08/28 15:33:54
no else
pneubeck (no reviews)
2013/09/02 13:39:54
Done.
| |
| 164 LOG(ERROR) << "UIData is not a valid JSON dictionary."; | |
| 165 } else { | |
| 166 VLOG(2) << "Dictionary has no UIData entry."; | |
| 167 } | |
| 168 return scoped_ptr<NetworkUIData>(); | |
| 169 } | |
| 170 | |
| 171 void SetUIData(const NetworkUIData& ui_data, | |
| 172 base::DictionaryValue* shill_dictionary) { | |
| 173 base::DictionaryValue ui_data_dict; | |
| 174 ui_data.FillDictionary(&ui_data_dict); | |
| 175 std::string ui_data_blob; | |
| 176 base::JSONWriter::Write(&ui_data_dict, &ui_data_blob); | |
| 177 shill_dictionary->SetStringWithoutPathExpansion(flimflam::kUIDataProperty, | |
| 178 ui_data_blob); | |
| 179 } | |
| 180 | |
| 181 bool CopyIdentifyingProperties(const base::DictionaryValue& service_properties, | |
| 182 base::DictionaryValue* dest) { | |
| 183 CopyStringFromDictionary(service_properties, flimflam::kGuidProperty, dest); | |
| 184 | |
| 185 std::string type; | |
| 186 service_properties.GetStringWithoutPathExpansion(flimflam::kTypeProperty, | |
| 187 &type); | |
| 188 dest->SetStringWithoutPathExpansion(flimflam::kTypeProperty, type); | |
| 189 if (type == flimflam::kTypeWifi) { | |
| 190 CopyStringFromDictionary( | |
| 191 service_properties, flimflam::kSecurityProperty, dest); | |
| 192 CopyStringFromDictionary(service_properties, flimflam::kSSIDProperty, dest); | |
| 193 CopyStringFromDictionary(service_properties, flimflam::kModeManaged, dest); | |
| 194 } else if (type == flimflam::kTypeVPN) { | |
| 195 CopyStringFromDictionary(service_properties, flimflam::kNameProperty, dest); | |
| 196 // VPN Provider values are read from the "Provider" dictionary, but written | |
| 197 // with the keys "Provider.Type" and "Provider.Host". | |
| 198 const base::DictionaryValue* provider_properties; | |
| 199 if (!service_properties.GetDictionaryWithoutPathExpansion( | |
| 200 flimflam::kProviderProperty, &provider_properties)) { | |
| 201 LOG(ERROR) << "Incomplete Shill dictionary missing VPN provider dict."; | |
| 202 return false; | |
| 203 } | |
| 204 std::string vpn_provider_type; | |
| 205 provider_properties->GetStringWithoutPathExpansion(flimflam::kTypeProperty, | |
| 206 &vpn_provider_type); | |
| 207 dest->SetStringWithoutPathExpansion(flimflam::kProviderTypeProperty, | |
| 208 vpn_provider_type); | |
| 209 | |
| 210 std::string vpn_provider_host; | |
| 211 provider_properties->GetStringWithoutPathExpansion(flimflam::kHostProperty, | |
| 212 &vpn_provider_host); | |
| 213 dest->SetStringWithoutPathExpansion(flimflam::kProviderHostProperty, | |
| 214 vpn_provider_host); | |
| 215 } else if (type == flimflam::kTypeEthernet || | |
| 216 type == shill::kTypeEthernetEap) { | |
|
stevenjb
2013/08/28 15:33:54
I think we should add something like shill_propert
| |
| 217 // Ethernet and EthernetEAP don't have any additional identifying | |
| 218 // properties. | |
| 219 } else { | |
| 220 NOTREACHED() << "Unsupported network type " << type; | |
| 221 } | |
| 222 return true; | |
| 223 } | |
| 224 | |
| 225 } // namespace shill_property_util | |
| 226 | |
| 227 } // namespace chromeos | |
| OLD | NEW |