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

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

Issue 555148: Add more gears geolocaiton files into chromium: locaiton provider, network lo... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 10 years, 11 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 | « chrome/browser/geolocation/network_location_request.h ('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')
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 // Copyright 2008, Google Inc.
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are met:
5 //
6 // 1. Redistributions of source code must retain the above copyright notice,
7 // this list of conditions and the following disclaimer.
8 // 2. Redistributions in binary form must reproduce the above copyright notice,
9 // this list of conditions and the following disclaimer in the documentation
10 // and/or other materials provided with the distribution.
11 // 3. Neither the name of Google Inc. nor the names of its contributors may be
12 // used to endorse or promote products derived from this software without
13 // specific prior written permission.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
16 // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
17 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
18 // EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21 // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24 // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
26 // TODO(joth): port to chromium
27 #if 0
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
59 static const char16* RadioTypeToString(RadioType type);
60 // Adds a string if it's valid to the JSON object.
61 static void AddString(const std::string &property_name,
62 const std::string16 &value,
63 Json::Value *object);
64 // Adds an integer if it's valid to the JSON object.
65 static void AddInteger(const std::string &property_name,
66 const int &value,
67 Json::Value *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.
71 static bool ParseServerResponse(const std::string &response_body,
72 int64 timestamp,
73 bool is_reverse_geocode,
74 Position *position,
75 std::string16 *access_token);
76 static void AddRadioData(const RadioData &radio_data, Json::Value *body_object);
77 static void AddWifiData(const WifiData &wifi_data, Json::Value *body_object);
78
79 // static
80 NetworkLocationRequest *NetworkLocationRequest::Create(
81 BrowsingContext *browsing_context,
82 const std::string16 &url,
83 const std::string16 &host_name,
84 ListenerInterface *listener) {
85 scoped_ptr<NetworkLocationRequest> request(
86 new NetworkLocationRequest(browsing_context, url, host_name, listener));
87 assert(request.get());
88 if (!request.get() || !request->Init() || !request->Start()) {
89 return NULL;
90 }
91 return request.release();
92 }
93
94 NetworkLocationRequest::NetworkLocationRequest(
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) {
114 is_reverse_geocode_ = request_address &&
115 IsValidAngle(latitude) &&
116 IsValidAngle(longitude);
117 if (!FormRequestBody(host_name_, access_token, radio_data, wifi_data,
118 request_address, address_language, latitude, longitude,
119 is_reverse_geocode_, &post_body_)) {
120 return false;
121 }
122 timestamp_ = timestamp;
123
124 thread_event_.Signal();
125 return true;
126 }
127
128 // AsyncTask implementation.
129 void NetworkLocationRequest::Run() {
130 while (true) {
131 thread_event_.Wait();
132 if (is_shutting_down_) {
133 break;
134 }
135 MakeRequestImpl();
136 }
137 }
138
139 void NetworkLocationRequest::MakeRequestImpl() {
140 WebCacheDB::PayloadInfo payload;
141 // TODO(andreip): remove this once WebCacheDB::PayloadInfo.data is a Blob.
142 scoped_refptr<BlobInterface> payload_data;
143 bool result = HttpPost(url_.c_str(),
144 false, // Not capturing, so follow redirects
145 NULL, // reason_header_value
146 HttpConstants::kMimeApplicationJson, // Content-Type
147 NULL, // mod_since_date
148 NULL, // required_cookie
149 true, // disable_browser_cookies
150 post_body_.get(),
151 &payload,
152 &payload_data,
153 NULL, // was_redirected
154 NULL, // full_redirect_url
155 NULL); // error_message
156
157 MutexLock lock(&is_processing_response_mutex_);
158 // is_aborted_ may be true even if HttpPost succeeded.
159 if (is_aborted_) {
160 LOG(("NetworkLocationRequest::Run() : HttpPost request was cancelled.\n"));
161 return;
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.
203 if (host_name.empty()) {
204 return false;
205 }
206 body_object["version"] = Json::Value(kGearsNetworkLocationProtocolVersion);
207 AddString("host", host_name, &body_object);
208
209 AddString("access_token", access_token, &body_object);
210
211 body_object["request_address"] = request_address;
212 AddString("address_language", address_language, &body_object);
213
214 if (is_reverse_geocode) {
215 assert(request_address);
216 assert(IsValidAngle(latitude) && IsValidAngle(longitude));
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
228 // 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
230 // parse the JSON accordingly.
231 #ifdef OS_WINCE
232 // WinCE does not support setlocale.
233 #else
234 char *current_locale = setlocale(LC_NUMERIC, "C");
235 #endif
236 std::string body_string = writer.write(body_object);
237 #ifdef OS_WINCE
238 // WinCE does not support setlocale.
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;
247 }
248
249 // static
250 void NetworkLocationRequest::GetLocationFromResponse(
251 bool http_post_result,
252 int status_code,
253 const std::string &response_body,
254 int64 timestamp,
255 const std::string16 &server_url,
256 bool is_reverse_geocode,
257 Position *position,
258 std::string16 *access_token) {
259 assert(position);
260 assert(access_token);
261
262 // HttpPost can fail for a number of reasons. Most likely this is because
263 // we're offline, or there was no response.
264 if (!http_post_result) {
265 LOG(("NetworkLocationRequest::GetLocationFromResponse() : HttpPost request "
266 "failed.\n"));
267 position->error_code = Position::ERROR_CODE_POSITION_UNAVAILABLE;
268 position->error_message = STRING16(L"No response from network provider "
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.
297 LOG(("NetworkLocationRequest::GetLocationFromResponse() : HttpPost "
298 "response was bad.\n"));
299 position->error_code = Position::ERROR_CODE_POSITION_UNAVAILABLE;
300 position->error_message = STRING16(L"Network provider at ");
301 position->error_message += server_url.c_str();
302 position->error_message += STRING16(L" returned error code ");
303 position->error_message += IntegerToString16(status_code);
304 position->error_message += STRING16(L".");
305 }
306 }
307
308 void NetworkLocationRequest::StopThreadAndDelete() {
309 // The FF implementation of AsyncTask::Abort() delivers a message to the UI
310 // thread to cancel the request. So if we call this method on the UI thread,
311 // we must return to the OS before the call to Abort() will take effect. In
312 // particular, we can't call Abort() then block here waiting for HttpPost to
313 // return.
314 is_shutting_down_ = true;
315 thread_event_.Signal();
316 is_processing_response_mutex_.Lock();
317 Abort();
318 is_processing_response_mutex_.Unlock();
319 DeleteWhenDone();
320 }
321
322 // Local functions.
323
324 static const char16* RadioTypeToString(RadioType type) {
325 switch (type) {
326 case RADIO_TYPE_UNKNOWN:
327 return STRING16(L"unknown");
328 case RADIO_TYPE_GSM:
329 return STRING16(L"gsm");
330 case RADIO_TYPE_CDMA:
331 return STRING16(L"cdma");
332 case RADIO_TYPE_WCDMA:
333 return STRING16(L"wcdma");
334 default:
335 assert(false);
336 }
337 return NULL;
338 }
339
340 static void AddString(const std::string &property_name,
341 const std::string16 &value,
342 Json::Value *object) {
343 assert(object);
344 assert(object->isObject());
345 if (!value.empty()) {
346 std::string value_utf8;
347 if (String16ToUTF8(value.c_str(), value.size(), &value_utf8)) {
348 (*object)[property_name] = Json::Value(value_utf8);
349 }
350 }
351 }
352
353 static void AddInteger(const std::string &property_name,
354 const int &value,
355 Json::Value *object) {
356 assert(object);
357 assert(object->isObject());
358 if (kint32min != value) {
359 (*object)[property_name] = Json::Value(value);
360 }
361 }
362
363 static bool IsValidAngle(const double &value) {
364 return value >= -180.0 && value <= 180.0;
365 }
366
367 // Numeric values without a decimal point have type integer and IsDouble() will
368 // return false. This is convenience function for detecting integer or floating
369 // point numeric values. Note that isIntegral() includes boolean values, which
370 // is not what we want.
371 static bool IsDoubleOrInt(const Json::Value &object,
372 const std::string &property_name) {
373 return object[property_name].isDouble() || object[property_name].isInt();
374 }
375
376 // The JsValue::asXXX() methods return zero if a property isn't specified. For
377 // our purposes, zero is a valid value, so we have to test for existence.
378
379 // Gets a double if it's present.
380 static bool GetAsDouble(const Json::Value &object,
381 const std::string &property_name,
382 double *out) {
383 assert(out);
384 if (!IsDoubleOrInt(object, property_name)) {
385 return false;
386 }
387 *out = object[property_name].asDouble();
388 return true;
389 }
390
391 // Gets a string if it's present.
392 static bool GetAsString(const Json::Value &object,
393 const std::string &property_name,
394 std::string16 *out) {
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);
504 AddInteger("home_mobile_network_code", radio_data.home_mobile_network_code,
505 body_object);
506 AddString("radio_type", RadioTypeToString(radio_data.radio_type),
507 body_object);
508 AddString("carrier", radio_data.carrier, body_object);
509
510 Json::Value cell_towers;
511 assert(cell_towers.isArray());
512 int num_cell_towers = static_cast<int>(radio_data.cell_data.size());
513 for (int i = 0; i < num_cell_towers; ++i) {
514 Json::Value cell_tower;
515 assert(cell_tower.isObject());
516 AddInteger("cell_id", radio_data.cell_data[i].cell_id, &cell_tower);
517 AddInteger("location_area_code", radio_data.cell_data[i].location_area_code,
518 &cell_tower);
519 AddInteger("mobile_country_code",
520 radio_data.cell_data[i].mobile_country_code, &cell_tower);
521 AddInteger("mobile_network_code",
522 radio_data.cell_data[i].mobile_network_code, &cell_tower);
523 AddInteger("age", radio_data.cell_data[i].age, &cell_tower);
524 AddInteger("signal_strength", radio_data.cell_data[i].radio_signal_strength,
525 &cell_tower);
526 AddInteger("timing_advance", radio_data.cell_data[i].timing_advance,
527 &cell_tower);
528 cell_towers[i] = cell_tower;
529 }
530 if (num_cell_towers > 0) {
531 (*body_object)["cell_towers"] = cell_towers;
532 }
533 }
534
535 static void AddWifiData(const WifiData &wifi_data, Json::Value *body_object) {
536 assert(body_object);
537
538 if (wifi_data.access_point_data.empty()) {
539 return;
540 }
541
542 Json::Value wifi_towers;
543 assert(wifi_towers.isArray());
544 for (WifiData::AccessPointDataSet::const_iterator iter =
545 wifi_data.access_point_data.begin();
546 iter != wifi_data.access_point_data.end();
547 iter++) {
548 Json::Value wifi_tower;
549 assert(wifi_tower.isObject());
550 AddString("mac_address", iter->mac_address, &wifi_tower);
551 AddInteger("signal_strength", iter->radio_signal_strength, &wifi_tower);
552 AddInteger("age", iter->age, &wifi_tower);
553 AddInteger("channel", iter->channel, &wifi_tower);
554 AddInteger("signal_to_noise", iter->signal_to_noise, &wifi_tower);
555 AddString("ssid", iter->ssid, &wifi_tower);
556 wifi_towers.append(wifi_tower);
557 }
558 (*body_object)["wifi_towers"] = wifi_towers;
559 }
560
561 #endif // if 0
OLDNEW
« no previous file with comments | « chrome/browser/geolocation/network_location_request.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698