| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "device/geolocation/network_location_request.h" | 5 #include "device/geolocation/network_location_request.h" |
| 6 | 6 |
| 7 #include <stdint.h> | 7 #include <stdint.h> |
| 8 | 8 |
| 9 #include <limits> | 9 #include <limits> |
| 10 #include <set> | 10 #include <set> |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 45 NETWORK_LOCATION_REQUEST_EVENT_RESPONSE_NOT_OK = 3, | 45 NETWORK_LOCATION_REQUEST_EVENT_RESPONSE_NOT_OK = 3, |
| 46 NETWORK_LOCATION_REQUEST_EVENT_RESPONSE_EMPTY = 4, | 46 NETWORK_LOCATION_REQUEST_EVENT_RESPONSE_EMPTY = 4, |
| 47 NETWORK_LOCATION_REQUEST_EVENT_RESPONSE_MALFORMED = 5, | 47 NETWORK_LOCATION_REQUEST_EVENT_RESPONSE_MALFORMED = 5, |
| 48 NETWORK_LOCATION_REQUEST_EVENT_RESPONSE_INVALID_FIX = 6, | 48 NETWORK_LOCATION_REQUEST_EVENT_RESPONSE_INVALID_FIX = 6, |
| 49 | 49 |
| 50 // NOTE: Add entries only immediately above this line. | 50 // NOTE: Add entries only immediately above this line. |
| 51 NETWORK_LOCATION_REQUEST_EVENT_COUNT = 7 | 51 NETWORK_LOCATION_REQUEST_EVENT_COUNT = 7 |
| 52 }; | 52 }; |
| 53 | 53 |
| 54 void RecordUmaEvent(NetworkLocationRequestEvent event) { | 54 void RecordUmaEvent(NetworkLocationRequestEvent event) { |
| 55 UMA_HISTOGRAM_ENUMERATION("Geolocation.NetworkLocationRequest.Event", | 55 UMA_HISTOGRAM_ENUMERATION("Geolocation.NetworkLocationRequest.Event", event, |
| 56 event, NETWORK_LOCATION_REQUEST_EVENT_COUNT); | 56 NETWORK_LOCATION_REQUEST_EVENT_COUNT); |
| 57 } | 57 } |
| 58 | 58 |
| 59 void RecordUmaResponseCode(int code) { | 59 void RecordUmaResponseCode(int code) { |
| 60 UMA_HISTOGRAM_SPARSE_SLOWLY("Geolocation.NetworkLocationRequest.ResponseCode", | 60 UMA_HISTOGRAM_SPARSE_SLOWLY("Geolocation.NetworkLocationRequest.ResponseCode", |
| 61 code); | 61 code); |
| 62 } | 62 } |
| 63 | 63 |
| 64 void RecordUmaAccessPoints(int count) { | 64 void RecordUmaAccessPoints(int count) { |
| 65 const int min = 0; | 65 const int min = 0; |
| 66 const int max = 20; | 66 const int max = 20; |
| 67 const int buckets = 21; | 67 const int buckets = 21; |
| 68 UMA_HISTOGRAM_CUSTOM_COUNTS("Geolocation.NetworkLocationRequest.AccessPoints", | 68 UMA_HISTOGRAM_CUSTOM_COUNTS("Geolocation.NetworkLocationRequest.AccessPoints", |
| 69 count, min, max, buckets); | 69 count, min, max, buckets); |
| 70 } | 70 } |
| 71 | 71 |
| 72 // Local functions | 72 // Local functions |
| 73 // Creates the request url to send to the server. | 73 // Creates the request url to send to the server. |
| 74 GURL FormRequestURL(const GURL& url); | 74 GURL FormRequestURL(const GURL& url); |
| 75 | 75 |
| 76 void FormUploadData(const WifiData& wifi_data, | 76 void FormUploadData(const WifiData& wifi_data, |
| 77 const base::Time& wifi_timestamp, | 77 const base::Time& wifi_timestamp, |
| 78 const base::string16& access_token, | 78 const base::string16& access_token, |
| 79 std::string* upload_data); | 79 std::string* upload_data); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 99 int age_milliseconds, | 99 int age_milliseconds, |
| 100 base::DictionaryValue* request); | 100 base::DictionaryValue* request); |
| 101 } // namespace | 101 } // namespace |
| 102 | 102 |
| 103 int NetworkLocationRequest::url_fetcher_id_for_tests = 0; | 103 int NetworkLocationRequest::url_fetcher_id_for_tests = 0; |
| 104 | 104 |
| 105 NetworkLocationRequest::NetworkLocationRequest( | 105 NetworkLocationRequest::NetworkLocationRequest( |
| 106 const scoped_refptr<net::URLRequestContextGetter>& context, | 106 const scoped_refptr<net::URLRequestContextGetter>& context, |
| 107 const GURL& url, | 107 const GURL& url, |
| 108 LocationResponseCallback callback) | 108 LocationResponseCallback callback) |
| 109 : url_context_(context), location_response_callback_(callback), url_(url) { | 109 : url_context_(context), location_response_callback_(callback), url_(url) {} |
| 110 } | |
| 111 | 110 |
| 112 NetworkLocationRequest::~NetworkLocationRequest() { | 111 NetworkLocationRequest::~NetworkLocationRequest() {} |
| 113 } | |
| 114 | 112 |
| 115 bool NetworkLocationRequest::MakeRequest(const base::string16& access_token, | 113 bool NetworkLocationRequest::MakeRequest(const base::string16& access_token, |
| 116 const WifiData& wifi_data, | 114 const WifiData& wifi_data, |
| 117 const base::Time& wifi_timestamp) { | 115 const base::Time& wifi_timestamp) { |
| 118 RecordUmaEvent(NETWORK_LOCATION_REQUEST_EVENT_REQUEST_START); | 116 RecordUmaEvent(NETWORK_LOCATION_REQUEST_EVENT_REQUEST_START); |
| 119 RecordUmaAccessPoints(wifi_data.access_point_data.size()); | 117 RecordUmaAccessPoints(wifi_data.access_point_data.size()); |
| 120 if (url_fetcher_ != NULL) { | 118 if (url_fetcher_ != NULL) { |
| 121 DVLOG(1) << "NetworkLocationRequest : Cancelling pending request"; | 119 DVLOG(1) << "NetworkLocationRequest : Cancelling pending request"; |
| 122 RecordUmaEvent(NETWORK_LOCATION_REQUEST_EVENT_REQUEST_CANCEL); | 120 RecordUmaEvent(NETWORK_LOCATION_REQUEST_EVENT_REQUEST_CANCEL); |
| 123 url_fetcher_.reset(); | 121 url_fetcher_.reset(); |
| 124 } | 122 } |
| 125 wifi_data_ = wifi_data; | 123 wifi_data_ = wifi_data; |
| 126 wifi_timestamp_ = wifi_timestamp; | 124 wifi_timestamp_ = wifi_timestamp; |
| 127 | 125 |
| 128 GURL request_url = FormRequestURL(url_); | 126 GURL request_url = FormRequestURL(url_); |
| 129 url_fetcher_ = net::URLFetcher::Create(url_fetcher_id_for_tests, request_url, | 127 url_fetcher_ = net::URLFetcher::Create(url_fetcher_id_for_tests, request_url, |
| 130 net::URLFetcher::POST, this); | 128 net::URLFetcher::POST, this); |
| 131 url_fetcher_->SetRequestContext(url_context_.get()); | 129 url_fetcher_->SetRequestContext(url_context_.get()); |
| 132 std::string upload_data; | 130 std::string upload_data; |
| 133 FormUploadData(wifi_data, wifi_timestamp, access_token, &upload_data); | 131 FormUploadData(wifi_data, wifi_timestamp, access_token, &upload_data); |
| 134 url_fetcher_->SetUploadData("application/json", upload_data); | 132 url_fetcher_->SetUploadData("application/json", upload_data); |
| 135 url_fetcher_->SetLoadFlags( | 133 url_fetcher_->SetLoadFlags(net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE | |
| 136 net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE | | 134 net::LOAD_DO_NOT_SAVE_COOKIES | |
| 137 net::LOAD_DO_NOT_SAVE_COOKIES | net::LOAD_DO_NOT_SEND_COOKIES | | 135 net::LOAD_DO_NOT_SEND_COOKIES | |
| 138 net::LOAD_DO_NOT_SEND_AUTH_DATA); | 136 net::LOAD_DO_NOT_SEND_AUTH_DATA); |
| 139 | 137 |
| 140 request_start_time_ = base::TimeTicks::Now(); | 138 request_start_time_ = base::TimeTicks::Now(); |
| 141 url_fetcher_->Start(); | 139 url_fetcher_->Start(); |
| 142 return true; | 140 return true; |
| 143 } | 141 } |
| 144 | 142 |
| 145 void NetworkLocationRequest::OnURLFetchComplete( | 143 void NetworkLocationRequest::OnURLFetchComplete(const net::URLFetcher* source) { |
| 146 const net::URLFetcher* source) { | |
| 147 DCHECK_EQ(url_fetcher_.get(), source); | 144 DCHECK_EQ(url_fetcher_.get(), source); |
| 148 | 145 |
| 149 net::URLRequestStatus status = source->GetStatus(); | 146 net::URLRequestStatus status = source->GetStatus(); |
| 150 int response_code = source->GetResponseCode(); | 147 int response_code = source->GetResponseCode(); |
| 151 RecordUmaResponseCode(response_code); | 148 RecordUmaResponseCode(response_code); |
| 152 | 149 |
| 153 Geoposition position; | 150 Geoposition position; |
| 154 base::string16 access_token; | 151 base::string16 access_token; |
| 155 std::string data; | 152 std::string data; |
| 156 source->GetResponseAsString(&data); | 153 source->GetResponseAsString(&data); |
| 157 GetLocationFromResponse(status.is_success(), response_code, data, | 154 GetLocationFromResponse(status.is_success(), response_code, data, |
| 158 wifi_timestamp_, source->GetURL(), &position, | 155 wifi_timestamp_, source->GetURL(), &position, |
| 159 &access_token); | 156 &access_token); |
| 160 const bool server_error = | 157 const bool server_error = |
| 161 !status.is_success() || (response_code >= 500 && response_code < 600); | 158 !status.is_success() || (response_code >= 500 && response_code < 600); |
| 162 url_fetcher_.reset(); | 159 url_fetcher_.reset(); |
| 163 | 160 |
| 164 if (!server_error) { | 161 if (!server_error) { |
| 165 const base::TimeDelta request_time = | 162 const base::TimeDelta request_time = |
| 166 base::TimeTicks::Now() - request_start_time_; | 163 base::TimeTicks::Now() - request_start_time_; |
| 167 | 164 |
| 168 UMA_HISTOGRAM_CUSTOM_TIMES( | 165 UMA_HISTOGRAM_CUSTOM_TIMES("Net.Wifi.LbsLatency", request_time, |
| 169 "Net.Wifi.LbsLatency", | 166 base::TimeDelta::FromMilliseconds(1), |
| 170 request_time, | 167 base::TimeDelta::FromSeconds(10), 100); |
| 171 base::TimeDelta::FromMilliseconds(1), | |
| 172 base::TimeDelta::FromSeconds(10), | |
| 173 100); | |
| 174 } | 168 } |
| 175 | 169 |
| 176 DVLOG(1) << "NetworkLocationRequest::OnURLFetchComplete() : run callback."; | 170 DVLOG(1) << "NetworkLocationRequest::OnURLFetchComplete() : run callback."; |
| 177 location_response_callback_.Run( | 171 location_response_callback_.Run(position, server_error, access_token, |
| 178 position, server_error, access_token, wifi_data_); | 172 wifi_data_); |
| 179 } | 173 } |
| 180 | 174 |
| 181 // Local functions. | 175 // Local functions. |
| 182 namespace { | 176 namespace { |
| 183 | 177 |
| 184 struct AccessPointLess { | 178 struct AccessPointLess { |
| 185 bool operator()(const AccessPointData* ap1, | 179 bool operator()(const AccessPointData* ap1, |
| 186 const AccessPointData* ap2) const { | 180 const AccessPointData* ap2) const { |
| 187 return ap2->radio_signal_strength < ap1->radio_signal_strength; | 181 return ap2->radio_signal_strength < ap1->radio_signal_strength; |
| 188 } | 182 } |
| (...skipping 28 matching lines...) Expand all Loading... |
| 217 age = static_cast<int>(delta_ms); | 211 age = static_cast<int>(delta_ms); |
| 218 } | 212 } |
| 219 | 213 |
| 220 base::DictionaryValue request; | 214 base::DictionaryValue request; |
| 221 AddWifiData(wifi_data, age, &request); | 215 AddWifiData(wifi_data, age, &request); |
| 222 if (!access_token.empty()) | 216 if (!access_token.empty()) |
| 223 request.SetString(kAccessTokenString, access_token); | 217 request.SetString(kAccessTokenString, access_token); |
| 224 base::JSONWriter::Write(request, upload_data); | 218 base::JSONWriter::Write(request, upload_data); |
| 225 } | 219 } |
| 226 | 220 |
| 227 void AddString(const std::string& property_name, const std::string& value, | 221 void AddString(const std::string& property_name, |
| 222 const std::string& value, |
| 228 base::DictionaryValue* dict) { | 223 base::DictionaryValue* dict) { |
| 229 DCHECK(dict); | 224 DCHECK(dict); |
| 230 if (!value.empty()) | 225 if (!value.empty()) |
| 231 dict->SetString(property_name, value); | 226 dict->SetString(property_name, value); |
| 232 } | 227 } |
| 233 | 228 |
| 234 void AddInteger(const std::string& property_name, int value, | 229 void AddInteger(const std::string& property_name, |
| 230 int value, |
| 235 base::DictionaryValue* dict) { | 231 base::DictionaryValue* dict) { |
| 236 DCHECK(dict); | 232 DCHECK(dict); |
| 237 if (value != std::numeric_limits<int32_t>::min()) | 233 if (value != std::numeric_limits<int32_t>::min()) |
| 238 dict->SetInteger(property_name, value); | 234 dict->SetInteger(property_name, value); |
| 239 } | 235 } |
| 240 | 236 |
| 241 void AddWifiData(const WifiData& wifi_data, | 237 void AddWifiData(const WifiData& wifi_data, |
| 242 int age_milliseconds, | 238 int age_milliseconds, |
| 243 base::DictionaryValue* request) { | 239 base::DictionaryValue* request) { |
| 244 DCHECK(request); | 240 DCHECK(request); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 261 AddInteger("channel", ap_data->channel, wifi_dict); | 257 AddInteger("channel", ap_data->channel, wifi_dict); |
| 262 AddInteger("signalToNoiseRatio", ap_data->signal_to_noise, wifi_dict); | 258 AddInteger("signalToNoiseRatio", ap_data->signal_to_noise, wifi_dict); |
| 263 wifi_access_point_list->Append(wifi_dict); | 259 wifi_access_point_list->Append(wifi_dict); |
| 264 } | 260 } |
| 265 request->Set("wifiAccessPoints", wifi_access_point_list); | 261 request->Set("wifiAccessPoints", wifi_access_point_list); |
| 266 } | 262 } |
| 267 | 263 |
| 268 void FormatPositionError(const GURL& server_url, | 264 void FormatPositionError(const GURL& server_url, |
| 269 const std::string& message, | 265 const std::string& message, |
| 270 Geoposition* position) { | 266 Geoposition* position) { |
| 271 position->error_code = Geoposition::ERROR_CODE_POSITION_UNAVAILABLE; | 267 position->error_code = Geoposition::ERROR_CODE_POSITION_UNAVAILABLE; |
| 272 position->error_message = "Network location provider at '"; | 268 position->error_message = "Network location provider at '"; |
| 273 position->error_message += server_url.GetOrigin().spec(); | 269 position->error_message += server_url.GetOrigin().spec(); |
| 274 position->error_message += "' : "; | 270 position->error_message += "' : "; |
| 275 position->error_message += message; | 271 position->error_message += message; |
| 276 position->error_message += "."; | 272 position->error_message += "."; |
| 277 VLOG(1) << "NetworkLocationRequest::GetLocationFromResponse() : " | 273 VLOG(1) << "NetworkLocationRequest::GetLocationFromResponse() : " |
| 278 << position->error_message; | 274 << position->error_message; |
| 279 } | 275 } |
| 280 | 276 |
| 281 void GetLocationFromResponse(bool http_post_result, | 277 void GetLocationFromResponse(bool http_post_result, |
| 282 int status_code, | 278 int status_code, |
| 283 const std::string& response_body, | 279 const std::string& response_body, |
| 284 const base::Time& wifi_timestamp, | 280 const base::Time& wifi_timestamp, |
| 285 const GURL& server_url, | 281 const GURL& server_url, |
| 286 Geoposition* position, | 282 Geoposition* position, |
| 287 base::string16* access_token) { | 283 base::string16* access_token) { |
| 288 DCHECK(position); | 284 DCHECK(position); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 307 if (!ParseServerResponse(response_body, wifi_timestamp, position, | 303 if (!ParseServerResponse(response_body, wifi_timestamp, position, |
| 308 access_token)) { | 304 access_token)) { |
| 309 // We failed to parse the repsonse. | 305 // We failed to parse the repsonse. |
| 310 FormatPositionError(server_url, "Response was malformed", position); | 306 FormatPositionError(server_url, "Response was malformed", position); |
| 311 RecordUmaEvent(NETWORK_LOCATION_REQUEST_EVENT_RESPONSE_MALFORMED); | 307 RecordUmaEvent(NETWORK_LOCATION_REQUEST_EVENT_RESPONSE_MALFORMED); |
| 312 return; | 308 return; |
| 313 } | 309 } |
| 314 // The response was successfully parsed, but it may not be a valid | 310 // The response was successfully parsed, but it may not be a valid |
| 315 // position fix. | 311 // position fix. |
| 316 if (!position->Validate()) { | 312 if (!position->Validate()) { |
| 317 FormatPositionError(server_url, | 313 FormatPositionError(server_url, "Did not provide a good position fix", |
| 318 "Did not provide a good position fix", position); | 314 position); |
| 319 RecordUmaEvent(NETWORK_LOCATION_REQUEST_EVENT_RESPONSE_INVALID_FIX); | 315 RecordUmaEvent(NETWORK_LOCATION_REQUEST_EVENT_RESPONSE_INVALID_FIX); |
| 320 return; | 316 return; |
| 321 } | 317 } |
| 322 RecordUmaEvent(NETWORK_LOCATION_REQUEST_EVENT_RESPONSE_SUCCESS); | 318 RecordUmaEvent(NETWORK_LOCATION_REQUEST_EVENT_RESPONSE_SUCCESS); |
| 323 } | 319 } |
| 324 | 320 |
| 325 // Numeric values without a decimal point have type integer and IsDouble() will | 321 // Numeric values without a decimal point have type integer and IsDouble() will |
| 326 // return false. This is convenience function for detecting integer or floating | 322 // return false. This is convenience function for detecting integer or floating |
| 327 // point numeric values. Note that isIntegral() includes boolean values, which | 323 // point numeric values. Note that isIntegral() includes boolean values, which |
| 328 // is not what we want. | 324 // is not what we want. |
| (...skipping 28 matching lines...) Expand all Loading... |
| 357 return false; | 353 return false; |
| 358 } | 354 } |
| 359 DVLOG(1) << "ParseServerResponse() : Parsing response " << response_body; | 355 DVLOG(1) << "ParseServerResponse() : Parsing response " << response_body; |
| 360 | 356 |
| 361 // Parse the response, ignoring comments. | 357 // Parse the response, ignoring comments. |
| 362 std::string error_msg; | 358 std::string error_msg; |
| 363 std::unique_ptr<base::Value> response_value = | 359 std::unique_ptr<base::Value> response_value = |
| 364 base::JSONReader::ReadAndReturnError(response_body, base::JSON_PARSE_RFC, | 360 base::JSONReader::ReadAndReturnError(response_body, base::JSON_PARSE_RFC, |
| 365 NULL, &error_msg); | 361 NULL, &error_msg); |
| 366 if (response_value == NULL) { | 362 if (response_value == NULL) { |
| 367 LOG(WARNING) << "ParseServerResponse() : JSONReader failed : " | 363 LOG(WARNING) << "ParseServerResponse() : JSONReader failed : " << error_msg; |
| 368 << error_msg; | |
| 369 return false; | 364 return false; |
| 370 } | 365 } |
| 371 | 366 |
| 372 if (!response_value->IsType(base::Value::TYPE_DICTIONARY)) { | 367 if (!response_value->IsType(base::Value::TYPE_DICTIONARY)) { |
| 373 VLOG(1) << "ParseServerResponse() : Unexpected response type " | 368 VLOG(1) << "ParseServerResponse() : Unexpected response type " |
| 374 << response_value->GetType(); | 369 << response_value->GetType(); |
| 375 return false; | 370 return false; |
| 376 } | 371 } |
| 377 const base::DictionaryValue* response_object = | 372 const base::DictionaryValue* response_object = |
| 378 static_cast<base::DictionaryValue*>(response_value.get()); | 373 static_cast<base::DictionaryValue*>(response_value.get()); |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 418 | 413 |
| 419 // Other fields are optional. | 414 // Other fields are optional. |
| 420 GetAsDouble(*response_object, kAccuracyString, &position->accuracy); | 415 GetAsDouble(*response_object, kAccuracyString, &position->accuracy); |
| 421 | 416 |
| 422 return true; | 417 return true; |
| 423 } | 418 } |
| 424 | 419 |
| 425 } // namespace | 420 } // namespace |
| 426 | 421 |
| 427 } // namespace device | 422 } // namespace device |
| OLD | NEW |