Updated Branches:
  refs/heads/CB-3530 [created] caa93a57b

[CB-3530] PhoneGap app crashes on iOS with error "CDVWebViewDelegate: 
Navigation started when state=1" (for navigation to an anchor on the same page)


Project: http://git-wip-us.apache.org/repos/asf/cordova-ios/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-ios/commit/caa93a57
Tree: http://git-wip-us.apache.org/repos/asf/cordova-ios/tree/caa93a57
Diff: http://git-wip-us.apache.org/repos/asf/cordova-ios/diff/caa93a57

Branch: refs/heads/CB-3530
Commit: caa93a57b0de81d619effff217fdc20fcc329bc4
Parents: d9d77c4
Author: Shazron Abdullah <[email protected]>
Authored: Tue Jun 18 17:50:01 2013 -0700
Committer: Shazron Abdullah <[email protected]>
Committed: Tue Jun 18 17:50:01 2013 -0700

----------------------------------------------------------------------
 CordovaLib/Classes/CDVWebViewDelegate.h         |  1 +
 CordovaLib/Classes/CDVWebViewDelegate.m         | 51 ++++++++++++-
 CordovaLibTests/CDVWebViewDelegateTests.m       | 77 ++++++++++++++++++++
 .../CordovaTests.xcodeproj/project.pbxproj      |  4 +
 4 files changed, 129 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/caa93a57/CordovaLib/Classes/CDVWebViewDelegate.h
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVWebViewDelegate.h 
b/CordovaLib/Classes/CDVWebViewDelegate.h
index a4d78bd..dd71807 100644
--- a/CordovaLib/Classes/CDVWebViewDelegate.h
+++ b/CordovaLib/Classes/CDVWebViewDelegate.h
@@ -34,5 +34,6 @@
 }
 
 - (id)initWithDelegate:(NSObject <UIWebViewDelegate>*)delegate;
+- (BOOL)request:(NSURLRequest*)newRequest 
isFragmentIdentifierToRequest:(NSURLRequest*)originalRequest;
 
 @end

http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/caa93a57/CordovaLib/Classes/CDVWebViewDelegate.m
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVWebViewDelegate.m 
b/CordovaLib/Classes/CDVWebViewDelegate.m
index 1ee7aea..38828c7 100644
--- a/CordovaLib/Classes/CDVWebViewDelegate.m
+++ b/CordovaLib/Classes/CDVWebViewDelegate.m
@@ -103,6 +103,47 @@ typedef enum {
     return self;
 }
 
