Changeset 48687 in webkit
- Timestamp:
- Sep 23, 2009 4:27:01 PM (15 years ago)
- Location:
- trunk/WebCore
- Files:
-
- 2 added
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/WebCore/ChangeLog
r48686 r48687 1 2009-09-23 Darin Adler <darin@apple.com> 2 3 Reviewed by Sam Weinig. 4 5 Crash when website does a history.back() followed by an alert() 6 https://bugs.webkit.org/show_bug.cgi?id=29686 7 rdar://problem/6984996 8 9 When loading is deferred, we need to defer timer-based loads 10 too, not just networking-driven loads. Otherwise we can get 11 syncronouse navigation while running a script, which leads to 12 crashes and other badness. 13 14 This patch includes a manual test; an automated test may be 15 possible some time in the future. 16 17 * dom/Document.cpp: 18 (WebCore::Document::processHttpEquiv): Use scheduleLocationChange 19 instead of scheduleHTTPRedirection to implement the navigation 20 needed for x-frame-options. 21 22 * loader/FrameLoader.cpp: 23 (WebCore::FrameLoader::FrameLoader): Updated for data members with 24 new names and new data members. 25 (WebCore::FrameLoader::setDefersLoading): When turning deferral 26 off, call startRedirectionTimer and startCheckCompleteTimer, since 27 either of them might have been fired and ignored while defersLoading 28 was true. 29 (WebCore::FrameLoader::clear): Updated for replacement of the 30 m_checkCompletedTimer and m_checkLoadCompleteTimer timers. 31 (WebCore::FrameLoader::allAncestorsAreComplete): Added. 32 (WebCore::FrameLoader::checkCompleted): Added code to set 33 m_shouldCallCheckCompleted to false. Changed code that calls 34 startRedirectionTimer to call it unconditionally, since that 35 function now knows when to do work and doesn't expect callers 36 to handle that any more. 37 (WebCore::FrameLoader::checkTimerFired): Added. Replaces the old 38 timer fired callbacks. Calls checkCompleted and checkLoadComplete 39 as appropriate, but not when defersLoading is true. 40 (WebCore::FrameLoader::startCheckCompleteTimer): Added. Replaces 41 the two different calls to start timers before. Only starts the 42 timers if they are needed. 43 (WebCore::FrameLoader::scheduleCheckCompleted): Changed to call 44 startCheckCompleteTimer after setting boolean. 45 (WebCore::FrameLoader::scheduleCheckLoadComplete): Ditto. 46 (WebCore::FrameLoader::scheduleHistoryNavigation): Removed 47 canGoBackOrForward check. The logic works more naturally when 48 we don't do anything until the timer fires. 49 (WebCore::FrameLoader::redirectionTimerFired): Do nothing if 50 defersLoading is true. Also moved canGoBackOrForward check here. 51 (WebCore::FrameLoader::scheduleRedirection): Changed code that 52 calls startRedirectionTimer to do so unconditionally. That 53 function now handles the rules about when to start the timer 54 rather than expecting the caller to do so. 55 (WebCore::FrameLoader::startRedirectionTimer): Added code to 56 handle the case where there is no redirection scheduled, 57 where the timer is already active, or where this is a classic 58 redirection and there is an ancestor that has not yet completed 59 loading. 60 (WebCore::FrameLoader::completed): Call startRedirectionTimer 61 here directly instead of calling a cover named parentCompleted. 62 Hooray! One less function in the giant FrameLoader class! 63 (WebCore::FrameLoader::checkLoadComplete): Added code to set 64 m_shouldCallCheckLoadComplete to false. 65 66 * loader/FrameLoader.h: Replaced the two functions 67 checkCompletedTimerFired and checkLoadCompleteTimerFired with 68 one function, checkTimerFired. Removed the parentCompleted 69 function. Added the startCheckCompleteTimer and 70 allAncestorsAreComplete functions. Replaced the 71 m_checkCompletedTimer and m_checkLoadCompleteTimer data 72 members with m_checkTimer, m_shouldCallCheckCompleted, and 73 m_shouldCallCheckLoadComplete. 74 75 * manual-tests/go-back-after-alert.html: Added. 76 * manual-tests/resources/alert-and-go-back.html: Added. 77 1 78 2009-09-23 David Kilzer <ddkilzer@apple.com> 2 79 -
trunk/WebCore/dom/Document.cpp
r48559 r48687 2174 2174 if (frameLoader->shouldInterruptLoadForXFrameOptions(content, url())) { 2175 2175 frameLoader->stopAllLoaders(); 2176 frameLoader->schedule HTTPRedirection(0, blankURL());2176 frameLoader->scheduleLocationChange(blankURL(), String()); 2177 2177 } 2178 2178 } -
trunk/WebCore/loader/FrameLoader.cpp
r48680 r48687 273 273 , m_containsPlugIns(false) 274 274 , m_redirectionTimer(this, &FrameLoader::redirectionTimerFired) 275 , m_checkCompletedTimer(this, &FrameLoader::checkCompletedTimerFired) 276 , m_checkLoadCompleteTimer(this, &FrameLoader::checkLoadCompleteTimerFired) 275 , m_checkTimer(this, &FrameLoader::checkTimerFired) 276 , m_shouldCallCheckCompleted(false) 277 , m_shouldCallCheckLoadComplete(false) 277 278 , m_opener(0) 278 279 , m_openedByDOM(false) … … 324 325 if (m_policyDocumentLoader) 325 326 m_policyDocumentLoader->setDefersLoading(defers); 327 328 if (!defers) { 329 startRedirectionTimer(); 330 startCheckCompleteTimer(); 331 } 326 332 } 327 333 … … 850 856 m_scheduledRedirection.clear(); 851 857 852 m_checkCompletedTimer.stop(); 853 m_checkLoadCompleteTimer.stop(); 858 m_checkTimer.stop(); 859 m_shouldCallCheckCompleted = false; 860 m_shouldCallCheckLoadComplete = false; 854 861 855 862 m_receivedData = false; … … 1253 1260 } 1254 1261 1262 bool FrameLoader::allAncestorsAreComplete() const 1263 { 1264 for (Frame* ancestor = m_frame; ancestor; ancestor = ancestor->tree()->parent()) { 1265 if (!ancestor->loader()->m_isComplete) 1266 return false; 1267 } 1268 return true; 1269 } 1270 1255 1271 void FrameLoader::checkCompleted() 1256 1272 { 1273 m_shouldCallCheckCompleted = false; 1274 1257 1275 if (m_frame->view()) 1258 1276 m_frame->view()->checkStopDelayingDeferredRepaints(); … … 1280 1298 checkCallImplicitClose(); // if we didn't do it before 1281 1299 1282 // Do not start a redirection timer for subframes here. 1283 // That is deferred until the parent is completed. 1284 if (m_scheduledRedirection && !m_frame->tree()->parent()) 1285 startRedirectionTimer(); 1300 startRedirectionTimer(); 1286 1301 1287 1302 completed(); … … 1290 1305 } 1291 1306 1292 void FrameLoader::checkCompletedTimerFired(Timer<FrameLoader>*) 1293 { 1294 checkCompleted(); 1307 void FrameLoader::checkTimerFired(Timer<FrameLoader>*) 1308 { 1309 if (Page* page = m_frame->page()) { 1310 if (page->defersLoading()) 1311 return; 1312 } 1313 if (m_shouldCallCheckCompleted) 1314 checkCompleted(); 1315 if (m_shouldCallCheckLoadComplete) 1316 checkLoadComplete(); 1317 } 1318 1319 void FrameLoader::startCheckCompleteTimer() 1320 { 1321 if (!(m_shouldCallCheckCompleted || m_shouldCallCheckLoadComplete)) 1322 return; 1323 if (m_checkTimer.isActive()) 1324 return; 1325 m_checkTimer.startOneShot(0); 1295 1326 } 1296 1327 1297 1328 void FrameLoader::scheduleCheckCompleted() 1298 1329 { 1299 if (!m_checkCompletedTimer.isActive()) 1300 m_checkCompletedTimer.startOneShot(0); 1301 } 1302 1303 void FrameLoader::checkLoadCompleteTimerFired(Timer<FrameLoader>*) 1304 { 1305 if (!m_frame->page()) 1306 return; 1307 checkLoadComplete(); 1330 m_shouldCallCheckCompleted = true; 1331 startCheckCompleteTimer(); 1308 1332 } 1309 1333 1310 1334 void FrameLoader::scheduleCheckLoadComplete() 1311 1335 { 1312 if (!m_checkLoadCompleteTimer.isActive())1313 m_checkLoadCompleteTimer.startOneShot(0);1336 m_shouldCallCheckLoadComplete = true; 1337 startCheckCompleteTimer(); 1314 1338 } 1315 1339 … … 1439 1463 if (!m_frame->page()) 1440 1464 return; 1441 1442 // navigation will always be allowed in the 0 steps case, which is OK because that's supposed to force a reload.1443 if (!canGoBackOrForward(steps)) {1444 cancelRedirection();1445 return;1446 }1447 1465 1448 1466 scheduleRedirection(new ScheduledRedirection(steps)); … … 1482 1500 { 1483 1501 ASSERT(m_frame->page()); 1502 1503 if (m_frame->page()->defersLoading()) 1504 return; 1484 1505 1485 1506 OwnPtr<ScheduledRedirection> redirection(m_scheduledRedirection.release()); … … 1499 1520 // go(i!=0) from a frame navigates into the history of the frame only, 1500 1521 // in both IE and NS (but not in Mozilla). We can't easily do that. 1501 goBackOrForward(redirection->historySteps); 1522 if (canGoBackOrForward(redirection->historySteps)) 1523 goBackOrForward(redirection->historySteps); 1502 1524 return; 1503 1525 case ScheduledRedirection::formSubmission: … … 1721 1743 1722 1744 return widget != 0; 1723 }1724 1725 void FrameLoader::parentCompleted()1726 {1727 if (m_scheduledRedirection && !m_redirectionTimer.isActive())1728 startRedirectionTimer();1729 1745 } 1730 1746 … … 2140 2156 if (!m_isComplete && m_scheduledRedirection->type != ScheduledRedirection::redirection) 2141 2157 completed(); 2142 if (m_isComplete || m_scheduledRedirection->type != ScheduledRedirection::redirection) 2143 startRedirectionTimer(); 2158 startRedirectionTimer(); 2144 2159 } 2145 2160 2146 2161 void FrameLoader::startRedirectionTimer() 2147 2162 { 2163 if (!m_scheduledRedirection) 2164 return; 2165 2148 2166 ASSERT(m_frame->page()); 2149 ASSERT(m_scheduledRedirection); 2150 2151 m_redirectionTimer.stop(); 2167 2168 if (m_redirectionTimer.isActive()) 2169 return; 2170 2171 if (m_scheduledRedirection->type == ScheduledRedirection::redirection && !allAncestorsAreComplete()) 2172 return; 2173 2152 2174 m_redirectionTimer.startOneShot(m_scheduledRedirection->delay); 2153 2175 … … 2188 2210 RefPtr<Frame> protect(m_frame); 2189 2211 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) 2190 child->loader()-> parentCompleted();2212 child->loader()->startRedirectionTimer(); 2191 2213 if (Frame* parent = m_frame->tree()->parent()) 2192 2214 parent->loader()->checkCompleted(); … … 3560 3582 ASSERT(m_client->hasWebView()); 3561 3583 3584 m_shouldCallCheckLoadComplete = false; 3585 3562 3586 // FIXME: Always traversing the entire frame tree is a bit inefficient, but 3563 3587 // is currently needed in order to null out the previous history item for all frames. -
trunk/WebCore/loader/FrameLoader.h
r48661 r48687 413 413 414 414 void redirectionTimerFired(Timer<FrameLoader>*); 415 void checkCompletedTimerFired(Timer<FrameLoader>*); 416 void checkLoadCompleteTimerFired(Timer<FrameLoader>*); 415 void checkTimerFired(Timer<FrameLoader>*); 417 416 418 417 void cancelRedirection(bool newLoadInProgress = false); … … 421 420 422 421 void completed(); 423 void parentCompleted();424 422 425 423 bool shouldUsePlugin(const KURL&, const String& mimeType, bool hasFallback, bool& useFallback); … … 540 538 void scheduleCheckCompleted(); 541 539 void scheduleCheckLoadComplete(); 540 void startCheckCompleteTimer(); 542 541 543 542 KURL originalRequestURL() const; … … 547 546 void saveScrollPositionAndViewStateToItem(HistoryItem*); 548 547 548 bool allAncestorsAreComplete() const; // including this 549 549 bool allChildrenAreComplete() const; // immediate children, not all descendants 550 550 … … 613 613 614 614 Timer<FrameLoader> m_redirectionTimer; 615 Timer<FrameLoader> m_checkCompletedTimer; 616 Timer<FrameLoader> m_checkLoadCompleteTimer; 615 Timer<FrameLoader> m_checkTimer; 616 bool m_shouldCallCheckCompleted; 617 bool m_shouldCallCheckLoadComplete; 617 618 618 619 Frame* m_opener;
Note: See TracChangeset
for help on using the changeset viewer.