You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by ag...@apache.org on 2012/11/23 03:38:31 UTC
[3/4] ios commit: Use the VC's address in the User-Agent instead of a
GUID.
Use the VC's address in the User-Agent instead of a GUID.
This allows us to simplify CDVURLProtocol a bit, and to also
remove explicitly setting cordova.iOSVCAddr.
This also changes from caching the with-GUID UA to storing the original
UA. The original UA is more useful.
Project: http://git-wip-us.apache.org/repos/asf/cordova-ios/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-ios/commit/e8a74017
Tree: http://git-wip-us.apache.org/repos/asf/cordova-ios/tree/e8a74017
Diff: http://git-wip-us.apache.org/repos/asf/cordova-ios/diff/e8a74017
Branch: refs/heads/master
Commit: e8a740176a465092b0d55dc9aee9a3e0ac314691
Parents: 66fed79
Author: Andrew Grieve <ag...@chromium.org>
Authored: Thu Nov 22 21:34:03 2012 -0500
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Thu Nov 22 21:34:03 2012 -0500
----------------------------------------------------------------------
CordovaLib/Classes/CDVInAppBrowser.m | 2 +-
CordovaLib/Classes/CDVURLProtocol.m | 108 +++++++++++++++------------
CordovaLib/Classes/CDVViewController.h | 4 +-
CordovaLib/Classes/CDVViewController.m | 47 +++++++-----
4 files changed, 90 insertions(+), 71 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/e8a74017/CordovaLib/Classes/CDVInAppBrowser.m
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVInAppBrowser.m b/CordovaLib/Classes/CDVInAppBrowser.m
index 006eb41..227ab9a 100644
--- a/CordovaLib/Classes/CDVInAppBrowser.m
+++ b/CordovaLib/Classes/CDVInAppBrowser.m
@@ -80,7 +80,7 @@
- (void)openInInAppBrowser:(NSURL*)url withOptions:(NSString*)options
{
if (self.inAppBrowserViewController == nil) {
- NSString* originalUA = [self.webView stringByEvaluatingJavaScriptFromString:@"navigator.userAgent"];
+ NSString* originalUA = [CDVViewController originalUserAgent];
CFUUIDRef uuidRef = CFUUIDCreate(kCFAllocatorDefault);
CFStringRef uuidString = CFUUIDCreateString(kCFAllocatorDefault, uuidRef);
http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/e8a74017/CordovaLib/Classes/CDVURLProtocol.m
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVURLProtocol.m b/CordovaLib/Classes/CDVURLProtocol.m
index 5878b38..a645288 100644
--- a/CordovaLib/Classes/CDVURLProtocol.m
+++ b/CordovaLib/Classes/CDVURLProtocol.m
@@ -32,8 +32,37 @@ static CDVWhitelist * gWhitelist = nil;
// Contains a set of NSNumbers of addresses of controllers. It doesn't store
// the actual pointer to avoid retaining.
static NSMutableSet* gRegisteredControllers = nil;
-// Contains a set of NSStrings of User Agents
-static NSMutableSet* gRegisteredUserAgents = nil;
+
+// Returns the registered view controller that sent the given request.
+// If the user-agent is not from a UIWebView, or if it's from an unregistered one,
+// then nil is returned.
+static CDVViewController *viewControllerForRequest(NSURLRequest* request)
+{
+ // The exec bridge explicitly sets the VC address in a header.
+ // This works around the User-Agent not being set for file: URLs.
+ NSString* addrString = [request valueForHTTPHeaderField:@"vc"];
+
+ if (addrString == nil) {
+ NSString* userAgent = [request valueForHTTPHeaderField:@"User-Agent"];
+ if (userAgent == nil) {
+ return nil;
+ }
+ NSUInteger bracketLocation = [userAgent rangeOfString:@"(" options:NSBackwardsSearch].location;
+ if (bracketLocation == NSNotFound) {
+ return nil;
+ }
+ addrString = [userAgent substringFromIndex:bracketLocation + 1];
+ }
+
+ long long viewControllerAddress = [addrString longLongValue];
+ @synchronized(gRegisteredControllers) {
+ if (![gRegisteredControllers containsObject:[NSNumber numberWithLongLong:viewControllerAddress]]) {
+ return nil;
+ }
+ }
+
+ return (__bridge CDVViewController*)(void*)viewControllerAddress;
+}
@implementation CDVURLProtocol
@@ -48,7 +77,6 @@ static NSMutableSet* gRegisteredUserAgents = nil;
if (gRegisteredControllers == nil) {
[NSURLProtocol registerClass:[CDVURLProtocol class]];
gRegisteredControllers = [[NSMutableSet alloc] initWithCapacity:8];
- gRegisteredUserAgents = [[NSMutableSet alloc] initWithCapacity:8];
// The whitelist doesn't change, so grab the first one and store it.
gWhitelist = viewController.whitelist;
@@ -63,65 +91,49 @@ static NSMutableSet* gRegisteredUserAgents = nil;
@synchronized(gRegisteredControllers) {
[gRegisteredControllers addObject:[NSNumber numberWithLongLong:(long long)viewController]];
- NSString* userAgent = [viewController.webView stringByEvaluatingJavaScriptFromString:@"navigator.userAgent"];
- [gRegisteredUserAgents addObject:userAgent];
}
}
+ (void)unregisterViewController:(CDVViewController*)viewController
{
- [gRegisteredControllers removeObject:[NSNumber numberWithLongLong:(long long)viewController]];
- NSString* userAgent = [viewController.webView stringByEvaluatingJavaScriptFromString:@"navigator.userAgent"];
- [gRegisteredUserAgents removeObject:userAgent];
+ @synchronized(gRegisteredControllers) {
+ [gRegisteredControllers removeObject:[NSNumber numberWithLongLong:(long long)viewController]];
+ }
}
+ (BOOL)canInitWithRequest:(NSURLRequest*)theRequest
{
NSURL* theUrl = [theRequest URL];
- NSString* theScheme = [theUrl scheme];
- NSString* theUserAgent = [theRequest valueForHTTPHeaderField:@"User-Agent"];
-
- if ([[theUrl path] isEqualToString:@"/!gap_exec"]) {
- NSString* viewControllerAddressStr = [theRequest valueForHTTPHeaderField:@"vc"];
- if (viewControllerAddressStr == nil) {
- NSLog(@"!cordova request missing vc header");
- return NO;
- }
- long long viewControllerAddress = [viewControllerAddressStr longLongValue];
- // Ensure that the CDVViewController has not been dealloc'ed.
- CDVViewController* viewController = nil;
- @synchronized(gRegisteredControllers) {
- if (![gRegisteredControllers containsObject:[NSNumber numberWithLongLong:viewControllerAddress]]) {
+ CDVViewController* viewController = viewControllerForRequest(theRequest);
+
+ if (viewController != nil) {
+ if ([[theUrl path] isEqualToString:@"/!gap_exec"]) {
+ NSString* queuedCommandsJSON = [theRequest valueForHTTPHeaderField:@"cmds"];
+ NSString* requestId = [theRequest valueForHTTPHeaderField:@"rc"];
+ if (requestId == nil) {
+ NSLog(@"!cordova request missing rc header");
return NO;
}
- viewController = (__bridge CDVViewController*)(void*)viewControllerAddress;
- }
-
- NSString* queuedCommandsJSON = [theRequest valueForHTTPHeaderField:@"cmds"];
- NSString* requestId = [theRequest valueForHTTPHeaderField:@"rc"];
- if (requestId == nil) {
- NSLog(@"!cordova request missing rc header");
- return NO;
+ BOOL hasCmds = [queuedCommandsJSON length] > 0;
+ if (hasCmds) {
+ SEL sel = @selector(enqueCommandBatch:);
+ [viewController.commandQueue performSelectorOnMainThread:sel withObject:queuedCommandsJSON waitUntilDone:NO];
+ } else {
+ SEL sel = @selector(maybeFetchCommandsFromJs:);
+ [viewController.commandQueue performSelectorOnMainThread:sel withObject:[NSNumber numberWithInteger:[requestId integerValue]] waitUntilDone:NO];
+ }
+ // Returning NO here would be 20% faster, but it spams WebInspector's console with failure messages.
+ // If JS->Native bridge speed is really important for an app, they should use the iframe bridge.
+ // Returning YES here causes the request to come through canInitWithRequest two more times.
+ // For this reason, we return NO when cmds exist.
+ return !hasCmds;
}
- BOOL hasCmds = [queuedCommandsJSON length] > 0;
- if (hasCmds) {
- SEL sel = @selector(enqueCommandBatch:);
- [viewController.commandQueue performSelectorOnMainThread:sel withObject:queuedCommandsJSON waitUntilDone:NO];
- } else {
- SEL sel = @selector(maybeFetchCommandsFromJs:);
- [viewController.commandQueue performSelectorOnMainThread:sel withObject:[NSNumber numberWithInteger:[requestId integerValue]] waitUntilDone:NO];
+ // we only care about http and https connections.
+ // CORS takes care of http: trying to access file: URLs.
+ if ([gWhitelist schemeIsAllowed:[theUrl scheme]]) {
+ // if it FAILS the whitelist, we return TRUE, so we can fail the connection later
+ return ![gWhitelist URLIsAllowed:theUrl];
}
- // Returning NO here would be 20% faster, but it spams WebInspector's console with failure messages.
- // If JS->Native bridge speed is really important for an app, they should use the iframe bridge.
- // Returning YES here causes the request to come through canInitWithRequest two more times.
- // For this reason, we return NO when cmds exist.
- return !hasCmds;
- }
-
- // we only care about http and https connections, and registered user-agents
- if ([gWhitelist schemeIsAllowed:theScheme] && [gRegisteredUserAgents containsObject:theUserAgent]) {
- // if it FAILS the whitelist, we return TRUE, so we can fail the connection later
- return ![gWhitelist URLIsAllowed:theUrl];
}
return NO;
http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/e8a74017/CordovaLib/Classes/CDVViewController.h
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVViewController.h b/CordovaLib/Classes/CDVViewController.h
index ab661f8..017af27 100644
--- a/CordovaLib/Classes/CDVViewController.h
+++ b/CordovaLib/Classes/CDVViewController.h
@@ -32,6 +32,7 @@
@interface CDVViewController : UIViewController <UIWebViewDelegate, CDVScreenOrientationDelegate>{
@private
CDVCommandDelegateImpl* _commandDelegate;
+ NSString* _userAgent;
}
@property (nonatomic, strong) IBOutlet CDVCordovaView* webView;
@@ -51,10 +52,11 @@
@property (nonatomic, readwrite, copy) NSString* startPage;
@property (nonatomic, readonly, strong) CDVCommandQueue* commandQueue;
@property (nonatomic, readonly, strong) CDVCommandDelegateImpl* commandDelegate;
-@property (nonatomic, readonly, copy) NSString* userAgent;
+@property (nonatomic, readonly) NSString* userAgent;
+ (NSDictionary*)getBundlePlist:(NSString*)plistName;
+ (NSString*)applicationDocumentsDirectory;
++ (NSString*)originalUserAgent;
- (void)printMultitaskingInfo;
- (void)createGapView;
http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/e8a74017/CordovaLib/Classes/CDVViewController.m
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVViewController.m b/CordovaLib/Classes/CDVViewController.m
index 20b9b35..85f3722 100644
--- a/CordovaLib/Classes/CDVViewController.m
+++ b/CordovaLib/Classes/CDVViewController.m
@@ -406,33 +406,39 @@
return [[CDVCordovaView alloc] initWithFrame:bounds];
}
-- (NSString*)userAgent
++ (NSString*)originalUserAgent
{
- NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
- NSString* systemVersion = [[UIDevice currentDevice] systemVersion];
+ static NSString* originalUserAgent = nil;
- NSString* cordovaUserAgentVersion = [userDefaults stringForKey:CDV_USER_AGENT_VERSION_KEY];
- NSString* cordovaUserAgent = [userDefaults stringForKey:CDV_USER_AGENT_KEY];
- BOOL systemVersionChanged = ![systemVersion isEqualToString:cordovaUserAgentVersion];
+ if (originalUserAgent == nil) {
+ NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
+ NSString* systemVersion = [[UIDevice currentDevice] systemVersion];
- if ((cordovaUserAgent == nil) || (cordovaUserAgentVersion == nil) || systemVersionChanged) {
- UIWebView* sampleWebView = [[UIWebView alloc] initWithFrame:CGRectZero];
- NSString* originalUserAgent = [sampleWebView stringByEvaluatingJavaScriptFromString:@"navigator.userAgent"];
+ NSString* cordovaUserAgentVersion = [userDefaults stringForKey:CDV_USER_AGENT_VERSION_KEY];
+ originalUserAgent = [userDefaults stringForKey:CDV_USER_AGENT_KEY];
+ BOOL systemVersionChanged = ![systemVersion isEqualToString:cordovaUserAgentVersion];
- // generate a GUID to append to the User-Agent
- CFUUIDRef uuidRef = CFUUIDCreate(kCFAllocatorDefault);
- CFStringRef uuidString = CFUUIDCreateString(kCFAllocatorDefault, uuidRef);
- cordovaUserAgent = [NSString stringWithFormat:@"%@ (%@)", originalUserAgent, uuidString];
- CFRelease(uuidString);
- CFRelease(uuidRef);
+ if ((originalUserAgent == nil) || systemVersionChanged) {
+ UIWebView* sampleWebView = [[UIWebView alloc] initWithFrame:CGRectZero];
+ originalUserAgent = [sampleWebView stringByEvaluatingJavaScriptFromString:@"navigator.userAgent"];
- [userDefaults setObject:cordovaUserAgent forKey:CDV_USER_AGENT_KEY];
- [userDefaults setObject:systemVersion forKey:CDV_USER_AGENT_VERSION_KEY];
+ [userDefaults setObject:originalUserAgent forKey:CDV_USER_AGENT_KEY];
+ [userDefaults setObject:systemVersion forKey:CDV_USER_AGENT_VERSION_KEY];
- [userDefaults synchronize];
+ [userDefaults synchronize];
+ }
}
+ return originalUserAgent;
+}
- return cordovaUserAgent;
+- (NSString*)userAgent
+{
+ if (_userAgent == nil) {
+ NSString* originalUserAgent = [[self class] originalUserAgent];
+ // Use our address as a unique number to append to the User-Agent.
+ _userAgent = [NSString stringWithFormat:@"%@ (%lld)", originalUserAgent, (long long)self];
+ }
+ return _userAgent;
}
- (void)createGapView
@@ -525,10 +531,9 @@
}
[self didRotateFromInterfaceOrientation:(UIInterfaceOrientation)[[UIDevice currentDevice] orientation]];
- // The iOSVCAddr is used to identify the WebView instance when using one of the XHR js->native bridge modes.
// The .onNativeReady().fire() will work when cordova.js is already loaded.
// The _nativeReady = true; is used when this is run before cordova.js is loaded.
- NSString* nativeReady = [NSString stringWithFormat:@"cordova.iOSVCAddr='%lld';try{cordova.require('cordova/channel').onNativeReady.fire();}catch(e){window._nativeReady = true;}", (long long)self];
+ NSString* nativeReady = @"try{cordova.require('cordova/channel').onNativeReady.fire();}catch(e){window._nativeReady = true;}";
[self.commandDelegate evalJs:nativeReady];
}