cordova-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From agri...@apache.org
Subject ios commit: [CB-2698] Fix load detection when pages have redirects.
Date Sat, 20 Apr 2013 15:44:22 GMT
Updated Branches:
  refs/heads/master 59806196c -> 7e0a32892


[CB-2698] Fix load detection when pages have redirects.


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

Branch: refs/heads/master
Commit: 7e0a32892a540295e7de5da6a4832dfdaf337ac0
Parents: 5980619
Author: Andrew Grieve <agrieve@chromium.org>
Authored: Sat Apr 20 11:43:37 2013 -0400
Committer: Andrew Grieve <agrieve@chromium.org>
Committed: Sat Apr 20 11:43:37 2013 -0400

----------------------------------------------------------------------
 CordovaLib/Classes/CDVWebViewDelegate.h |    1 +
 CordovaLib/Classes/CDVWebViewDelegate.m |  198 +++++++++++++++++++-------
 2 files changed, 148 insertions(+), 51 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/7e0a3289/CordovaLib/Classes/CDVWebViewDelegate.h
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVWebViewDelegate.h b/CordovaLib/Classes/CDVWebViewDelegate.h
index 8a89a22..a4d78bd 100644
--- a/CordovaLib/Classes/CDVWebViewDelegate.h
+++ b/CordovaLib/Classes/CDVWebViewDelegate.h
@@ -30,6 +30,7 @@
     NSInteger _loadCount;
     NSInteger _state;
     NSInteger _curLoadToken;
+    NSInteger _loadStartPollCount;
 }
 
 - (id)initWithDelegate:(NSObject <UIWebViewDelegate>*)delegate;

http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/7e0a3289/CordovaLib/Classes/CDVWebViewDelegate.m
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVWebViewDelegate.m b/CordovaLib/Classes/CDVWebViewDelegate.m
index dd98d43..fd9c032 100644
--- a/CordovaLib/Classes/CDVWebViewDelegate.m
+++ b/CordovaLib/Classes/CDVWebViewDelegate.m
@@ -58,6 +58,23 @@
 // 4. didStart
 // 5. didFailWithError
 // 6. didFinish
+//
+// Loading a page with an iframe that fails to load due to an invalid URL:
+// 1. shouldStart (main page)
+// 2. didStart
+// 3. shouldStart (iframe)
+// 5. didFailWithError
+// 6. didFinish
+//
+// This case breaks our logic since there is a missing didStart. To prevent this,
+// we check URLs in shouldStart and return NO if they are invalid.
+//
+// Loading a page with an invalid URL
+// 1. shouldStart (main page)
+// 2. didFailWithError
+//
+// TODO: Record order when page is re-navigated before the first navigation finishes.
+//
 
 #import "CDVWebViewDelegate.h"
 #import "CDVAvailability.h"
@@ -66,10 +83,11 @@
 #define VerboseLog(...) do {} while (0)
 
 typedef enum {
-    STATE_NORMAL,
-    STATE_SHOULD_LOAD_MISSING,
-    STATE_WAITING_FOR_START,
-    STATE_WAITING_FOR_FINISH
+    STATE_IDLE,
+    STATE_WAITING_FOR_LOAD_START,
+    STATE_WAITING_FOR_LOAD_FINISH,
+    STATE_IOS5_POLLING_FOR_LOAD_START,
+    STATE_IOS5_POLLING_FOR_LOAD_FINISH
 } State;
 
 @implementation CDVWebViewDelegate
@@ -80,7 +98,7 @@ typedef enum {
     if (self != nil) {
         _delegate = delegate;
         _loadCount = -1;
-        _state = STATE_NORMAL;
+        _state = STATE_IDLE;
     }
     return self;
 }
