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

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

Issue 552250: Port the gears geolocation network provider to Chromium... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 10 years, 10 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
OLDNEW
1 // Copyright 2008, Google Inc. 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // 2 // Use of this source code is governed by a BSD-style license that can be
3 // Redistribution and use in source and binary forms, with or without 3 // found in the LICENSE file.
4 // modification, are permitted provided that the following conditions are met: 4
5 // 5 #include "chrome/browser/geolocation/network_location_request.h"
6 // 1. Redistributions of source code must retain the above copyright notice, 6
7 // this list of conditions and the following disclaimer. 7 #include "base/json/json_reader.h"
8 // 2. Redistributions in binary form must reproduce the above copyright notice, 8 #include "base/json/json_writer.h"
9 // this list of conditions and the following disclaimer in the documentation 9 #include "base/string_util.h"
10 // and/or other materials provided with the distribution. 10 #include "base/values.h"
11 // 3. Neither the name of Google Inc. nor the names of its contributors may be 11 #include "chrome/browser/geolocation/geoposition.h"
12 // used to endorse or promote products derived from this software without 12 #include "chrome/browser/net/url_request_context_getter.h"
13 // specific prior written permission. 13 #include "net/url_request/url_request_status.h"
14 // 14
15 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 15 namespace {
16 // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 16 const char* const kMimeApplicationJson = "application/json";
17 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 17
18 // EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 18 // See http://code.google.com/apis/gears/geolocation_network_protocol.html
19 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 const char* kGeoLocationNetworkProtocolVersion = "1.1.0";
20 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 20
21 // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 21 const wchar_t* kAccessTokenString = L"access_token";
22 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 22 const wchar_t* kLocationString = L"location";
23 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 23 const wchar_t* kLatitudeString = L"latitude";
24 // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 const wchar_t* kLongitudeString = L"longitude";
25 25 const wchar_t* kAltitudeString = L"altitude";
26 // TODO(joth): port to chromium 26 const wchar_t* kAccuracyString = L"accuracy";
27 #if 0 27 const wchar_t* kAltitudeAccuracyString = L"altitude_accuracy";
28 28
29 #include "gears/geolocation/network_location_request.h"
30
31 #include "gears/blob/blob_utils.h"
32 #include "gears/blob/buffer_blob.h"
33 #include "gears/localserver/common/http_constants.h"
34 #include "third_party/jsoncpp/reader.h"
35 #include "third_party/jsoncpp/value.h"
36 #include "third_party/jsoncpp/writer.h"
37
38 static const char *kGearsNetworkLocationProtocolVersion = "1.1.0";
39
40 static const char *kAccessTokenString = "access_token";
41 static const char *kLatitudeString = "latitude";
42 static const char *kLongitudeString = "longitude";
43 static const char *kAltitudeString = "altitude";
44 static const char *kAccuracyString = "accuracy";
45 static const char *kAltitudeAccuracyString = "altitude_accuracy";
46 // Note that the corresponding JavaScript Position property is 'gearsAddress'.
47 static const char *kAddressString = "address";
48 static const char *kStreetNumberString = "street_number";
49 static const char *kStreetString = "street";
50 static const char *kPremisesString = "premises";
51 static const char *kCityString = "city";
52 static const char *kCountyString = "county";
53 static const char *kRegionString = "region";
54 static const char *kCountryString = "country";
55 static const char *kCountryCodeString = "country_code";
56 static const char *kPostalCodeString = "postal_code";
57
58 // Local functions 29 // Local functions
59 static const char16* RadioTypeToString(RadioType type); 30 // Creates the request payload to send to the server.
31 bool FormRequestBody(const string16& host_name,
32 const string16& access_token,
33 const RadioData& radio_data,
34 const WifiData& wifi_data,
35 std::string* data);
36 // Parsers the server response.
37 void GetLocationFromResponse(bool http_post_result,
38 int status_code,
39 const std::string& response_body,
40 int64 timestamp,
41 const GURL& server_url,
42 Position* position,
43 string16* access_token);
44
45 const char* RadioTypeToString(RadioType type);
60 // Adds a string if it's valid to the JSON object. 46 // Adds a string if it's valid to the JSON object.
61 static void AddString(const std::string &property_name, 47 void AddString(const std::wstring& property_name,
62 const std::string16 &value, 48 const string16& value,
63 Json::Value *object); 49 DictionaryValue* object);
64 // Adds an integer if it's valid to the JSON object. 50 // Adds an integer if it's valid to the JSON object.
65 static void AddInteger(const std::string &property_name, 51 void AddInteger(const std::wstring& property_name,
66 const int &value, 52 int value,
67 Json::Value *object); 53 DictionaryValue* object);
68 // Returns true if the value is a valid angle.
69 static bool IsValidAngle(const double &value);
70 // Parses the server response body. Returns true if parsing was successful. 54 // Parses the server response body. Returns true if parsing was successful.
71 static bool ParseServerResponse(const std::string &response_body, 55 bool ParseServerResponse(const std::string& response_body,
72 int64 timestamp, 56 int64 timestamp,
73 bool is_reverse_geocode, 57 Position* position,
74 Position *position, 58 string16* access_token);
75 std::string16 *access_token); 59 void AddRadioData(const RadioData& radio_data, DictionaryValue* body_object);
76 static void AddRadioData(const RadioData &radio_data, Json::Value *body_object); 60 void AddWifiData(const WifiData& wifi_data, DictionaryValue* body_object);
77 static void AddWifiData(const WifiData &wifi_data, Json::Value *body_object); 61 } // namespace
78 62
79 // static 63 NetworkLocationRequest::NetworkLocationRequest(URLRequestContextGetter* context,
80 NetworkLocationRequest *NetworkLocationRequest::Create( 64 const GURL& url,
81 BrowsingContext *browsing_context, 65 const string16& host_name,
82 const std::string16 &url, 66 ListenerInterface* listener)
83 const std::string16 &host_name, 67 : url_context_(context), timestamp_(kint64min), listener_(listener),
84 ListenerInterface *listener) { 68 url_(url), host_name_(host_name) {
85 scoped_ptr<NetworkLocationRequest> request( 69 // DCHECK(url_context_);
86 new NetworkLocationRequest(browsing_context, url, host_name, listener)); 70 DCHECK(listener);
87 assert(request.get()); 71 }
88 if (!request.get() || !request->Init() || !request->Start()) { 72
89 return NULL; 73 NetworkLocationRequest::~NetworkLocationRequest() {
90 } 74 }
91 return request.release(); 75
92 } 76 bool NetworkLocationRequest::MakeRequest(const string16& access_token,
93 77 const RadioData& radio_data,
94 NetworkLocationRequest::NetworkLocationRequest( 78 const WifiData& wifi_data,
95 BrowsingContext *browsing_context,
96 const std::string16 &url,
97 const std::string16 &host_name,
98 ListenerInterface *listener)
99 : AsyncTask(browsing_context),
100 listener_(listener),
101 url_(url),
102 host_name_(host_name),
103 is_shutting_down_(false) {
104 }
105
106 bool NetworkLocationRequest::MakeRequest(const std::string16 &access_token,
107 const RadioData &radio_data,
108 const WifiData &wifi_data,
109 bool request_address,
110 const std::string16 &address_language,
111 double latitude,
112 double longitude,
113 int64 timestamp) { 79 int64 timestamp) {
114 is_reverse_geocode_ = request_address && 80 if (url_fetcher_ != NULL) {
115 IsValidAngle(latitude) && 81 DLOG(INFO) << "NetworkLocationRequest : Cancelling pending request";
116 IsValidAngle(longitude); 82 url_fetcher_.reset();
83 }
84 std::string post_body;
117 if (!FormRequestBody(host_name_, access_token, radio_data, wifi_data, 85 if (!FormRequestBody(host_name_, access_token, radio_data, wifi_data,
118 request_address, address_language, latitude, longitude, 86 &post_body)) {
119 is_reverse_geocode_, &post_body_)) {
120 return false; 87 return false;
121 } 88 }
122 timestamp_ = timestamp; 89 timestamp_ = timestamp;
123 90
124 thread_event_.Signal(); 91 url_fetcher_.reset(URLFetcher::Create(
92 host_name_.size(), // Used for testing
93 url_, URLFetcher::POST, this));
94 url_fetcher_->set_upload_data(kMimeApplicationJson, post_body);
95 url_fetcher_->set_request_context(url_context_);
96 url_fetcher_->Start();
125 return true; 97 return true;
126 } 98 }
127 99
128 // AsyncTask implementation. 100 void NetworkLocationRequest::OnURLFetchComplete(const URLFetcher* source,
129 void NetworkLocationRequest::Run() { 101 const GURL& url,
130 while (true) { 102 const URLRequestStatus& status,
131 thread_event_.Wait(); 103 int response_code,
132 if (is_shutting_down_) { 104 const ResponseCookies& cookies,
133 break; 105 const std::string& data) {
134 } 106 DCHECK_EQ(url_fetcher_.get(), source);
135 MakeRequestImpl(); 107 DCHECK(url_.possibly_invalid_spec() == url.possibly_invalid_spec());
136 } 108
137 } 109 Position position;
138 110 string16 access_token;
139 void NetworkLocationRequest::MakeRequestImpl() { 111 GetLocationFromResponse(status.is_success(), response_code, data,
140 WebCacheDB::PayloadInfo payload; 112 timestamp_, url, &position, &access_token);
141 // TODO(andreip): remove this once WebCacheDB::PayloadInfo.data is a Blob. 113 const bool server_error =
142 scoped_refptr<BlobInterface> payload_data; 114 !status.is_success() || (response_code >= 500 && response_code < 600);
143 bool result = HttpPost(url_.c_str(), 115 url_fetcher_.reset();
144 false, // Not capturing, so follow redirects 116
145 NULL, // reason_header_value 117 DCHECK(listener_);
146 HttpConstants::kMimeApplicationJson, // Content-Type 118 DLOG(INFO) << "NetworkLocationRequest::Run() : "
147 NULL, // mod_since_date 119 "Calling listener with position.\n";
148 NULL, // required_cookie 120 listener_->LocationResponseAvailable(position, server_error, access_token);
149 true, // disable_browser_cookies 121 }
150 post_body_.get(), 122
151 &payload, 123 // Local functions.
152 &payload_data, 124 namespace {
153 NULL, // was_redirected 125
154 NULL, // full_redirect_url 126 bool FormRequestBody(const string16& host_name,
155 NULL); // error_message 127 const string16& access_token,
156 128 const RadioData& radio_data,
157 MutexLock lock(&is_processing_response_mutex_); 129 const WifiData& wifi_data,
158 // is_aborted_ may be true even if HttpPost succeeded. 130 std::string* data) {
159 if (is_aborted_) { 131 DCHECK(data);
160 LOG(("NetworkLocationRequest::Run() : HttpPost request was cancelled.\n")); 132
161 return; 133 DictionaryValue body_object;
162 }
163
164 if (listener_) {
165 Position position;
166 std::string response_body;
167 if (result) {
168 // If HttpPost succeeded, payload_data is guaranteed to be non-NULL.
169 assert(payload_data.get());
170 if (!payload_data->Length() ||
171 !BlobToString(payload_data.get(), &response_body)) {
172 LOG(("NetworkLocationRequest::Run() : Failed to get response body.\n"));
173 }
174 }
175 std::string16 access_token;
176 GetLocationFromResponse(result, payload.status_code, response_body,
177 timestamp_, url_, is_reverse_geocode_,
178 &position, &access_token);
179
180 LOG(("NetworkLocationRequest::Run() : Calling listener with position.\n"));
181 bool server_error =
182 !result || (payload.status_code >= 500 && payload.status_code < 600);
183 listener_->LocationResponseAvailable(position, server_error, access_token);
184 }
185 }
186
187 // static
188 bool NetworkLocationRequest::FormRequestBody(
189 const std::string16 &host_name,
190 const std::string16 &access_token,
191 const RadioData &radio_data,
192 const WifiData &wifi_data,
193 bool request_address,
194 std::string16 address_language,
195 double latitude,
196 double longitude,
197 bool is_reverse_geocode,
198 scoped_refptr<BlobInterface> *blob) {
199 assert(blob);
200 Json::Value body_object;
201 assert(body_object.isObject());
202 // Version and host are required. 134 // Version and host are required.
203 if (host_name.empty()) { 135 if (host_name.empty()) {
204 return false; 136 return false;
205 } 137 }
206 body_object["version"] = Json::Value(kGearsNetworkLocationProtocolVersion); 138 body_object.SetString(L"version", kGeoLocationNetworkProtocolVersion);
207 AddString("host", host_name, &body_object); 139 AddString(L"host", host_name, &body_object);
208 140
209 AddString("access_token", access_token, &body_object); 141 AddString(L"access_token", access_token, &body_object);
210 142
211 body_object["request_address"] = request_address; 143 body_object.SetBoolean(L"request_address", false);
212 AddString("address_language", address_language, &body_object); 144
213 145 AddRadioData(radio_data, &body_object);
214 if (is_reverse_geocode) { 146 AddWifiData(wifi_data, &body_object);
215 assert(request_address); 147
216 assert(IsValidAngle(latitude) && IsValidAngle(longitude)); 148 // TODO(joth): Do we need to mess with locales?
217 Json::Value location;
218 location["latitude"] = Json::Value(latitude);
219 location["longitude"] = Json::Value(longitude);
220 body_object["location"] = location;
221 } else {
222 AddRadioData(radio_data, &body_object);
223 AddWifiData(wifi_data, &body_object);
224 }
225
226 Json::FastWriter writer;
227 // We always use the platform independent 'C' locale when writing the JSON 149 // We always use the platform independent 'C' locale when writing the JSON
228 // request, irrespective of the browser's locale. This avoids the need for 150 // request, irrespective of the browser's locale. This avoids the need for
229 // the network location provider to determine the locale of the request and 151 // the network location provider to determine the locale of the request and
230 // parse the JSON accordingly. 152 // parse the JSON accordingly.
231 #ifdef OS_WINCE 153 // char* current_locale = setlocale(LC_NUMERIC, "C");
232 // WinCE does not support setlocale. 154
233 #else 155 base::JSONWriter::Write(&body_object, false, data);
234 char *current_locale = setlocale(LC_NUMERIC, "C"); 156
235 #endif 157 // setlocale(LC_NUMERIC, current_locale);
236 std::string body_string = writer.write(body_object); 158
237 #ifdef OS_WINCE 159 DLOG(INFO) << "NetworkLocationRequest::FormRequestBody(): Formed body "
238 // WinCE does not support setlocale. 160 << data << ".\n";
239 #else
240 setlocale(LC_NUMERIC, current_locale);
241 #endif
242 LOG(("NetworkLocationRequest::FormRequestBody(): Formed body %s.\n",
243 body_string.c_str()));
244
245 blob->reset(new BufferBlob(body_string.c_str(), body_string.size()));
246 return true; 161 return true;
247 } 162 }
248 163
249 // static 164 void FormatPositionError(const GURL& server_url,
250 void NetworkLocationRequest::GetLocationFromResponse( 165 const std::wstring& message,
251 bool http_post_result, 166 Position* position) {
252 int status_code, 167 position->error_code = Position::ERROR_CODE_POSITION_UNAVAILABLE;
253 const std::string &response_body, 168 position->error_message = L"Network location provider at '";
254 int64 timestamp, 169 position->error_message += ASCIIToWide(server_url.possibly_invalid_spec());
255 const std::string16 &server_url, 170 position->error_message += L"' : ";
256 bool is_reverse_geocode, 171 position->error_message += message;
257 Position *position, 172 position->error_message += L".";
258 std::string16 *access_token) { 173 LOG(INFO) << "NetworkLocationRequest::GetLocationFromResponse() : "
259 assert(position); 174 << position->error_message;
260 assert(access_token); 175 }
176
177 void GetLocationFromResponse(bool http_post_result,
178 int status_code,
179 const std::string& response_body,
180 int64 timestamp,
181 const GURL& server_url,
182 Position* position,
183 string16* access_token) {
184 DCHECK(position);
185 DCHECK(access_token);
261 186
262 // HttpPost can fail for a number of reasons. Most likely this is because 187 // HttpPost can fail for a number of reasons. Most likely this is because
263 // we're offline, or there was no response. 188 // we're offline, or there was no response.
264 if (!http_post_result) { 189 if (!http_post_result) {
265 LOG(("NetworkLocationRequest::GetLocationFromResponse() : HttpPost request " 190 FormatPositionError(server_url, L"No response received", position);
266 "failed.\n")); 191 return;
267 position->error_code = Position::ERROR_CODE_POSITION_UNAVAILABLE; 192 }
268 position->error_message = STRING16(L"No response from network provider " 193 if (status_code != 200) { // XXX is '200' in a constant? Can't see it
269 L"at ");
270 position->error_message += server_url.c_str();
271 position->error_message += STRING16(L".");
272 } else if (status_code == HttpConstants::HTTP_OK) {
273 // We use the timestamp from the device data that was used to generate
274 // this position fix.
275 if (ParseServerResponse(response_body, timestamp, is_reverse_geocode,
276 position, access_token)) {
277 // The response was successfully parsed, but it may not be a valid
278 // position fix.
279 if (!position->IsGoodFix()) {
280 position->error_code = Position::ERROR_CODE_POSITION_UNAVAILABLE;
281 position->error_message = STRING16(L"Network provider at ");
282 position->error_message += server_url.c_str();
283 position->error_message += STRING16(L" did not provide a good position "
284 L"fix.");
285 }
286 } else {
287 // We failed to parse the repsonse.
288 LOG(("NetworkLocationRequest::GetLocationFromResponse() : Response "
289 "malformed.\n"));
290 position->error_code = Position::ERROR_CODE_POSITION_UNAVAILABLE;
291 position->error_message = STRING16(L"Response from network provider at ");
292 position->error_message += server_url.c_str();
293 position->error_message += STRING16(L" was malformed.");
294 }
295 } else {
296 // The response was bad. 194 // The response was bad.
297 LOG(("NetworkLocationRequest::GetLocationFromResponse() : HttpPost " 195 std::wstring message = L"Returned error code ";
298 "response was bad.\n")); 196 message += IntToWString(status_code);
299 position->error_code = Position::ERROR_CODE_POSITION_UNAVAILABLE; 197 FormatPositionError(server_url, message, position);
300 position->error_message = STRING16(L"Network provider at "); 198 return;
301 position->error_message += server_url.c_str(); 199 }
302 position->error_message += STRING16(L" returned error code "); 200 // We use the timestamp from the device data that was used to generate
303 position->error_message += IntegerToString16(status_code); 201 // this position fix.
304 position->error_message += STRING16(L"."); 202 if (!ParseServerResponse(response_body, timestamp, position, access_token)) {
305 } 203 // We failed to parse the repsonse.
306 } 204 FormatPositionError(server_url, L"Response was malformed", position);
307 205 return;
308 void NetworkLocationRequest::StopThreadAndDelete() { 206 }
309 // The FF implementation of AsyncTask::Abort() delivers a message to the UI 207 // The response was successfully parsed, but it may not be a valid
310 // thread to cancel the request. So if we call this method on the UI thread, 208 // position fix.
311 // we must return to the OS before the call to Abort() will take effect. In 209 if (!position->IsValidFix()) {
312 // particular, we can't call Abort() then block here waiting for HttpPost to 210 FormatPositionError(server_url,
313 // return. 211 L"Did not provide a good position fix", position);
314 is_shutting_down_ = true; 212 return;
315 thread_event_.Signal(); 213 }
316 is_processing_response_mutex_.Lock(); 214 }
317 Abort(); 215
318 is_processing_response_mutex_.Unlock(); 216 const char* RadioTypeToString(RadioType type) {
319 DeleteWhenDone();
320 }
321
322 // Local functions.
323
324 static const char16* RadioTypeToString(RadioType type) {
325 switch (type) { 217 switch (type) {
326 case RADIO_TYPE_UNKNOWN: 218 case RADIO_TYPE_UNKNOWN:
327 return STRING16(L"unknown"); 219 break;
328 case RADIO_TYPE_GSM: 220 case RADIO_TYPE_GSM:
329 return STRING16(L"gsm"); 221 return "gsm";
330 case RADIO_TYPE_CDMA: 222 case RADIO_TYPE_CDMA:
331 return STRING16(L"cdma"); 223 return "cdma";
332 case RADIO_TYPE_WCDMA: 224 case RADIO_TYPE_WCDMA:
333 return STRING16(L"wcdma"); 225 return "wcdma";
334 default: 226 default:
335 assert(false); 227 LOG(DFATAL) << "Bad RadioType";
336 } 228 }
337 return NULL; 229 return "unknown";
338 } 230 }
339 231
340 static void AddString(const std::string &property_name, 232 void AddString(const std::wstring& property_name,
341 const std::string16 &value, 233 const string16& value,
342 Json::Value *object) { 234 DictionaryValue* object) {
343 assert(object); 235 DCHECK(object);
344 assert(object->isObject());
345 if (!value.empty()) { 236 if (!value.empty()) {
346 std::string value_utf8; 237 object->SetStringFromUTF16(property_name, value);
347 if (String16ToUTF8(value.c_str(), value.size(), &value_utf8)) { 238 }
348 (*object)[property_name] = Json::Value(value_utf8); 239 }
349 } 240
350 } 241 void AddInteger(const std::wstring& property_name,
351 } 242 int value,
352 243 DictionaryValue* object) {
353 static void AddInteger(const std::string &property_name, 244 DCHECK(object);
354 const int &value,
355 Json::Value *object) {
356 assert(object);
357 assert(object->isObject());
358 if (kint32min != value) { 245 if (kint32min != value) {
359 (*object)[property_name] = Json::Value(value); 246 object->SetInteger(property_name, value);
360 } 247 }
361 }
362
363 static bool IsValidAngle(const double &value) {
364 return value >= -180.0 && value <= 180.0;
365 } 248 }
366 249
367 // Numeric values without a decimal point have type integer and IsDouble() will 250 // Numeric values without a decimal point have type integer and IsDouble() will
368 // return false. This is convenience function for detecting integer or floating 251 // return false. This is convenience function for detecting integer or floating
369 // point numeric values. Note that isIntegral() includes boolean values, which 252 // point numeric values. Note that isIntegral() includes boolean values, which
370 // is not what we want. 253 // is not what we want.
371 static bool IsDoubleOrInt(const Json::Value &object, 254 bool GetAsDouble(const DictionaryValue& object,
372 const std::string &property_name) { 255 const std::wstring& property_name,
373 return object[property_name].isDouble() || object[property_name].isInt(); 256 double* out) {
374 } 257 DCHECK(out);
375 258 Value* value = NULL;
376 // The JsValue::asXXX() methods return zero if a property isn't specified. For 259 if (!object.Get(property_name, &value))
377 // our purposes, zero is a valid value, so we have to test for existence. 260 return false;
378 261 int value_as_int;
379 // Gets a double if it's present. 262 DCHECK(value);
380 static bool GetAsDouble(const Json::Value &object, 263 if (value->GetAsInteger(&value_as_int)) {
381 const std::string &property_name, 264 *out = value_as_int;
382 double *out) { 265 return true;
383 assert(out); 266 }
384 if (!IsDoubleOrInt(object, property_name)) { 267 return value->GetAsReal(out);
385 return false; 268 }
386 } 269
387 *out = object[property_name].asDouble(); 270 bool ParseServerResponse(const std::string& response_body,
271 int64 timestamp,
272 Position* position,
273 string16* access_token) {
274 DCHECK(position);
275 DCHECK(access_token);
276 DCHECK(timestamp != kint64min);
277
278 if (response_body.empty()) {
279 LOG(WARNING) << "ParseServerResponse() : Response was empty.\n";
280 return false;
281 }
282 DLOG(INFO) << "ParseServerResponse() : Parsing response "
283 << response_body << ".\n";
284
285 // Parse the response, ignoring comments.
286 // TODO(joth): Gears version stated: The JSON reponse from the network
287 // location provider should always use the 'C' locale.
288 // Chromium JSON parser works in UTF8 so hopefully we can ignore setlocale?
289
290 // char* current_locale = setlocale(LC_NUMERIC, "C");
291 std::string error_msg;
292 scoped_ptr<Value> response_value(base::JSONReader::ReadAndReturnError(
293 response_body, false, &error_msg));
294
295 // setlocale(LC_NUMERIC, current_locale);
296
297 if (response_value == NULL) {
298 LOG(WARNING) << "ParseServerResponse() : JSONReader failed : "
299 << error_msg << ".\n";
300 return false;
301 }
302
303 if (!response_value->IsType(Value::TYPE_DICTIONARY)) {
304 LOG(INFO) << "ParseServerResponse() : Unexpected resopnse type "
305 << response_value->GetType() << ".\n";
306 return false;
307 }
308 const DictionaryValue* response_object =
309 static_cast<DictionaryValue*>(response_value.get());
310
311 // Get the access token, if any.
312 response_object->GetStringAsUTF16(kAccessTokenString, access_token);
313
314 // Get the location
315 DictionaryValue* location_object;
316 if (!response_object->GetDictionary(kLocationString, &location_object)) {
317 Value* value = NULL;
318 // If the network provider was unable to provide a position fix, it should
319 // return a 200 with location == null. Otherwise it's an error.
320 return response_object->Get(kLocationString, &value)
321 && value && value->IsType(Value::TYPE_NULL);
322 }
323 DCHECK(location_object);
324
325 // latitude and longitude fields are always required.
326 double latitude, longitude;
327 if (!GetAsDouble(*location_object, kLatitudeString, &latitude) ||
328 !GetAsDouble(*location_object, kLongitudeString, &longitude)) {
329 return false;
330 }
331 // All error paths covered: now start actually modifying postion.
332 position->latitude = latitude;
333 position->longitude = longitude;
334 position->timestamp = timestamp;
335
336 // Other fields are optional.
337 GetAsDouble(*location_object, kAccuracyString, &position->accuracy);
338 GetAsDouble(*location_object, kAltitudeString, &position->altitude);
339 GetAsDouble(*location_object, kAltitudeAccuracyString,
340 &position->altitude_accuracy);
341
388 return true; 342 return true;
389 } 343 }
390 344
391 // Gets a string if it's present. 345 void AddRadioData(const RadioData& radio_data, DictionaryValue* body_object) {
392 static bool GetAsString(const Json::Value &object, 346 DCHECK(body_object);
393 const std::string &property_name, 347
394 std::string16 *out) { 348 AddInteger(L"home_mobile_country_code", radio_data.home_mobile_country_code,
395 assert(out);
396 if (!object[property_name].isString()) {
397 return false;
398 }
399 std::string out_utf8 = object[property_name].asString();
400 return UTF8ToString16(out_utf8.c_str(), out_utf8.size(), out);
401 }
402
403 static bool ParseServerResponse(const std::string &response_body,
404 int64 timestamp,
405 bool is_reverse_geocode,
406 Position *position,
407 std::string16 *access_token) {
408 assert(position);
409 assert(access_token);
410
411 if (response_body.empty()) {
412 LOG(("ParseServerResponse() : Response was empty.\n"));
413 return false;
414 }
415 LOG(("ParseServerResponse() : Parsing response %s.\n",
416 response_body.c_str()));
417
418 // Parse the response, ignoring comments. The JSON reposne from the network
419 // location provider should always use the 'C' locale.
420 Json::Reader reader;
421 Json::Value response_object;
422 #ifdef OS_WINCE
423 // WinCE does not support setlocale.
424 #else
425 char *current_locale = setlocale(LC_NUMERIC, "C");
426 #endif
427 bool res = reader.parse(response_body, response_object, false);
428 #ifdef OS_WINCE
429 // WinCE does not support setlocale.
430 #else
431 setlocale(LC_NUMERIC, current_locale);
432 #endif
433 if (!res) {
434 LOG(("ParseServerResponse() : Failed to parse response : %s.\n",
435 reader.getFormatedErrorMessages().c_str()));
436 return false;
437 }
438
439 if (!response_object.isObject()) {
440 LOG(("ParseServerResponse() : Unexpected response type: %d.\n",
441 response_object.type()));
442 return false;
443 }
444
445 // Get the access token.
446 GetAsString(response_object, kAccessTokenString, access_token);
447
448 // Get the location
449 Json::Value location = response_object["location"];
450
451 // If the network provider was unable to provide a position fix, it should
452 // return a 200 with location == null.
453 if (location.type() == Json::nullValue) {
454 LOG(("ParseServerResponse() : Location is null.\n"));
455 return true;
456 }
457
458 // If location is not null, it must be an object.
459 if (!location.isObject()) {
460 return false;
461 }
462
463 // latitude and longitude fields are always required.
464 if (!GetAsDouble(location, kLatitudeString, &position->latitude) ||
465 !GetAsDouble(location, kLongitudeString, &position->longitude)) {
466 return false;
467 }
468
469 // If it's not a reverse geocode request, the accuracy field is also required.
470 if (is_reverse_geocode) {
471 position->accuracy = 0.0;
472 } else {
473 if (!GetAsDouble(location, kAccuracyString, &position->accuracy)) {
474 return false;
475 }
476 }
477
478 // Other fields are optional.
479 GetAsDouble(location, kAltitudeString, &position->altitude);
480 GetAsDouble(location, kAltitudeAccuracyString, &position->altitude_accuracy);
481 Json::Value address = location[kAddressString];
482 if (address.isObject()) {
483 GetAsString(address, kStreetNumberString, &position->address.street_number);
484 GetAsString(address, kStreetString, &position->address.street);
485 GetAsString(address, kPremisesString, &position->address.premises);
486 GetAsString(address, kCityString, &position->address.city);
487 GetAsString(address, kCountyString, &position->address.county);
488 GetAsString(address, kRegionString, &position->address.region);
489 GetAsString(address, kCountryString, &position->address.country);
490 GetAsString(address, kCountryCodeString, &position->address.country_code);
491 GetAsString(address, kPostalCodeString, &position->address.postal_code);
492 }
493
494 position->timestamp = timestamp;
495 return true;
496 }
497
498 static void AddRadioData(const RadioData &radio_data,
499 Json::Value *body_object) {
500 assert(body_object);
501
502 AddInteger("home_mobile_country_code", radio_data.home_mobile_country_code,
503 body_object); 349 body_object);
504 AddInteger("home_mobile_network_code", radio_data.home_mobile_network_code, 350 AddInteger(L"home_mobile_network_code", radio_data.home_mobile_network_code,
505 body_object); 351 body_object);
506 AddString("radio_type", RadioTypeToString(radio_data.radio_type), 352 AddString(L"radio_type",
353 ASCIIToUTF16(RadioTypeToString(radio_data.radio_type)),
507 body_object); 354 body_object);
508 AddString("carrier", radio_data.carrier, body_object); 355 AddString(L"carrier", radio_data.carrier, body_object);
509 356
510 Json::Value cell_towers; 357 const int num_cell_towers = static_cast<int>(radio_data.cell_data.size());
511 assert(cell_towers.isArray()); 358 if (num_cell_towers == 0) {
512 int num_cell_towers = static_cast<int>(radio_data.cell_data.size()); 359 return;
360 }
361 ListValue* cell_towers = new ListValue;
513 for (int i = 0; i < num_cell_towers; ++i) { 362 for (int i = 0; i < num_cell_towers; ++i) {
514 Json::Value cell_tower; 363 DictionaryValue* cell_tower = new DictionaryValue;
515 assert(cell_tower.isObject()); 364 AddInteger(L"cell_id", radio_data.cell_data[i].cell_id, cell_tower);
516 AddInteger("cell_id", radio_data.cell_data[i].cell_id, &cell_tower); 365 AddInteger(L"location_area_code",
517 AddInteger("location_area_code", radio_data.cell_data[i].location_area_code, 366 radio_data.cell_data[i].location_area_code, cell_tower);
518 &cell_tower); 367 AddInteger(L"mobile_country_code",
519 AddInteger("mobile_country_code", 368 radio_data.cell_data[i].mobile_country_code, cell_tower);
520 radio_data.cell_data[i].mobile_country_code, &cell_tower); 369 AddInteger(L"mobile_network_code",
521 AddInteger("mobile_network_code", 370 radio_data.cell_data[i].mobile_network_code, cell_tower);
522 radio_data.cell_data[i].mobile_network_code, &cell_tower); 371 AddInteger(L"age", radio_data.cell_data[i].age, cell_tower);
523 AddInteger("age", radio_data.cell_data[i].age, &cell_tower); 372 AddInteger(L"signal_strength",
524 AddInteger("signal_strength", radio_data.cell_data[i].radio_signal_strength, 373 radio_data.cell_data[i].radio_signal_strength, cell_tower);
525 &cell_tower); 374 AddInteger(L"timing_advance", radio_data.cell_data[i].timing_advance,
526 AddInteger("timing_advance", radio_data.cell_data[i].timing_advance, 375 cell_tower);
527 &cell_tower); 376 cell_towers->Append(cell_tower);
528 cell_towers[i] = cell_tower; 377 }
529 } 378 body_object->Set(L"cell_towers", cell_towers);
530 if (num_cell_towers > 0) { 379 }
531 (*body_object)["cell_towers"] = cell_towers; 380
532 } 381 void AddWifiData(const WifiData& wifi_data, DictionaryValue* body_object) {
533 } 382 DCHECK(body_object);
534
535 static void AddWifiData(const WifiData &wifi_data, Json::Value *body_object) {
536 assert(body_object);
537 383
538 if (wifi_data.access_point_data.empty()) { 384 if (wifi_data.access_point_data.empty()) {
539 return; 385 return;
540 } 386 }
541 387
542 Json::Value wifi_towers; 388 ListValue* wifi_towers = new ListValue;
543 assert(wifi_towers.isArray());
544 for (WifiData::AccessPointDataSet::const_iterator iter = 389 for (WifiData::AccessPointDataSet::const_iterator iter =
545 wifi_data.access_point_data.begin(); 390 wifi_data.access_point_data.begin();
546 iter != wifi_data.access_point_data.end(); 391 iter != wifi_data.access_point_data.end();
547 iter++) { 392 iter++) {
548 Json::Value wifi_tower; 393 DictionaryValue* wifi_tower = new DictionaryValue;
549 assert(wifi_tower.isObject()); 394 AddString(L"mac_address", iter->mac_address, wifi_tower);
550 AddString("mac_address", iter->mac_address, &wifi_tower); 395 AddInteger(L"signal_strength", iter->radio_signal_strength, wifi_tower);
551 AddInteger("signal_strength", iter->radio_signal_strength, &wifi_tower); 396 AddInteger(L"age", iter->age, wifi_tower);
552 AddInteger("age", iter->age, &wifi_tower); 397 AddInteger(L"channel", iter->channel, wifi_tower);
553 AddInteger("channel", iter->channel, &wifi_tower); 398 AddInteger(L"signal_to_noise", iter->signal_to_noise, wifi_tower);
554 AddInteger("signal_to_noise", iter->signal_to_noise, &wifi_tower); 399 AddString(L"ssid", iter->ssid, wifi_tower);
555 AddString("ssid", iter->ssid, &wifi_tower); 400 wifi_towers->Append(wifi_tower);
556 wifi_towers.append(wifi_tower); 401 }
557 } 402 body_object->Set(L"wifi_towers", wifi_towers);
558 (*body_object)["wifi_towers"] = wifi_towers; 403 }
559 } 404 } // namespace
560
561 #endif // if 0
OLDNEW
« no previous file with comments | « chrome/browser/geolocation/network_location_request.h ('k') | chrome/browser/geolocation/wifi_data_provider_unittest_win.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698