+- (BOOL)request:(NSURLRequest*)newRequest 
isFragmentIdentifierToRequest:(NSURLRequest*)originalRequest
+{
+    if (originalRequest.URL && newRequest.URL) {
+        NSString* originalRequestUrl = [originalRequest.URL absoluteString];
+        NSString* newRequestUrl = [newRequest.URL absoluteString];
+
+        // no fragment, easy
+        if (newRequest.URL.fragment == nil) {
+            return NO;
+        }
+
+        // if the urls have fragments and they are equal
+        if ((originalRequest.URL.fragment && newRequest.URL.fragment) && 
[originalRequestUrl isEqualToString:newRequestUrl]) {
+            return YES;
+        }
+
+        NSString* urlFormat = @"%@://%@:%d/%@#%@";
+        // reconstruct the URLs (ignoring basic auth credentials, query string)
+        NSString* baseOriginalRequestUrl = [NSString 
stringWithFormat:urlFormat,
+            [originalRequest.URL scheme],
+            [originalRequest.URL host],
+            [[originalRequest.URL port] intValue],
+            [originalRequest.URL path],
+            [newRequest.URL fragment]                                 // add 
the new request's fragment
+            ];
+        NSLog(@"baseOriginalRequestUrl: %@", baseOriginalRequestUrl);
+        NSString* baseNewRequestUrl = [NSString stringWithFormat:urlFormat,
+            [newRequest.URL scheme],
+            [newRequest.URL host],
+            [[newRequest.URL port] intValue],
+            [newRequest.URL path],
+            [newRequest.URL fragment]
+            ];
+        NSLog(@"baseNewRequestUrl: %@", baseNewRequestUrl);
+
+        return [baseOriginalRequestUrl isEqualToString:baseNewRequestUrl];
+    }
+
+    return NO;
+}
+
 - (BOOL)isPageLoaded:(UIWebView*)webView
 {
     NSString* readyState = [webView 
stringByEvaluatingJavaScriptFromString:@"document.readyState"];
@@ -198,10 +239,12 @@ typedef enum {
                         NSLog(@"%@", description);
                         _loadCount = 0;
                         _state = STATE_WAITING_FOR_LOAD_START;
-                        if ([_delegate 
respondsToSelector:@selector(webView:didFailLoadWithError:)]) {
-                            NSDictionary* errorDictionary = 
@{NSLocalizedDescriptionKey : description};
-                            NSError* error = [[NSError alloc] 
initWithDomain:@"CDVWebViewDelegate" code:1 userInfo:errorDictionary];
-                            [_delegate webView:webView 
didFailLoadWithError:error];
+                        if (![self request:request 
isFragmentIdentifierToRequest:webView.request]) {
+                            if ([_delegate 
respondsToSelector:@selector(webView:didFailLoadWithError:)]) {
+                                NSDictionary* errorDictionary = 
@{NSLocalizedDescriptionKey : description};
+                                NSError* error = [[NSError alloc] 
initWithDomain:@"CDVWebViewDelegate" code:1 userInfo:errorDictionary];
+                                [_delegate webView:webView 
didFailLoadWithError:error];
+                            }
                         }
                     }
             }

http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/caa93a57/CordovaLibTests/CDVWebViewDelegateTests.m
----------------------------------------------------------------------
diff --git a/CordovaLibTests/CDVWebViewDelegateTests.m 
b/CordovaLibTests/CDVWebViewDelegateTests.m
new file mode 100644
index 0000000..1e536fa
--- /dev/null
+++ b/CordovaLibTests/CDVWebViewDelegateTests.m
@@ -0,0 +1,77 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import <SenTestingKit/SenTestingKit.h>
+
+#import <Cordova/CDVWebViewDelegate.h>
+
+@interface CDVWebViewDelegateTests : SenTestCase
+@end
+
+@implementation CDVWebViewDelegateTests
+
+- (void)setUp
+{
+    [super setUp];
+}
+
+- (void)tearDown
+{
+    [super tearDown];
+}
+
+- (void)testFragmentIdentifiersWithHttpUrl
+{
+    [self doTestFragmentIdentifiersWithBaseUrl:@"http://cordova.apache.org";];
+}
+
+- (void)testFragmentIdentifiersWithFileUrl
+{
+    [self 
doTestFragmentIdentifiersWithBaseUrl:@"file:///var/mobile/GASGEQGQsdga3313/www/index.html"];
+}
+
+- (void)doTestFragmentIdentifiersWithBaseUrl:(NSString*)baseUrl
+{
+    CDVWebViewDelegate* wvd = [[CDVWebViewDelegate alloc] 
initWithDelegate:nil]; // not really testing delegate handling
+
+    NSString* originalUrlString = baseUrl;
+    NSURL* originalUrl = [NSURL URLWithString:originalUrlString];
+    NSURL* originalUrlWithFragmentOnly = [NSURL URLWithString:[NSString 
stringWithFormat:@"%@#myfragment", originalUrlString]];
+    NSURL* originalUrlWithFragmentOnlyNoIdentifier = [NSURL 
URLWithString:[NSString stringWithFormat:@"%@#", originalUrlString]];
+    NSURL* originalUrlWithQueryParamsAndFragment = [NSURL 
URLWithString:[NSString stringWithFormat:@"%@?foo=bar#myfragment", 
originalUrlString]];
+
+    NSURLRequest* originalRequest = [NSURLRequest requestWithURL:originalUrl];
+    NSURLRequest* originalRequestWithFragmentOnly = [NSURLRequest 
requestWithURL:originalUrlWithFragmentOnly];
+    NSURLRequest* originalRequestWithFragmentOnlyNoIdentifier = [NSURLRequest 
requestWithURL:originalUrlWithFragmentOnlyNoIdentifier];
+    NSURLRequest* originalRequestWithQueryParamsAndFragment = [NSURLRequest 
requestWithURL:originalUrlWithQueryParamsAndFragment];
+    NSURLRequest* notOriginalRequest = [NSURLRequest requestWithURL:[NSURL 
URLWithString:@"http://httpd.apache.org";]];
+
+    STAssertFalse([wvd request:originalRequest 
isFragmentIdentifierToRequest:originalRequest], @"originalRequest should not be 
a fragment of originalRequest");
+    STAssertTrue([wvd request:originalRequestWithFragmentOnly 
isFragmentIdentifierToRequest:originalRequest], @"originalRequestWithFragment 
should be a fragment of originalRequest");
+    STAssertTrue([wvd request:originalRequestWithFragmentOnlyNoIdentifier 
isFragmentIdentifierToRequest:originalRequest], 
@"originalRequestWithFragmentNoIdentifier should be a fragment of 
originalRequest");
+    STAssertTrue([wvd request:originalRequestWithQueryParamsAndFragment 
isFragmentIdentifierToRequest:originalRequest], 
@"originalRequestWithQueryParamsAndFragment should be a fragment of 
originalRequest");
+    STAssertFalse([wvd request:notOriginalRequest 
isFragmentIdentifierToRequest:originalRequest], @"notOriginalRequest should not 
be a fragment of originalRequest");
+
+    // equality tests
+    STAssertTrue([wvd request:originalRequestWithFragmentOnly 
isFragmentIdentifierToRequest:originalRequestWithFragmentOnly], 
@"originalRequestWithFragment should be a fragment of itself");
+    STAssertTrue([wvd request:originalRequestWithFragmentOnlyNoIdentifier 
isFragmentIdentifierToRequest:originalRequestWithFragmentOnlyNoIdentifier], 
@"originalRequestWithFragmentNoIdentifier should be a fragment of itself");
+    STAssertTrue([wvd request:originalRequestWithQueryParamsAndFragment 
isFragmentIdentifierToRequest:originalRequestWithQueryParamsAndFragment], 
@"originalRequestWithQueryParamsAndFragment should be a fragment of itself");
+}
+
+@end

http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/caa93a57/CordovaLibTests/CordovaTests.xcodeproj/project.pbxproj
----------------------------------------------------------------------
diff --git a/CordovaLibTests/CordovaTests.xcodeproj/project.pbxproj 
b/CordovaLibTests/CordovaTests.xcodeproj/project.pbxproj
index 3ac6c85..88ac047 100644
--- a/CordovaLibTests/CordovaTests.xcodeproj/project.pbxproj
+++ b/CordovaLibTests/CordovaTests.xcodeproj/project.pbxproj
@@ -43,6 +43,7 @@
                68A32D7E141030EB006B237C /* UIKit.framework in Frameworks */ = 
{isa = PBXBuildFile; fileRef = 686357AA141002F100DF4CF2 /* UIKit.framework */; 
};
                68A32D7F141030F3006B237C /* Foundation.framework in Frameworks 
*/ = {isa = PBXBuildFile; fileRef = 686357AC141002F100DF4CF2 /* 
Foundation.framework */; };
                7E13A295175D487B00E522AB /* CDVExifTests.m in Sources */ = {isa 
= PBXBuildFile; fileRef = 7E13A294175D487B00E522AB /* CDVExifTests.m */; };
+               7E91406017711D88002C6A3F /* CDVWebViewDelegateTests.m in 
Sources */ = {isa = PBXBuildFile; fileRef = 7E91405F17711D88002C6A3F /* 
CDVWebViewDelegateTests.m */; };
                8220B5C216D541BD00EC3921 /* AssetsLibrary.framework in 
Frameworks */ = {isa = PBXBuildFile; fileRef = 8220B5C116D541BD00EC3921 /* 
AssetsLibrary.framework */; };
                8220B5C616D542F500EC3921 /* AssetsLibrary.framework in 
Frameworks */ = {isa = PBXBuildFile; fileRef = 8220B5C116D541BD00EC3921 /* 
AssetsLibrary.framework */; };
                EB3B34E9161B5532003DBE7D /* libCordova.a in Frameworks */ = 
{isa = PBXBuildFile; fileRef = EB3B34E6161B5454003DBE7D /* libCordova.a */; };
@@ -110,6 +111,7 @@
                68A32D7414103017006B237C /* AddressBook.framework */ = {isa = 
PBXFileReference; lastKnownFileType = wrapper.framework; name = 
AddressBook.framework; path = System/Library/Frameworks/AddressBook.framework; 
sourceTree = SDKROOT; };
                7E13A293175D487B00E522AB /* CDVExifTests.h */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 
CDVExifTests.h; sourceTree = "<group>"; };
                7E13A294175D487B00E522AB /* CDVExifTests.m */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path 
= CDVExifTests.m; sourceTree = "<group>"; };
+               7E91405F17711D88002C6A3F /* CDVWebViewDelegateTests.m */ = {isa 
= PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; 
path = CDVWebViewDelegateTests.m; sourceTree = "<group>"; };
                8220B5C116D541BD00EC3921 /* AssetsLibrary.framework */ = {isa = 
PBXFileReference; lastKnownFileType = wrapper.framework; name = 
AssetsLibrary.framework; path = 
System/Library/Frameworks/AssetsLibrary.framework; sourceTree = SDKROOT; };
                EB37018115D18B2D00BEBC43 /* CordovaLib.xcodeproj */ = {isa = 
PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = 
CordovaLib.xcodeproj; path = ../CordovaLib/CordovaLib.xcodeproj; sourceTree = 
"<group>"; };
                EB89634915FE66EA00E12277 /* CDVInvokedUrlCommandTests.m */ = 
{isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = 
sourcecode.c.objc; path = CDVInvokedUrlCommandTests.m; sourceTree = "<group>"; 
};
@@ -250,6 +252,7 @@
                EB3B34F4161B585D003DBE7D /* CordovaLibTests */ = {
                        isa = PBXGroup;
                        children = (
+                               7E91405F17711D88002C6A3F /* 
CDVWebViewDelegateTests.m */,
                                7E13A293175D487B00E522AB /* CDVExifTests.h */,
                                7E13A294175D487B00E522AB /* CDVExifTests.m */,
                                EB96677116ADBCF500D86CDF /* CDVUserAgentTest.m 
*/,
@@ -435,6 +438,7 @@
                                EB89634A15FE66EA00E12277 /* 
CDVInvokedUrlCommandTests.m in Sources */,
                                EB96677216ADBCF500D86CDF /* CDVUserAgentTest.m 
in Sources */,
                                7E13A295175D487B00E522AB /* CDVExifTests.m in 
Sources */,
+                               7E91406017711D88002C6A3F /* 
CDVWebViewDelegateTests.m in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };

Reply via email to