summaryrefslogtreecommitdiffstats
path: root/content/browser/geolocation/network_location_request.cc
diff options
context:
space:
mode:
authorallanwoj@chromium.org <allanwoj@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-08-31 11:08:19 +0000
committerallanwoj@chromium.org <allanwoj@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-08-31 11:08:19 +0000
commitabfb89d06c8062df02660aa4b4efbae1f5320823 (patch)
tree63f7bcc2df6a5ada50ae11f9e674bdf9e4da9026 /content/browser/geolocation/network_location_request.cc
parent569d127f862832145c979308ba1d2f4144d72bec (diff)
downloadchromium_src-abfb89d06c8062df02660aa4b4efbae1f5320823.zip
chromium_src-abfb89d06c8062df02660aa4b4efbae1f5320823.tar.gz
chromium_src-abfb89d06c8062df02660aa4b4efbae1f5320823.tar.bz2
Use new network location service protocol
Changed NetworkLocationRequest to point to the new Geolocation API. All data is now sent in the url as an HTTP GET. Altered unit tests to reflect this and removed a test fixture related to gateway data as this API does not support it. Further removal of gateway code to be done in a separate CL. BUG=http://b/5094774 TEST=--gtest_filter=GeolocationNetwork* Review URL: http://codereview.chromium.org/7718028 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@98954 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/browser/geolocation/network_location_request.cc')
-rw-r--r--content/browser/geolocation/network_location_request.cc302
1 files changed, 116 insertions, 186 deletions
diff --git a/content/browser/geolocation/network_location_request.cc b/content/browser/geolocation/network_location_request.cc
index deedc92..0199f12 100644
--- a/content/browser/geolocation/network_location_request.cc
+++ b/content/browser/geolocation/network_location_request.cc
@@ -4,39 +4,38 @@
#include "content/browser/geolocation/network_location_request.h"
+#include <set>
+
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "content/common/geoposition.h"
+#include "net/base/escape.h"
#include "net/base/load_flags.h"
#include "net/url_request/url_request_context_getter.h"
#include "net/url_request/url_request_status.h"
namespace {
-const char kMimeApplicationJson[] = "application/json";
-// See http://code.google.com/apis/gears/geolocation_network_protocol.html
-const char kGeoLocationNetworkProtocolVersion[] = "1.1.0";
+const size_t kMaxRequestLength = 2048;
const char kAccessTokenString[] = "access_token";
const char kLocationString[] = "location";
-const char kLatitudeString[] = "latitude";
-const char kLongitudeString[] = "longitude";
-const char kAltitudeString[] = "altitude";
+const char kLatitudeString[] = "lat";
+const char kLongitudeString[] = "lng";
const char kAccuracyString[] = "accuracy";
-const char kAltitudeAccuracyString[] = "altitude_accuracy";
+const char kStatusString[] = "status";
+const char kStatusOKString[] = "OK";
// Local functions
-// Creates the request payload to send to the server.
-void FormRequestBody(const std::string& host_name,
- const string16& access_token,
- const GatewayData& gateway_data,
- const RadioData& radio_data,
- const WifiData& wifi_data,
- const base::Time& timestamp,
- std::string* data);
+// Creates the request url to send to the server.
+GURL FormRequestURL(const std::string& url,
+ const string16& access_token,
+ const WifiData& wifi_data,
+ const base::Time& timestamp);
+
// Parsers the server response.
void GetLocationFromResponse(bool http_post_result,
int status_code,
@@ -46,15 +45,6 @@ void GetLocationFromResponse(bool http_post_result,
Geoposition* position,
string16* access_token);
-const char* RadioTypeToString(RadioType type);
-// Adds a string if it's valid to the JSON object.
-void AddString(const std::string& property_name,
- const string16& value,
- DictionaryValue* object);
-// Adds an integer if it's valid to the JSON object.
-void AddInteger(const std::string& property_name,
- int value,
- DictionaryValue* object);
// Parses the server response body. Returns true if parsing was successful.
// Sets |*position| to the parsed location if a valid fix was received,
// otherwise leaves it unchanged (i.e. IsInitialized() == false).
@@ -62,15 +52,9 @@ bool ParseServerResponse(const std::string& response_body,
const base::Time& timestamp,
Geoposition* position,
string16* access_token);
-void AddGatewayData(const GatewayData& gateway_data,
- int age_milliseconds,
- DictionaryValue* body_object);
-void AddRadioData(const RadioData& radio_data,
- int age_milliseconds,
- DictionaryValue* body_object);
void AddWifiData(const WifiData& wifi_data,
int age_milliseconds,
- DictionaryValue* body_object);
+ std::vector<std::string>* params);
} // namespace
int NetworkLocationRequest::url_fetcher_id_for_tests = 0;
@@ -101,18 +85,17 @@ bool NetworkLocationRequest::MakeRequest(const std::string& host_name,
radio_data_ = radio_data;
wifi_data_ = wifi_data;
timestamp_ = timestamp;
- std::string post_body;
- FormRequestBody(host_name, access_token, gateway_data, radio_data_,
- wifi_data_, timestamp_, &post_body);
+ GURL request_url = FormRequestURL(url_.spec(), access_token,
+ wifi_data, timestamp_);
url_fetcher_.reset(URLFetcher::Create(
- url_fetcher_id_for_tests, url_, URLFetcher::POST, this));
- url_fetcher_->set_upload_data(kMimeApplicationJson, post_body);
+ url_fetcher_id_for_tests, request_url, URLFetcher::GET, this));
url_fetcher_->set_request_context(url_context_);
url_fetcher_->set_load_flags(
net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE |
net::LOAD_DO_NOT_SAVE_COOKIES | net::LOAD_DO_NOT_SEND_COOKIES |
net::LOAD_DO_NOT_SEND_AUTH_DATA);
+
url_fetcher_->Start();
return true;
}
@@ -125,7 +108,6 @@ void NetworkLocationRequest::OnURLFetchComplete(
const net::ResponseCookies& cookies,
const std::string& data) {
DCHECK_EQ(url_fetcher_.get(), source);
- DCHECK(url_.possibly_invalid_spec() == url.possibly_invalid_spec());
Geoposition position;
string16 access_token;
@@ -144,27 +126,17 @@ void NetworkLocationRequest::OnURLFetchComplete(
// Local functions.
namespace {
-void FormRequestBody(const std::string& host_name,
- const string16& access_token,
- const GatewayData& gateway_data,
- const RadioData& radio_data,
- const WifiData& wifi_data,
- const base::Time& timestamp,
- std::string* data) {
- DCHECK(data);
-
- DictionaryValue body_object;
- // Version and host are required.
- COMPILE_ASSERT(sizeof(kGeoLocationNetworkProtocolVersion) > 1,
- must_include_valid_version);
- DCHECK(!host_name.empty());
- body_object.SetString("version", kGeoLocationNetworkProtocolVersion);
- body_object.SetString("host", host_name);
-
- AddString("access_token", access_token, &body_object);
-
- body_object.SetBoolean("request_address", false);
+struct AccessPointLess {
+ bool operator()(const AccessPointData* ap1,
+ const AccessPointData* ap2) const {
+ return ap2->radio_signal_strength < ap1->radio_signal_strength;
+ }
+};
+GURL FormRequestURL(const std::string& url,
+ const string16& access_token,
+ const WifiData& wifi_data,
+ const base::Time& timestamp) {
int age = kint32min; // Invalid so AddInteger() will ignore.
if (!timestamp.is_null()) {
// Convert absolute timestamps into a relative age.
@@ -172,13 +144,63 @@ void FormRequestBody(const std::string& host_name,
if (delta_ms >= 0 && delta_ms < kint32max)
age = static_cast<int>(delta_ms);
}
- AddRadioData(radio_data, age, &body_object);
- AddWifiData(wifi_data, age, &body_object);
- AddGatewayData(gateway_data, age, &body_object);
- base::JSONWriter::Write(&body_object, false, data);
- DVLOG(1) << "NetworkLocationRequest::FormRequestBody(): Formed body " << *data
- << ".";
+ std::vector<std::string> params;
+ params.push_back("browser=chromium");
+ params.push_back("sensor=true");
+ if (!access_token.empty())
+ params.push_back("token=" + UTF16ToUTF8(access_token));
+ AddWifiData(wifi_data, age, &params);
+
+ std::string request_string = url + '?' + JoinString(params, '&');
+ if (request_string.length() > kMaxRequestLength) {
+ size_t last_param_pos =
+ request_string.find_last_of('&', kMaxRequestLength);
+ CHECK_NE(std::string::npos, last_param_pos);
+ request_string.erase(last_param_pos);
+ }
+
+ return GURL(request_string);
+}
+
+void AddWifiData(const WifiData& wifi_data,
+ int age_milliseconds,
+ std::vector<std::string>* params) {
+ DCHECK(params);
+
+ if (wifi_data.access_point_data.empty())
+ return;
+
+ typedef std::multiset<const AccessPointData*, AccessPointLess> AccessPointSet;
+ AccessPointSet access_points_by_signal_strength;
+
+ for (WifiData::AccessPointDataSet::const_iterator iter =
+ wifi_data.access_point_data.begin();
+ iter != wifi_data.access_point_data.end();
+ ++iter) {
+ access_points_by_signal_strength.insert(&(*iter));
+ }
+
+ for (AccessPointSet::iterator iter =
+ access_points_by_signal_strength.begin();
+ iter != access_points_by_signal_strength.end();
+ ++iter) {
+ std::string wifi_params = "wifi=";
+ wifi_params += "mac:" +
+ EscapeQueryParamValue(UTF16ToUTF8((*iter)->mac_address), false);
+ wifi_params += "%7Css:" +
+ base::IntToString((*iter)->radio_signal_strength);
+ if (kint32min != age_milliseconds)
+ wifi_params += "%7Cage:" + base::IntToString(age_milliseconds);
+ wifi_params += "%7Cchan:" + base::IntToString((*iter)->channel);
+ wifi_params += "%7Csnr:" + base::IntToString((*iter)->signal_to_noise);
+ std::string ssid = UTF16ToUTF8((*iter)->ssid);
+ // Pipe characters in the ssid need backslash-escaping to avoid being
+ // interpreted as the wifi parameter separator.
+ ReplaceSubstringsAfterOffset(&ssid, 0, "|", "\\|");
+ wifi_params += "%7Cssid:" + EscapeQueryParamValue(ssid, false);
+ params->push_back(wifi_params);
+ }
}
void FormatPositionError(const GURL& server_url,
@@ -232,40 +254,6 @@ void GetLocationFromResponse(bool http_post_result,
}
}
-const char* RadioTypeToString(RadioType type) {
- switch (type) {
- case RADIO_TYPE_UNKNOWN:
- break;
- case RADIO_TYPE_GSM:
- return "gsm";
- case RADIO_TYPE_CDMA:
- return "cdma";
- case RADIO_TYPE_WCDMA:
- return "wcdma";
- default:
- LOG(DFATAL) << "Bad RadioType";
- }
- return "unknown";
-}
-
-void AddString(const std::string& property_name,
- const string16& value,
- DictionaryValue* object) {
- DCHECK(object);
- if (!value.empty()) {
- object->SetString(property_name, value);
- }
-}
-
-void AddInteger(const std::string& property_name,
- int value,
- DictionaryValue* object) {
- DCHECK(object);
- if (kint32min != value) {
- object->SetInteger(property_name, value);
- }
-}
-
// Numeric values without a decimal point have type integer and IsDouble() will
// return false. This is convenience function for detecting integer or floating
// point numeric values. Note that isIntegral() includes boolean values, which
@@ -312,13 +300,42 @@ bool ParseServerResponse(const std::string& response_body,
}
if (!response_value->IsType(Value::TYPE_DICTIONARY)) {
- VLOG(1) << "ParseServerResponse() : Unexpected resopnse type "
+ VLOG(1) << "ParseServerResponse() : Unexpected response type "
<< response_value->GetType();
return false;
}
const DictionaryValue* response_object =
static_cast<DictionaryValue*>(response_value.get());
+ // Check the status code.
+ Value* status_value = NULL;
+ if (!response_object->Get(kStatusString, &status_value)) {
+ VLOG(1) << "ParseServerResponse() : Missing status attribute.";
+ // The status attribute is required.
+ return false;
+ }
+ DCHECK(status_value);
+
+ if (!status_value->IsType(Value::TYPE_STRING)) {
+ VLOG(1) << "ParseServerResponse() : Unexpected status type "
+ << status_value->GetType();
+ // The status attribute is required to be a string.
+ return false;
+ }
+ StringValue* status_object = static_cast<StringValue*>(status_value);
+
+ std::string status;
+ if (!status_object->GetAsString(&status)) {
+ VLOG(1) << "ParseServerResponse() : Error parsing the status value.";
+ return false;
+ }
+
+ if (status != kStatusOKString) {
+ VLOG(1) << "ParseServerResponse() : Request failed with status "
+ << status;
+ return false;
+ }
+
// Get the access token, if any.
response_object->GetString(kAccessTokenString, access_token);
@@ -358,96 +375,9 @@ bool ParseServerResponse(const std::string& response_body,
position->timestamp = timestamp;
// Other fields are optional.
- GetAsDouble(*location_object, kAccuracyString, &position->accuracy);
- GetAsDouble(*location_object, kAltitudeString, &position->altitude);
- GetAsDouble(*location_object, kAltitudeAccuracyString,
- &position->altitude_accuracy);
+ GetAsDouble(*response_object, kAccuracyString, &position->accuracy);
return true;
}
-void AddRadioData(const RadioData& radio_data,
- int age_milliseconds,
- DictionaryValue* body_object) {
- DCHECK(body_object);
-
- AddInteger("home_mobile_country_code", radio_data.home_mobile_country_code,
- body_object);
- AddInteger("home_mobile_network_code", radio_data.home_mobile_network_code,
- body_object);
- AddString("radio_type",
- ASCIIToUTF16(RadioTypeToString(radio_data.radio_type)),
- body_object);
- AddString("carrier", radio_data.carrier, body_object);
-
- const int num_cell_towers = static_cast<int>(radio_data.cell_data.size());
- if (num_cell_towers == 0) {
- return;
- }
- ListValue* cell_towers = new ListValue;
- for (int i = 0; i < num_cell_towers; ++i) {
- DictionaryValue* cell_tower = new DictionaryValue;
- AddInteger("cell_id", radio_data.cell_data[i].cell_id, cell_tower);
- AddInteger("location_area_code",
- radio_data.cell_data[i].location_area_code, cell_tower);
- AddInteger("mobile_country_code",
- radio_data.cell_data[i].mobile_country_code, cell_tower);
- AddInteger("mobile_network_code",
- radio_data.cell_data[i].mobile_network_code, cell_tower);
- AddInteger("age", age_milliseconds, cell_tower);
- AddInteger("signal_strength",
- radio_data.cell_data[i].radio_signal_strength, cell_tower);
- AddInteger("timing_advance", radio_data.cell_data[i].timing_advance,
- cell_tower);
- cell_towers->Append(cell_tower);
- }
- body_object->Set("cell_towers", cell_towers);
-}
-
-void AddWifiData(const WifiData& wifi_data,
- int age_milliseconds,
- DictionaryValue* body_object) {
- DCHECK(body_object);
-
- if (wifi_data.access_point_data.empty()) {
- return;
- }
-
- ListValue* wifi_towers = new ListValue;
- for (WifiData::AccessPointDataSet::const_iterator iter =
- wifi_data.access_point_data.begin();
- iter != wifi_data.access_point_data.end();
- iter++) {
- DictionaryValue* wifi_tower = new DictionaryValue;
- AddString("mac_address", iter->mac_address, wifi_tower);
- AddInteger("signal_strength", iter->radio_signal_strength, wifi_tower);
- AddInteger("age", age_milliseconds, wifi_tower);
- AddInteger("channel", iter->channel, wifi_tower);
- AddInteger("signal_to_noise", iter->signal_to_noise, wifi_tower);
- AddString("ssid", iter->ssid, wifi_tower);
- wifi_towers->Append(wifi_tower);
- }
- body_object->Set("wifi_towers", wifi_towers);
-}
-
-void AddGatewayData(const GatewayData& gateway_data,
- int age_milliseconds,
- DictionaryValue* body_object) {
- DCHECK(body_object);
-
- if (gateway_data.router_data.empty()) {
- return;
- }
-
- ListValue* gateways = new ListValue;
- for (GatewayData::RouterDataSet::const_iterator iter =
- gateway_data.router_data.begin();
- iter != gateway_data.router_data.end();
- iter++) {
- DictionaryValue* gateway = new DictionaryValue;
- AddString("mac_address", iter->mac_address, gateway);
- gateways->Append(gateway);
- }
- body_object->Set("gateways", gateways);
-}
} // namespace