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

Unified Diff: ios/chrome/common/physical_web/physical_web_request.mm

Issue 2023833002: [iOS] Upstream physical web classes. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add comment about limiting the dependencies Created 4 years, 7 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 side-by-side diff with in-line comments
Download patch
Index: ios/chrome/common/physical_web/physical_web_request.mm
diff --git a/ios/chrome/common/physical_web/physical_web_request.mm b/ios/chrome/common/physical_web/physical_web_request.mm
new file mode 100644
index 0000000000000000000000000000000000000000..bbc0bd4b070f4601ff9d85839819049d6edd3623
--- /dev/null
+++ b/ios/chrome/common/physical_web/physical_web_request.mm
@@ -0,0 +1,247 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/common/physical_web/physical_web_request.h"
+
+#include "base/ios/weak_nsobject.h"
+#include "base/logging.h"
+#include "base/mac/foundation_util.h"
+#include "base/mac/scoped_block.h"
+#include "base/mac/scoped_nsobject.h"
+#include "base/metrics/histogram.h"
+#include "base/strings/sys_string_conversions.h"
+#include "components/version_info/version_info.h"
+#include "google_apis/google_api_keys.h"
+#import "ios/chrome/common/physical_web/physical_web_device.h"
+#import "ios/chrome/common/physical_web/physical_web_types.h"
+#include "ios/web/public/user_agent.h"
+
+typedef void (^SessionCompletionProceduralBlock)(NSData* data,
+ NSURLResponse* response,
+ NSError* error);
+
+namespace {
+
+NSString* const kUrlsKey = @"urls";
+NSString* const kUrlKey = @"url";
+NSString* const kResultsKey = @"results";
+NSString* const kPageInfoKey = @"pageInfo";
+NSString* const kIconKey = @"icon";
+NSString* const kTitleKey = @"title";
+NSString* const kDescriptionKey = @"description";
+NSString* const kScannedUrlKey = @"scannedUrl";
+NSString* const kResolvedUrlKey = @"resolvedUrl";
+
+NSString* const kMetadataServiceUrl =
+ @"https://physicalweb.googleapis.com/v1alpha1/urls:resolve";
+NSString* const kKeyQueryItemName = @"key";
+NSString* const kHTTPPOSTRequestMethod = @"POST";
+
+std::string GetUserAgent() {
+ static std::string user_agent;
+ static dispatch_once_t once_token;
+ dispatch_once(&once_token, ^{
+ std::string product("CriOS/");
+ product += version_info::GetVersionNumber();
+ user_agent = web::BuildUserAgentFromProduct(product);
+ });
+ return user_agent;
+}
+
+} // namespace
+
+@implementation PhysicalWebRequest {
+ base::mac::ScopedBlock<physical_web::RequestFinishedBlock> block_;
+ base::scoped_nsobject<PhysicalWebDevice> device_;
+ base::scoped_nsobject<NSMutableURLRequest> request_;
+ base::scoped_nsobject<NSURLSessionDataTask> urlSessionTask_;
+ base::scoped_nsobject<NSMutableData> data_;
+ base::scoped_nsobject<NSDate> startDate_;
+}
+
+- (instancetype)initWithDevice:(PhysicalWebDevice*)device {
+ self = [super init];
+ if (self) {
+ device_.reset([device retain]);
+ }
+ return self;
+}
+
+- (instancetype)init {
+ NOTREACHED();
+ return nil;
+}
+
+- (void)cancel {
+ [urlSessionTask_ cancel];
+ block_.reset();
+}
+
+- (void)start:(physical_web::RequestFinishedBlock)block {
+ block_.reset([block copy]);
+ data_.reset([[NSMutableData alloc] init]);
+
+ // Creates the HTTP post request.
+ NSURLComponents* components =
+ [[NSURLComponents alloc] initWithString:kMetadataServiceUrl];
+ NSString* apiKey =
+ [NSString stringWithUTF8String:google_apis::GetAPIKey().c_str()];
+ [components
+ setQueryItems:@[ [NSURLQueryItem queryItemWithName:kKeyQueryItemName
+ value:apiKey] ]];
+ NSURL* url = [components URL];
+ request_.reset([[NSMutableURLRequest requestWithURL:url] retain]);
+ [request_ setHTTPMethod:kHTTPPOSTRequestMethod];
+
+ // body of the POST request.
+ NSDictionary* jsonBody =
+ @{ kUrlsKey : @[ @{kUrlKey : [[device_ url] absoluteString]} ] };
+ [request_ setHTTPBody:[NSJSONSerialization dataWithJSONObject:jsonBody
+ options:0
+ error:NULL]];
+ [request_ setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
+ [request_ setValue:base::SysUTF8ToNSString(GetUserAgent())
+ forHTTPHeaderField:@"User-Agent"];
+
+ startDate_.reset([[NSDate date] retain]);
+ // Starts the request.
+ NSURLSession* session =
+ [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration
+ ephemeralSessionConfiguration]
+ delegate:nil
+ delegateQueue:[NSOperationQueue mainQueue]];
+ base::WeakNSObject<PhysicalWebRequest> weakSelf(self);
+ SessionCompletionProceduralBlock completionHandler =
+ ^(NSData* data, NSURLResponse* response, NSError* error) {
+ base::scoped_nsobject<PhysicalWebRequest> strongSelf([weakSelf retain]);
+ if (!strongSelf) {
+ return;
+ }
+ if (error) {
+ [strongSelf callBlockWithError:error jsonObject:nil];
+ } else {
+ [strongSelf.get()->data_ appendData:data];
+ [strongSelf sessionDidFinishLoading];
+ }
+ };
+ urlSessionTask_.reset([
+ [session dataTaskWithRequest:request_ completionHandler:completionHandler]
+ retain]);
+ [urlSessionTask_ resume];
+}
+
+- (void)sessionDidFinishLoading {
+ NSError* error = nil;
+ NSDictionary* jsonObject =
+ [NSJSONSerialization JSONObjectWithData:data_ options:0 error:&error];
+ if (error != nil) {
+ [self callBlockWithError:error jsonObject:nil];
+ return;
+ }
+ if (![self isValidJSON:jsonObject]) {
+ [self callBlockWithError:
+ [NSError errorWithDomain:physical_web::kPhysicalWebErrorDomain
+ code:physical_web::ERROR_INVALID_JSON
+ userInfo:nil]
+ jsonObject:jsonObject];
+ return;
+ }
+ [self callBlockWithError:error jsonObject:jsonObject];
+}
+
+// Checks whether the JSON object has the correct format.
+// The format should be similar to the following:
+// {
+// "results":[
+// {
+// "pageInfo":{
+// "title":"Google"
+// "description":"Search the world's information"
+// "icon":"https://www.google.com/favicon.ico"
+// }
+// "scannedUrl":"https://www.google.com"
+// "resolvedUrl":"https://www.google.com"
+// }
+// ]
+// }
+- (BOOL)isValidJSON:(id)jsonObject {
+ NSDictionary* dict = base::mac::ObjCCast<NSDictionary>(jsonObject);
+ if (!dict) {
+ return NO;
+ }
+ NSArray* list = base::mac::ObjCCast<NSArray>(dict[kResultsKey]);
+ if (!list) {
+ return NO;
+ }
+ if ([list count] != 1) {
+ return NO;
+ }
+ NSDictionary* item = base::mac::ObjCCast<NSDictionary>(list[0]);
+ if (!item) {
+ return NO;
+ }
+ return YES;
+}
+
+// Calls the block passed as parameter of -start: when the request is finished.
+- (void)callBlockWithError:(NSError*)error
+ jsonObject:(NSDictionary*)jsonObject {
+ if (error) {
+ if (block_.get()) {
+ block_.get()(nil, error);
+ }
+ } else {
+ NSTimeInterval roundTripTime =
+ [[NSDate date] timeIntervalSinceDate:startDate_];
+ int roundTripTimeMS = 1000 * roundTripTime;
+ UMA_HISTOGRAM_COUNTS("PhysicalWeb.RoundTripTimeMilliseconds",
+ roundTripTimeMS);
+ NSArray* list = jsonObject[kResultsKey];
+ NSDictionary* item = list[0];
+
+ NSDictionary* pageInfo =
+ base::mac::ObjCCast<NSDictionary>(item[kPageInfoKey]);
+ NSString* scannedUrlString =
+ base::mac::ObjCCast<NSString>(item[kScannedUrlKey]);
+ NSString* resolvedUrlString =
+ base::mac::ObjCCast<NSString>(item[kResolvedUrlKey]);
+
+ // Verify required fields pageInfo, scannedUrl, and resolvedUrl are present.
+ if (pageInfo == nil || scannedUrlString == nil ||
+ resolvedUrlString == nil) {
+ error = [NSError errorWithDomain:physical_web::kPhysicalWebErrorDomain
+ code:physical_web::ERROR_INVALID_JSON
+ userInfo:nil];
+ if (block_.get()) {
+ block_.get()(nil, error);
+ }
+ return;
+ }
+
+ // Read optional fields.
+ NSString* iconString = base::mac::ObjCCast<NSString>(pageInfo[kIconKey]);
+ NSString* description =
+ base::mac::ObjCCast<NSString>(pageInfo[kDescriptionKey]);
+ NSString* title = base::mac::ObjCCast<NSString>(pageInfo[kTitleKey]);
+ NSURL* scannedUrl =
+ scannedUrlString ? [NSURL URLWithString:scannedUrlString] : nil;
+ NSURL* resolvedUrl =
+ resolvedUrlString ? [NSURL URLWithString:resolvedUrlString] : nil;
+ NSURL* icon = iconString ? [NSURL URLWithString:iconString] : nil;
+ base::scoped_nsobject<PhysicalWebDevice> device([[PhysicalWebDevice alloc]
+ initWithURL:resolvedUrl
+ requestURL:scannedUrl
+ icon:icon
+ title:title
+ description:description
+ transmitPower:[device_ transmitPower]
+ rssi:[device_ rssi]
+ rank:physical_web::kMaxRank]);
+ if (block_.get() != nil) {
+ block_.get()(device, nil);
+ }
+ }
+}
+
+@end
« no previous file with comments | « ios/chrome/common/physical_web/physical_web_request.h ('k') | ios/chrome/common/physical_web/physical_web_scanner.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698