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 |