Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(49)

Side by Side Diff: content/browser/geolocation/network_location_request.cc

Issue 11179003: Reapply geolocation network protocol changes. (Closed) Base URL: svn://svn.chromium.org/chrome/branches/1271/src/
Patch Set: Created 8 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « content/browser/geolocation/network_location_provider_unittest.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 "content/browser/geolocation/network_location_request.h" 5 #include "content/browser/geolocation/network_location_request.h"
6 6
7 #include <set> 7 #include <set>
8 #include <string> 8 #include <string>
9 9
10 #include "base/json/json_reader.h" 10 #include "base/json/json_reader.h"
11 #include "base/json/json_writer.h" 11 #include "base/json/json_writer.h"
12 #include "base/string_number_conversions.h" 12 #include "base/string_number_conversions.h"
13 #include "base/utf_string_conversions.h" 13 #include "base/utf_string_conversions.h"
14 #include "base/values.h" 14 #include "base/values.h"
15 #include "content/browser/geolocation/location_arbitrator.h"
15 #include "content/public/common/geoposition.h" 16 #include "content/public/common/geoposition.h"
17 #include "google_apis/google_api_keys.h"
16 #include "net/base/escape.h" 18 #include "net/base/escape.h"
17 #include "net/base/load_flags.h" 19 #include "net/base/load_flags.h"
18 #include "net/url_request/url_fetcher.h" 20 #include "net/url_request/url_fetcher.h"
19 #include "net/url_request/url_request_context_getter.h" 21 #include "net/url_request/url_request_context_getter.h"
20 #include "net/url_request/url_request_status.h" 22 #include "net/url_request/url_request_status.h"
21 23
22 namespace { 24 namespace {
23 25
24 const size_t kMaxRequestLength = 2048; 26 const size_t kMaxRequestLength = 2048;
25 27
26 const char kAccessTokenString[] = "access_token"; 28 const char kAccessTokenString[] = "accessToken";
27 const char kLocationString[] = "location"; 29 const char kLocationString[] = "location";
28 const char kLatitudeString[] = "lat"; 30 const char kLatitudeString[] = "lat";
29 const char kLongitudeString[] = "lng"; 31 const char kLongitudeString[] = "lng";
30 const char kAccuracyString[] = "accuracy"; 32 const char kAccuracyString[] = "accuracy";
31 const char kStatusString[] = "status"; 33 const char kStatusString[] = "status";
32 const char kStatusOKString[] = "OK"; 34 const char kStatusOKString[] = "OK";
33 35
34 // Local functions 36 // Local functions
35 // Creates the request url to send to the server. 37 // Creates the request url to send to the server.
36 GURL FormRequestURL(const std::string& url, 38 GURL FormRequestURL(const GURL& url);
39
40 void FormUploadData(const WifiData& wifi_data,
41 const base::Time& timestamp,
37 const string16& access_token, 42 const string16& access_token,
38 const WifiData& wifi_data, 43 std::string* upload_data);
39 const base::Time& timestamp);
40 44
41 // Parsers the server response. 45 // Parsers the server response.
42 void GetLocationFromResponse(bool http_post_result, 46 void GetLocationFromResponse(bool http_post_result,
43 int status_code, 47 int status_code,
44 const std::string& response_body, 48 const std::string& response_body,
45 const base::Time& timestamp, 49 const base::Time& timestamp,
46 const GURL& server_url, 50 const GURL& server_url,
47 content::Geoposition* position, 51 content::Geoposition* position,
48 string16* access_token); 52 string16* access_token);
49 53
50 // Parses the server response body. Returns true if parsing was successful. 54 // Parses the server response body. Returns true if parsing was successful.
51 // Sets |*position| to the parsed location if a valid fix was received, 55 // Sets |*position| to the parsed location if a valid fix was received,
52 // otherwise leaves it unchanged. 56 // otherwise leaves it unchanged.
53 bool ParseServerResponse(const std::string& response_body, 57 bool ParseServerResponse(const std::string& response_body,
54 const base::Time& timestamp, 58 const base::Time& timestamp,
55 content::Geoposition* position, 59 content::Geoposition* position,
56 string16* access_token); 60 string16* access_token);
57 void AddWifiData(const WifiData& wifi_data, 61 void AddWifiData(const WifiData& wifi_data,
58 int age_milliseconds, 62 int age_milliseconds,
59 std::vector<std::string>* params); 63 base::DictionaryValue* request);
60 } // namespace 64 } // namespace
61 65
62 int NetworkLocationRequest::url_fetcher_id_for_tests = 0; 66 int NetworkLocationRequest::url_fetcher_id_for_tests = 0;
63 67
64 NetworkLocationRequest::NetworkLocationRequest( 68 NetworkLocationRequest::NetworkLocationRequest(
65 net::URLRequestContextGetter* context, 69 net::URLRequestContextGetter* context,
66 const GURL& url, 70 const GURL& url,
67 ListenerInterface* listener) 71 ListenerInterface* listener)
68 : url_context_(context), listener_(listener), 72 : url_context_(context), listener_(listener),
69 url_(url) { 73 url_(url) {
70 DCHECK(listener); 74 DCHECK(listener);
71 } 75 }
72 76
73 NetworkLocationRequest::~NetworkLocationRequest() { 77 NetworkLocationRequest::~NetworkLocationRequest() {
74 } 78 }
75 79
76 bool NetworkLocationRequest::MakeRequest(const string16& access_token, 80 bool NetworkLocationRequest::MakeRequest(const string16& access_token,
77 const WifiData& wifi_data, 81 const WifiData& wifi_data,
78 const base::Time& timestamp) { 82 const base::Time& timestamp) {
79 if (url_fetcher_ != NULL) { 83 if (url_fetcher_ != NULL) {
80 DVLOG(1) << "NetworkLocationRequest : Cancelling pending request"; 84 DVLOG(1) << "NetworkLocationRequest : Cancelling pending request";
81 url_fetcher_.reset(); 85 url_fetcher_.reset();
82 } 86 }
83 wifi_data_ = wifi_data; 87 wifi_data_ = wifi_data;
84 timestamp_ = timestamp; 88 timestamp_ = timestamp;
85 89
86 GURL request_url = FormRequestURL(url_.spec(), access_token, 90 GURL request_url = FormRequestURL(url_);
87 wifi_data, timestamp_);
88 url_fetcher_.reset(net::URLFetcher::Create( 91 url_fetcher_.reset(net::URLFetcher::Create(
89 url_fetcher_id_for_tests, request_url, net::URLFetcher::GET, this)); 92 url_fetcher_id_for_tests, request_url, net::URLFetcher::POST, this));
90 url_fetcher_->SetRequestContext(url_context_); 93 url_fetcher_->SetRequestContext(url_context_);
94 std::string upload_data;
95 FormUploadData(wifi_data, timestamp, access_token, &upload_data);
96 url_fetcher_->SetUploadData("application/json", upload_data);
91 url_fetcher_->SetLoadFlags( 97 url_fetcher_->SetLoadFlags(
92 net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE | 98 net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE |
93 net::LOAD_DO_NOT_SAVE_COOKIES | net::LOAD_DO_NOT_SEND_COOKIES | 99 net::LOAD_DO_NOT_SAVE_COOKIES | net::LOAD_DO_NOT_SEND_COOKIES |
94 net::LOAD_DO_NOT_SEND_AUTH_DATA); 100 net::LOAD_DO_NOT_SEND_AUTH_DATA);
95 101
96 url_fetcher_->Start(); 102 url_fetcher_->Start();
97 return true; 103 return true;
98 } 104 }
99 105
100 void NetworkLocationRequest::OnURLFetchComplete( 106 void NetworkLocationRequest::OnURLFetchComplete(
(...skipping 27 matching lines...) Expand all
128 // Local functions. 134 // Local functions.
129 namespace { 135 namespace {
130 136
131 struct AccessPointLess { 137 struct AccessPointLess {
132 bool operator()(const AccessPointData* ap1, 138 bool operator()(const AccessPointData* ap1,
133 const AccessPointData* ap2) const { 139 const AccessPointData* ap2) const {
134 return ap2->radio_signal_strength < ap1->radio_signal_strength; 140 return ap2->radio_signal_strength < ap1->radio_signal_strength;
135 } 141 }
136 }; 142 };
137 143
138 GURL FormRequestURL(const std::string& url, 144 GURL FormRequestURL(const GURL& url) {
145 if (url == GeolocationArbitrator::DefaultNetworkProviderURL()) {
146 std::string api_key = google_apis::GetAPIKey();
147 if (!api_key.empty()) {
148 std::string query(url.query());
149 if (!query.empty())
150 query += "&";
151 query += "key=" + net::EscapeQueryParamValue(api_key, true);
152 GURL::Replacements replacements;
153 replacements.SetQueryStr(query);
154 return url.ReplaceComponents(replacements);
155 }
156 }
157 return url;
158 }
159
160 void FormUploadData(const WifiData& wifi_data,
161 const base::Time& timestamp,
139 const string16& access_token, 162 const string16& access_token,
140 const WifiData& wifi_data, 163 std::string* upload_data) {
141 const base::Time& timestamp) {
142 int age = kint32min; // Invalid so AddInteger() will ignore. 164 int age = kint32min; // Invalid so AddInteger() will ignore.
143 if (!timestamp.is_null()) { 165 if (!timestamp.is_null()) {
144 // Convert absolute timestamps into a relative age. 166 // Convert absolute timestamps into a relative age.
145 int64 delta_ms = (base::Time::Now() - timestamp).InMilliseconds(); 167 int64 delta_ms = (base::Time::Now() - timestamp).InMilliseconds();
146 if (delta_ms >= 0 && delta_ms < kint32max) 168 if (delta_ms >= 0 && delta_ms < kint32max)
147 age = static_cast<int>(delta_ms); 169 age = static_cast<int>(delta_ms);
148 } 170 }
149 171
150 std::vector<std::string> params; 172 base::DictionaryValue request;
151 #if defined(GOOGLE_CHROME_BUILD) 173 AddWifiData(wifi_data, age, &request);
152 params.push_back("browser=googlechrome");
153 #else
154 params.push_back("browser=chromium");
155 #endif
156
157 params.push_back("sensor=true");
158 if (!access_token.empty()) 174 if (!access_token.empty())
159 params.push_back("token=" + UTF16ToUTF8(access_token)); 175 request.SetString(kAccessTokenString, access_token);
160 AddWifiData(wifi_data, age, &params); 176 base::JSONWriter::Write(&request, upload_data);
161
162 std::string request_string = url + '?' + JoinString(params, '&');
163 if (request_string.length() > kMaxRequestLength) {
164 size_t last_param_pos =
165 request_string.find_last_of('&', kMaxRequestLength);
166 CHECK_NE(std::string::npos, last_param_pos);
167 request_string.erase(last_param_pos);
168 }
169
170 return GURL(request_string);
171 } 177 }
172 178
173 void AddString(const std::string& property_name, const std::string& value, 179 void AddString(const std::string& property_name, const std::string& value,
174 std::string* wifi_params) { 180 base::DictionaryValue* dict) {
175 DCHECK(wifi_params); 181 DCHECK(dict);
176 if (!value.empty()) { 182 if (!value.empty())
177 if (!wifi_params->empty()) 183 dict->SetString(property_name, value);
178 *wifi_params += '|';
179 *wifi_params += property_name;
180 *wifi_params += value;
181 }
182 } 184 }
183 185
184 void AddInteger(const std::string& property_name, int value, 186 void AddInteger(const std::string& property_name, int value,
185 std::string* wifi_params) { 187 base::DictionaryValue* dict) {
186 DCHECK(wifi_params); 188 DCHECK(dict);
187 if (value != kint32min) { 189 if (value != kint32min)
188 if (!wifi_params->empty()) 190 dict->SetInteger(property_name, value);
189 *wifi_params += '|';
190 *wifi_params += property_name;
191 *wifi_params += base::IntToString(value);
192 }
193 } 191 }
194 192
195 void AddWifiData(const WifiData& wifi_data, 193 void AddWifiData(const WifiData& wifi_data,
196 int age_milliseconds, 194 int age_milliseconds,
197 std::vector<std::string>* params) { 195 base::DictionaryValue* request) {
198 DCHECK(params); 196 DCHECK(request);
199 197
200 if (wifi_data.access_point_data.empty()) 198 if (wifi_data.access_point_data.empty())
201 return; 199 return;
202 200
203 typedef std::multiset<const AccessPointData*, AccessPointLess> AccessPointSet; 201 typedef std::multiset<const AccessPointData*, AccessPointLess> AccessPointSet;
204 AccessPointSet access_points_by_signal_strength; 202 AccessPointSet access_points_by_signal_strength;
205 203
206 for (WifiData::AccessPointDataSet::const_iterator iter = 204 for (WifiData::AccessPointDataSet::const_iterator iter =
207 wifi_data.access_point_data.begin(); 205 wifi_data.access_point_data.begin();
208 iter != wifi_data.access_point_data.end(); 206 iter != wifi_data.access_point_data.end();
209 ++iter) { 207 ++iter) {
210 access_points_by_signal_strength.insert(&(*iter)); 208 access_points_by_signal_strength.insert(&(*iter));
211 } 209 }
212 210
211 base::ListValue* wifi_access_point_list = new base::ListValue();
213 for (AccessPointSet::iterator iter = 212 for (AccessPointSet::iterator iter =
214 access_points_by_signal_strength.begin(); 213 access_points_by_signal_strength.begin();
215 iter != access_points_by_signal_strength.end(); 214 iter != access_points_by_signal_strength.end();
216 ++iter) { 215 ++iter) {
217 std::string wifi_params; 216 base::DictionaryValue* wifi_dict = new base::DictionaryValue();
218 AddString("mac:", UTF16ToUTF8((*iter)->mac_address), &wifi_params); 217 AddString("macAddress", UTF16ToUTF8((*iter)->mac_address), wifi_dict);
219 AddInteger("ss:", (*iter)->radio_signal_strength, &wifi_params); 218 AddInteger("signalStrength", (*iter)->radio_signal_strength, wifi_dict);
220 AddInteger("age:", age_milliseconds, &wifi_params); 219 AddInteger("age", age_milliseconds, wifi_dict);
221 AddInteger("chan:", (*iter)->channel, &wifi_params); 220 AddInteger("channel", (*iter)->channel, wifi_dict);
222 AddInteger("snr:", (*iter)->signal_to_noise, &wifi_params); 221 AddInteger("signalToNoiseRatio", (*iter)->signal_to_noise, wifi_dict);
223 std::string ssid = UTF16ToUTF8((*iter)->ssid); 222 wifi_access_point_list->Append(wifi_dict);
224 // Backslash characters in the ssid need backslash-escaping to avoid
225 // escaping a following wifi parameter separator.
226 ReplaceSubstringsAfterOffset(&ssid, 0, "\\", "\\\\");
227 // Pipe characters in the ssid need backslash-escaping to avoid being
228 // interpreted as the wifi parameter separator.
229 ReplaceSubstringsAfterOffset(&ssid, 0, "|", "\\|");
230 AddString("ssid:", ssid, &wifi_params);
231 params->push_back(
232 "wifi=" + net::EscapeQueryParamValue(wifi_params, false));
233 } 223 }
224 request->Set("wifiAccessPoints", wifi_access_point_list);
234 } 225 }
235 226
236 void FormatPositionError(const GURL& server_url, 227 void FormatPositionError(const GURL& server_url,
237 const std::string& message, 228 const std::string& message,
238 content::Geoposition* position) { 229 content::Geoposition* position) {
239 position->error_code = 230 position->error_code =
240 content::Geoposition::ERROR_CODE_POSITION_UNAVAILABLE; 231 content::Geoposition::ERROR_CODE_POSITION_UNAVAILABLE;
241 position->error_message = "Network location provider at '"; 232 position->error_message = "Network location provider at '";
242 position->error_message += server_url.possibly_invalid_spec(); 233 position->error_message += server_url.GetOrigin().spec();
243 position->error_message += "' : "; 234 position->error_message += "' : ";
244 position->error_message += message; 235 position->error_message += message;
245 position->error_message += "."; 236 position->error_message += ".";
246 VLOG(1) << "NetworkLocationRequest::GetLocationFromResponse() : " 237 VLOG(1) << "NetworkLocationRequest::GetLocationFromResponse() : "
247 << position->error_message; 238 << position->error_message;
248 } 239 }
249 240
250 void GetLocationFromResponse(bool http_post_result, 241 void GetLocationFromResponse(bool http_post_result,
251 int status_code, 242 int status_code,
252 const std::string& response_body, 243 const std::string& response_body,
(...skipping 29 matching lines...) Expand all
282 FormatPositionError(server_url, 273 FormatPositionError(server_url,
283 "Did not provide a good position fix", position); 274 "Did not provide a good position fix", position);
284 return; 275 return;
285 } 276 }
286 } 277 }
287 278
288 // Numeric values without a decimal point have type integer and IsDouble() will 279 // Numeric values without a decimal point have type integer and IsDouble() will
289 // return false. This is convenience function for detecting integer or floating 280 // return false. This is convenience function for detecting integer or floating
290 // point numeric values. Note that isIntegral() includes boolean values, which 281 // point numeric values. Note that isIntegral() includes boolean values, which
291 // is not what we want. 282 // is not what we want.
292 bool GetAsDouble(const DictionaryValue& object, 283 bool GetAsDouble(const base::DictionaryValue& object,
293 const std::string& property_name, 284 const std::string& property_name,
294 double* out) { 285 double* out) {
295 DCHECK(out); 286 DCHECK(out);
296 const Value* value = NULL; 287 const Value* value = NULL;
297 if (!object.Get(property_name, &value)) 288 if (!object.Get(property_name, &value))
298 return false; 289 return false;
299 int value_as_int; 290 int value_as_int;
300 DCHECK(value); 291 DCHECK(value);
301 if (value->GetAsInteger(&value_as_int)) { 292 if (value->GetAsInteger(&value_as_int)) {
302 *out = value_as_int; 293 *out = value_as_int;
(...skipping 26 matching lines...) Expand all
329 LOG(WARNING) << "ParseServerResponse() : JSONReader failed : " 320 LOG(WARNING) << "ParseServerResponse() : JSONReader failed : "
330 << error_msg; 321 << error_msg;
331 return false; 322 return false;
332 } 323 }
333 324
334 if (!response_value->IsType(Value::TYPE_DICTIONARY)) { 325 if (!response_value->IsType(Value::TYPE_DICTIONARY)) {
335 VLOG(1) << "ParseServerResponse() : Unexpected response type " 326 VLOG(1) << "ParseServerResponse() : Unexpected response type "
336 << response_value->GetType(); 327 << response_value->GetType();
337 return false; 328 return false;
338 } 329 }
339 const DictionaryValue* response_object = 330 const base::DictionaryValue* response_object =
340 static_cast<DictionaryValue*>(response_value.get()); 331 static_cast<base::DictionaryValue*>(response_value.get());
341
342 // Check the status code.
343 const Value* status_value = NULL;
344 if (!response_object->Get(kStatusString, &status_value)) {
345 VLOG(1) << "ParseServerResponse() : Missing status attribute.";
346 // The status attribute is required.
347 return false;
348 }
349 DCHECK(status_value);
350
351 if (!status_value->IsType(Value::TYPE_STRING)) {
352 VLOG(1) << "ParseServerResponse() : Unexpected status type "
353 << status_value->GetType();
354 // The status attribute is required to be a string.
355 return false;
356 }
357 const StringValue* status_object =
358 static_cast<const StringValue*>(status_value);
359
360 std::string status;
361 if (!status_object->GetAsString(&status)) {
362 VLOG(1) << "ParseServerResponse() : Error parsing the status value.";
363 return false;
364 }
365
366 if (status != kStatusOKString) {
367 VLOG(1) << "ParseServerResponse() : Request failed with status "
368 << status;
369 return false;
370 }
371 332
372 // Get the access token, if any. 333 // Get the access token, if any.
373 response_object->GetString(kAccessTokenString, access_token); 334 response_object->GetString(kAccessTokenString, access_token);
374 335
375 // Get the location 336 // Get the location
376 const Value* location_value = NULL; 337 const Value* location_value = NULL;
377 if (!response_object->Get(kLocationString, &location_value)) { 338 if (!response_object->Get(kLocationString, &location_value)) {
378 VLOG(1) << "ParseServerResponse() : Missing location attribute."; 339 VLOG(1) << "ParseServerResponse() : Missing location attribute.";
379 // GLS returns a response with no location property to represent 340 // GLS returns a response with no location property to represent
380 // no fix available; return true to indicate successful parse. 341 // no fix available; return true to indicate successful parse.
381 return true; 342 return true;
382 } 343 }
383 DCHECK(location_value); 344 DCHECK(location_value);
384 345
385 if (!location_value->IsType(Value::TYPE_DICTIONARY)) { 346 if (!location_value->IsType(Value::TYPE_DICTIONARY)) {
386 if (!location_value->IsType(Value::TYPE_NULL)) { 347 if (!location_value->IsType(Value::TYPE_NULL)) {
387 VLOG(1) << "ParseServerResponse() : Unexpected location type " 348 VLOG(1) << "ParseServerResponse() : Unexpected location type "
388 << location_value->GetType(); 349 << location_value->GetType();
389 // If the network provider was unable to provide a position fix, it should 350 // If the network provider was unable to provide a position fix, it should
390 // return a HTTP 200, with "location" : null. Otherwise it's an error. 351 // return a HTTP 200, with "location" : null. Otherwise it's an error.
391 return false; 352 return false;
392 } 353 }
393 return true; // Successfully parsed response containing no fix. 354 return true; // Successfully parsed response containing no fix.
394 } 355 }
395 const DictionaryValue* location_object = 356 const base::DictionaryValue* location_object =
396 static_cast<const DictionaryValue*>(location_value); 357 static_cast<const base::DictionaryValue*>(location_value);
397 358
398 // latitude and longitude fields are always required. 359 // latitude and longitude fields are always required.
399 double latitude, longitude; 360 double latitude, longitude;
400 if (!GetAsDouble(*location_object, kLatitudeString, &latitude) || 361 if (!GetAsDouble(*location_object, kLatitudeString, &latitude) ||
401 !GetAsDouble(*location_object, kLongitudeString, &longitude)) { 362 !GetAsDouble(*location_object, kLongitudeString, &longitude)) {
402 VLOG(1) << "ParseServerResponse() : location lacks lat and/or long."; 363 VLOG(1) << "ParseServerResponse() : location lacks lat and/or long.";
403 return false; 364 return false;
404 } 365 }
405 // All error paths covered: now start actually modifying postion. 366 // All error paths covered: now start actually modifying postion.
406 position->latitude = latitude; 367 position->latitude = latitude;
407 position->longitude = longitude; 368 position->longitude = longitude;
408 position->timestamp = timestamp; 369 position->timestamp = timestamp;
409 370
410 // Other fields are optional. 371 // Other fields are optional.
411 GetAsDouble(*response_object, kAccuracyString, &position->accuracy); 372 GetAsDouble(*response_object, kAccuracyString, &position->accuracy);
412 373
413 return true; 374 return true;
414 } 375 }
415 376
416 } // namespace 377 } // namespace
378
OLDNEW
« no previous file with comments | « content/browser/geolocation/network_location_provider_unittest.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698