@@ -107,12 +125,12 @@ typedef enum {
 
 - (void)pollForPageLoadStart:(UIWebView*)webView
 {
-    if ((_state != STATE_WAITING_FOR_START) && (_state != STATE_SHOULD_LOAD_MISSING))
{
+    if (_state != STATE_IOS5_POLLING_FOR_LOAD_START) {
         return;
     }
     if (![self isJsLoadTokenSet:webView]) {
         VerboseLog(@"Polled for page load start. result = YES!");
-        _state = STATE_WAITING_FOR_FINISH;
+        _state = STATE_IOS5_POLLING_FOR_LOAD_FINISH;
         [self setLoadToken:webView];
         if ([_delegate respondsToSelector:@selector(webViewDidStartLoad:)]) {
             [_delegate webViewDidStartLoad:webView];
@@ -120,24 +138,28 @@ typedef enum {
         [self pollForPageLoadFinish:webView];
     } else {
         VerboseLog(@"Polled for page load start. result = NO");
-        [self performSelector:@selector(pollForPageLoadStart) withObject:webView afterDelay:50];
+        // Poll only for 1 second, and then fall back on checking only when delegate methods
are called.
+        ++_loadStartPollCount;
+        if (_loadStartPollCount < (1000 * .05)) {
+            [self performSelector:@selector(pollForPageLoadStart:) withObject:webView afterDelay:.05];
+        }
     }
 }
 
 - (void)pollForPageLoadFinish:(UIWebView*)webView
 {
-    if (_state != STATE_WAITING_FOR_FINISH) {
+    if (_state != STATE_IOS5_POLLING_FOR_LOAD_FINISH) {
         return;
     }
     if ([self isPageLoaded:webView]) {
         VerboseLog(@"Polled for page load finish. result = YES!");
-        _state = STATE_SHOULD_LOAD_MISSING;
+        _state = STATE_IDLE;
         if ([_delegate respondsToSelector:@selector(webViewDidFinishLoad:)]) {
             [_delegate webViewDidFinishLoad:webView];
         }
     } else {
         VerboseLog(@"Polled for page load finish. result = NO");
-        [self performSelector:@selector(pollForPageLoadFinish) withObject:webView afterDelay:50];
+        [self performSelector:@selector(pollForPageLoadFinish:) withObject:webView afterDelay:.05];
     }
 }
 
@@ -149,15 +171,41 @@ typedef enum {
         shouldLoad = [_delegate webView:webView shouldStartLoadWithRequest:request navigationType:navigationType];
     }
 
-    VerboseLog(@"webView shouldLoad=%d state=%d loadCount=%d URL=%@", shouldLoad, _state,
_loadCount, request.URL);
+    VerboseLog(@"webView shouldLoad=%d (before) state=%d loadCount=%d URL=%@", shouldLoad,
_state, _loadCount, request.URL);
 
     if (shouldLoad) {
         BOOL isTopLevelNavigation = [request.URL isEqual:[request mainDocumentURL]];
         if (isTopLevelNavigation) {
-            _loadCount = 0;
-            _state = STATE_NORMAL;
+            switch (_state) {
+                case STATE_WAITING_FOR_LOAD_FINISH:
+                    // Redirect case.
+                    // We expect loadCount == 1.
+                    if (_loadCount != 1) {
+                        NSLog(@"CDVWebViewDelegate: Detected redirect when loadCount=%d",
_loadCount);
+                    }
+                    break;
+
+                case STATE_IDLE:
+                case STATE_IOS5_POLLING_FOR_LOAD_START:
+                    // Page navigation start.
+                    _loadCount = 0;
+                    _state = STATE_WAITING_FOR_LOAD_START;
+                    break;
+
+                default:
+                    NSLog(@"CDVWebViewDelegate: Navigation started when state=%d", _state);
+                    _loadCount = 0;
+                    _state = STATE_WAITING_FOR_LOAD_START;
+                    if ([_delegate respondsToSelector:@selector(webView:didFailLoadWithError:)])
{
+                        [_delegate webView:webView didFailLoadWithError:nil];
+                    }
+            }
+        } else {
+            // Deny invalid URLs so that we don't get the case where we go straight from
+            // webViewShouldLoad -> webViewDidFailLoad (messes up _loadCount).
+            shouldLoad = shouldLoad && [NSURLConnection canHandleRequest:request];
         }
-        VerboseLog(@"webView shouldLoad isTopLevelNavigation=%d state=%d loadCount=%d", isTopLevelNavigation,
_state, _loadCount);
+        VerboseLog(@"webView shouldLoad=%d (after) isTopLevelNavigation=%d state=%d loadCount=%d",
shouldLoad, isTopLevelNavigation, _state, _loadCount);
     }
     return shouldLoad;
 }
@@ -166,28 +214,49 @@ typedef enum {
 {
     VerboseLog(@"webView didStartLoad (before). state=%d loadCount=%d", _state, _loadCount);
     BOOL fireCallback = NO;
-    if (_state == STATE_NORMAL) {
-        if (_loadCount == 0) {
-            fireCallback = [_delegate respondsToSelector:@selector(webViewDidStartLoad:)];
-            _loadCount += 1;
-        } else if (_loadCount > 0) {
-            _loadCount += 1;
-        } else if (!IsAtLeastiOSVersion(@"6.0")) {
+    switch (_state) {
+        case STATE_IDLE:
+            if (IsAtLeastiOSVersion(@"6.0")) {
+                break;
+            }
             // If history.go(-1) is used pre-iOS6, the shouldStartLoadWithRequest function
is not called.
             // Without shouldLoad, we can't distinguish an iframe from a top-level navigation.
             // We could try to distinguish using [UIWebView canGoForward], but that's too
much complexity,
             // and would work only on the first time it was used.
 
             // Our work-around is to set a JS variable and poll until it disappears (from
a naviagtion).
-            _state = STATE_WAITING_FOR_START;
+            _state = STATE_IOS5_POLLING_FOR_LOAD_START;
+            _loadStartPollCount = 0;
             [self setLoadToken:webView];
-        }
-    } else {
-        [self pollForPageLoadStart:webView];
-        [self pollForPageLoadFinish:webView];
+            [self pollForPageLoadStart:webView];
+            break;
+
+        case STATE_WAITING_FOR_LOAD_START:
+            if (_loadCount != 0) {
+                NSLog(@"CDVWebViewDelegate: Unexpected loadCount in didStart. count=%d",
_loadCount);
+            }
+            fireCallback = YES;
+            _state = STATE_WAITING_FOR_LOAD_FINISH;
+            _loadCount = 1;
+            break;
+
+        case STATE_WAITING_FOR_LOAD_FINISH:
+            _loadCount += 1;
+            break;
+
+        case STATE_IOS5_POLLING_FOR_LOAD_START:
+            [self pollForPageLoadStart:webView];
+            break;
+
+        case STATE_IOS5_POLLING_FOR_LOAD_FINISH:
+            [self pollForPageLoadFinish:webView];
+            break;
+
+        default:
+            NSLog(@"CDVWebViewDelegate: Unexpected didStart with state=%d loadCount=%d",
_state, _loadCount);
     }
-    VerboseLog(@"webView didStartLoad (after). state=%d loadCount=%d", _state, _loadCount);
-    if (fireCallback) {
+    VerboseLog(@"webView didStartLoad (after). state=%d loadCount=%d fireCallback=%d", _state,
_loadCount, fireCallback);
+    if (fireCallback && [_delegate respondsToSelector:@selector(webViewDidStartLoad:)])
{
         [_delegate webViewDidStartLoad:webView];
     }
 }
@@ -196,19 +265,32 @@ typedef enum {
 {
     VerboseLog(@"webView didFinishLoad (before). state=%d loadCount=%d", _state, _loadCount);
     BOOL fireCallback = NO;
-    if (_state == STATE_NORMAL) {
-        if (_loadCount == 1) {
-            fireCallback = [_delegate respondsToSelector:@selector(webViewDidFinishLoad:)];
-            _loadCount = -1;
-        } else if (_loadCount > 1) {
+    switch (_state) {
+        case STATE_IDLE:
+            break;
+
+        case STATE_WAITING_FOR_LOAD_START:
+            NSLog(@"CDVWebViewDelegate: Unexpected didFinish while waiting for load start.");
+            break;
+
+        case STATE_WAITING_FOR_LOAD_FINISH:
+            if (_loadCount == 1) {
+                fireCallback = YES;
+                _state = STATE_IDLE;
+            }
             _loadCount -= 1;
-        }
-    } else {
-        [self pollForPageLoadStart:webView];
-        [self pollForPageLoadFinish:webView];
+            break;
+
+        case STATE_IOS5_POLLING_FOR_LOAD_START:
+            [self pollForPageLoadStart:webView];
+            break;
+
+        case STATE_IOS5_POLLING_FOR_LOAD_FINISH:
+            [self pollForPageLoadFinish:webView];
+            break;
     }
-    VerboseLog(@"webView didFinishLoad (after). state=%d loadCount=%d", _state, _loadCount);
-    if (fireCallback) {
+    VerboseLog(@"webView didFinishLoad (after). state=%d loadCount=%d fireCallback=%d", _state,
_loadCount, fireCallback);
+    if (fireCallback && [_delegate respondsToSelector:@selector(webViewDidFinishLoad:)])
{
         [_delegate webViewDidFinishLoad:webView];
     }
 }
@@ -218,19 +300,33 @@ typedef enum {
     VerboseLog(@"webView didFailLoad (before). state=%d loadCount=%d", _state, _loadCount);
     BOOL fireCallback = NO;
 
-    if (_state == STATE_NORMAL) {
-        if (_loadCount == 1) {
-            fireCallback = [_delegate respondsToSelector:@selector(webView:didFailLoadWithError:)];
+    switch (_state) {
+        case STATE_IDLE:
+            break;
+
+        case STATE_WAITING_FOR_LOAD_START:
+            _state = STATE_IDLE;
+            fireCallback = YES;
+            break;
+
+        case STATE_WAITING_FOR_LOAD_FINISH:
+            if (_loadCount == 1) {
+                _state = STATE_IDLE;
+                fireCallback = YES;
+            }
             _loadCount = -1;
-        } else if (_loadCount > 1) {
-            _loadCount -= 1;
-        }
-    } else {
-        [self pollForPageLoadStart:webView];
-        [self pollForPageLoadFinish:webView];
+            break;
+
+        case STATE_IOS5_POLLING_FOR_LOAD_START:
+            [self pollForPageLoadStart:webView];
+            break;
+
+        case STATE_IOS5_POLLING_FOR_LOAD_FINISH:
+            [self pollForPageLoadFinish:webView];
+            break;
     }
-    VerboseLog(@"webView didFailLoad (after). state=%d loadCount=%d", _state, _loadCount);
-    if (fireCallback) {
+    VerboseLog(@"webView didFailLoad (after). state=%d loadCount=%d, fireCallback=%d", _state,
_loadCount, fireCallback);
+    if (fireCallback && [_delegate respondsToSelector:@selector(webView:didFailLoadWithError:)])
{
         [_delegate webView:webView didFailLoadWithError:error];
     }
 }


Mime
View raw message