FrameLoadDelegate.mm 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. /*
  2. * Copyright (C) 2007 Apple Inc. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
  14. * its contributors may be used to endorse or promote products derived
  15. * from this software without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
  18. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  19. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  20. * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
  21. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  22. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  23. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  24. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  26. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27. */
  28. #import "config.h"
  29. #import "DumpRenderTree.h"
  30. #import "FrameLoadDelegate.h"
  31. #import "AccessibilityController.h"
  32. #import "AppleScriptController.h"
  33. #import "EventSendingController.h"
  34. #import "Foundation/NSNotification.h"
  35. #import "GCController.h"
  36. #import "TestRunner.h"
  37. #import "NavigationController.h"
  38. #import "ObjCController.h"
  39. #import "ObjCPlugin.h"
  40. #import "ObjCPluginFunction.h"
  41. #import "TextInputController.h"
  42. #import "WebCoreTestSupport.h"
  43. #import "WorkQueue.h"
  44. #import "WorkQueueItem.h"
  45. #import <JavaScriptCore/JavaScriptCore.h>
  46. #import <WebKitSystemInterface.h>
  47. #import <WebKit/WebFramePrivate.h>
  48. #import <WebKit/WebHTMLViewPrivate.h>
  49. #import <WebKit/WebKit.h>
  50. #import <WebKit/WebNSURLExtras.h>
  51. #import <WebKit/WebScriptWorld.h>
  52. #import <WebKit/WebSecurityOriginPrivate.h>
  53. #import <WebKit/WebViewPrivate.h>
  54. #import <wtf/Assertions.h>
  55. #ifndef NSEC_PER_MSEC
  56. #define NSEC_PER_MSEC 1000000ull
  57. #endif
  58. @interface NSURL (DRTExtras)
  59. - (NSString *)_drt_descriptionSuitableForTestResult;
  60. @end
  61. @interface NSError (DRTExtras)
  62. - (NSString *)_drt_descriptionSuitableForTestResult;
  63. @end
  64. @interface NSURLResponse (DRTExtras)
  65. - (NSString *)_drt_descriptionSuitableForTestResult;
  66. @end
  67. @interface NSURLRequest (DRTExtras)
  68. - (NSString *)_drt_descriptionSuitableForTestResult;
  69. @end
  70. @interface WebFrame (DRTExtras)
  71. - (NSString *)_drt_descriptionSuitableForTestResult;
  72. @end
  73. @implementation WebFrame (DRTExtras)
  74. - (NSString *)_drt_descriptionSuitableForTestResult
  75. {
  76. BOOL isMainFrame = (self == [[self webView] mainFrame]);
  77. NSString *name = [self name];
  78. if (isMainFrame) {
  79. if ([name length])
  80. return [NSString stringWithFormat:@"main frame \"%@\"", name];
  81. else
  82. return @"main frame";
  83. } else {
  84. if (name)
  85. return [NSString stringWithFormat:@"frame \"%@\"", name];
  86. else
  87. return @"frame (anonymous)";
  88. }
  89. }
  90. - (NSString *)_drt_printFrameUserGestureStatus
  91. {
  92. BOOL isUserGesture = [[self webView] _isProcessingUserGesture];
  93. return [NSString stringWithFormat:@"Frame with user gesture \"%@\"", isUserGesture ? @"true" : @"false"];
  94. }
  95. @end
  96. @implementation FrameLoadDelegate
  97. - (id)init
  98. {
  99. if ((self = [super init])) {
  100. gcController = new GCController;
  101. accessibilityController = new AccessibilityController;
  102. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(webViewProgressFinishedNotification:) name:WebViewProgressFinishedNotification object:nil];
  103. }
  104. return self;
  105. }
  106. - (void)dealloc
  107. {
  108. [[NSNotificationCenter defaultCenter] removeObserver:self];
  109. delete gcController;
  110. delete accessibilityController;
  111. [super dealloc];
  112. }
  113. // Exec messages in the work queue until they're all done, or one of them starts a new load
  114. - (void)processWork:(id)dummy
  115. {
  116. // if another load started, then wait for it to complete.
  117. if (topLoadingFrame)
  118. return;
  119. // if we finish all the commands, we're ready to dump state
  120. if (WorkQueue::shared()->processWork() && !gTestRunner->waitToDump())
  121. dump();
  122. }
  123. - (void)resetToConsistentState
  124. {
  125. accessibilityController->resetToConsistentState();
  126. }
  127. - (void)webView:(WebView *)c locationChangeDone:(NSError *)error forDataSource:(WebDataSource *)dataSource
  128. {
  129. if ([dataSource webFrame] == topLoadingFrame) {
  130. topLoadingFrame = nil;
  131. WorkQueue::shared()->setFrozen(true); // first complete load freezes the queue for the rest of this test
  132. if (!gTestRunner->waitToDump()) {
  133. if (WorkQueue::shared()->count())
  134. [self performSelector:@selector(processWork:) withObject:nil afterDelay:0];
  135. else
  136. dump();
  137. }
  138. }
  139. }
  140. #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
  141. static NSString *testPathFromURL(NSURL* url)
  142. {
  143. if ([url isFileURL]) {
  144. NSString *filePath = [url path];
  145. NSRange layoutTestsRange = [filePath rangeOfString:@"/LayoutTests/"];
  146. if (layoutTestsRange.location == NSNotFound)
  147. return nil;
  148. return [filePath substringFromIndex:NSMaxRange(layoutTestsRange)];
  149. }
  150. // HTTP test URLs look like: http://127.0.0.1:8000/inspector/resource-tree/resource-request-content-after-loading-and-clearing-cache.html
  151. if (![[url scheme] isEqualToString:@"http"] && ![[url scheme] isEqualToString:@"https"])
  152. return nil;
  153. if ([[url host] isEqualToString:@"127.0.0.1"] && ([[url port] intValue] == 8000 || [[url port] intValue] == 8443))
  154. return [url path];
  155. return nil;
  156. }
  157. #endif
  158. - (void)webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame
  159. {
  160. ASSERT([frame provisionalDataSource]);
  161. #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
  162. if (!done && [[sender mainFrame] isEqual:frame]) {
  163. NSURL *provisionalLoadURL = [[[frame provisionalDataSource] initialRequest] URL];
  164. if (NSString *testPath = testPathFromURL(provisionalLoadURL))
  165. WKSetCrashReportApplicationSpecificInformation((CFStringRef)[@"CRASHING TEST: " stringByAppendingString:testPath]);
  166. }
  167. #endif
  168. if (!done && gTestRunner->dumpFrameLoadCallbacks()) {
  169. NSString *string = [NSString stringWithFormat:@"%@ - didStartProvisionalLoadForFrame", [frame _drt_descriptionSuitableForTestResult]];
  170. printf ("%s\n", [string UTF8String]);
  171. }
  172. if (!done && gTestRunner->dumpUserGestureInFrameLoadCallbacks()) {
  173. NSString *string = [NSString stringWithFormat:@"%@ - in didStartProvisionalLoadForFrame", [frame _drt_printFrameUserGestureStatus]];
  174. printf ("%s\n", [string UTF8String]);
  175. }
  176. // Make sure we only set this once per test. If it gets cleared, and then set again, we might
  177. // end up doing two dumps for one test.
  178. if (!topLoadingFrame && !done)
  179. topLoadingFrame = frame;
  180. if (!done && gTestRunner->stopProvisionalFrameLoads()) {
  181. NSString *string = [NSString stringWithFormat:@"%@ - stopping load in didStartProvisionalLoadForFrame callback", [frame _drt_descriptionSuitableForTestResult]];
  182. printf ("%s\n", [string UTF8String]);
  183. [frame stopLoading];
  184. }
  185. if (!done && gTestRunner->useDeferredFrameLoading()) {
  186. [sender setDefersCallbacks:YES];
  187. int64_t deferredWaitTime = 5 * NSEC_PER_MSEC;
  188. dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, deferredWaitTime);
  189. dispatch_after(when, dispatch_get_main_queue(), ^{
  190. [sender setDefersCallbacks:NO];
  191. });
  192. }
  193. }
  194. - (void)webView:(WebView *)sender didCommitLoadForFrame:(WebFrame *)frame
  195. {
  196. if (!done && gTestRunner->dumpFrameLoadCallbacks()) {
  197. NSString *string = [NSString stringWithFormat:@"%@ - didCommitLoadForFrame", [frame _drt_descriptionSuitableForTestResult]];
  198. printf ("%s\n", [string UTF8String]);
  199. }
  200. ASSERT(![frame provisionalDataSource]);
  201. ASSERT([frame dataSource]);
  202. gTestRunner->setWindowIsKey(true);
  203. NSView *documentView = [[mainFrame frameView] documentView];
  204. [[[mainFrame webView] window] makeFirstResponder:documentView];
  205. }
  206. - (void)webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame
  207. {
  208. if (!done && gTestRunner->dumpFrameLoadCallbacks()) {
  209. NSString *string = [NSString stringWithFormat:@"%@ - didFailProvisionalLoadWithError", [frame _drt_descriptionSuitableForTestResult]];
  210. printf("%s\n", [string UTF8String]);
  211. }
  212. if ([error domain] == NSURLErrorDomain && ([error code] == NSURLErrorServerCertificateHasUnknownRoot || [error code] == NSURLErrorServerCertificateUntrusted)) {
  213. // <http://webkit.org/b/31200> In order to prevent extra frame load delegate logging being generated if the first test to use SSL
  214. // is set to log frame load delegate calls we ignore SSL certificate errors on localhost and 127.0.0.1 from within dumpRenderTree.
  215. // Those are the only hosts that we use SSL with at present. If we hit this code path then we've found another host that we need
  216. // to apply the workaround to.
  217. ASSERT_NOT_REACHED();
  218. return;
  219. }
  220. ASSERT([frame provisionalDataSource]);
  221. [self webView:sender locationChangeDone:error forDataSource:[frame provisionalDataSource]];
  222. }
  223. - (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame
  224. {
  225. ASSERT([frame dataSource]);
  226. ASSERT(frame == [[frame dataSource] webFrame]);
  227. if (!done && gTestRunner->dumpFrameLoadCallbacks()) {
  228. NSString *string = [NSString stringWithFormat:@"%@ - didFinishLoadForFrame", [frame _drt_descriptionSuitableForTestResult]];
  229. printf ("%s\n", [string UTF8String]);
  230. }
  231. // FIXME: This call to displayIfNeeded can be removed when <rdar://problem/5092361> is fixed.
  232. // After that is fixed, we will reenable painting after WebCore is done loading the document,
  233. // and this call will no longer be needed.
  234. if ([[sender mainFrame] isEqual:frame])
  235. [sender displayIfNeeded];
  236. [self webView:sender locationChangeDone:nil forDataSource:[frame dataSource]];
  237. [gNavigationController webView:sender didFinishLoadForFrame:frame];
  238. }
  239. - (void)webView:(WebView *)sender didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame
  240. {
  241. if (!done && gTestRunner->dumpFrameLoadCallbacks()) {
  242. NSString *string = [NSString stringWithFormat:@"%@ - didFailLoadWithError", [frame _drt_descriptionSuitableForTestResult]];
  243. printf ("%s\n", [string UTF8String]);
  244. }
  245. ASSERT(![frame provisionalDataSource]);
  246. ASSERT([frame dataSource]);
  247. [self webView:sender locationChangeDone:error forDataSource:[frame dataSource]];
  248. }
  249. - (void)webView:(WebView *)webView windowScriptObjectAvailable:(WebScriptObject *)windowScriptObject
  250. {
  251. if (!done && gTestRunner->dumpFrameLoadCallbacks()) {
  252. NSString *string = [NSString stringWithFormat:@"?? - windowScriptObjectAvailable"];
  253. printf ("%s\n", [string UTF8String]);
  254. }
  255. ASSERT_NOT_REACHED();
  256. }
  257. - (void)didClearWindowObjectInStandardWorldForFrame:(WebFrame *)frame
  258. {
  259. // Make New-Style TestRunner
  260. JSContextRef context = [frame globalContext];
  261. JSObjectRef globalObject = JSContextGetGlobalObject(context);
  262. JSValueRef exception = 0;
  263. ASSERT(gTestRunner);
  264. gTestRunner->makeWindowObject(context, globalObject, &exception);
  265. ASSERT(!exception);
  266. gcController->makeWindowObject(context, globalObject, &exception);
  267. ASSERT(!exception);
  268. accessibilityController->makeWindowObject(context, globalObject, &exception);
  269. ASSERT(!exception);
  270. WebCoreTestSupport::injectInternalsObject(context);
  271. // Make Old-Style controllers
  272. WebView *webView = [frame webView];
  273. WebScriptObject *obj = [frame windowObject];
  274. AppleScriptController *asc = [[AppleScriptController alloc] initWithWebView:webView];
  275. [obj setValue:asc forKey:@"appleScriptController"];
  276. [asc release];
  277. EventSendingController *esc = [[EventSendingController alloc] init];
  278. [obj setValue:esc forKey:@"eventSender"];
  279. [esc release];
  280. [obj setValue:gNavigationController forKey:@"navigationController"];
  281. ObjCController *occ = [[ObjCController alloc] init];
  282. [obj setValue:occ forKey:@"objCController"];
  283. [occ release];
  284. ObjCPlugin *plugin = [[ObjCPlugin alloc] init];
  285. [obj setValue:plugin forKey:@"objCPlugin"];
  286. [plugin release];
  287. ObjCPluginFunction *pluginFunction = [[ObjCPluginFunction alloc] init];
  288. [obj setValue:pluginFunction forKey:@"objCPluginFunction"];
  289. [pluginFunction release];
  290. TextInputController *tic = [[TextInputController alloc] initWithWebView:webView];
  291. [obj setValue:tic forKey:@"textInputController"];
  292. [tic release];
  293. }
  294. - (void)didClearWindowObjectForFrame:(WebFrame *)frame inIsolatedWorld:(WebScriptWorld *)world
  295. {
  296. JSGlobalContextRef ctx = [frame _globalContextForScriptWorld:world];
  297. if (!ctx)
  298. return;
  299. JSObjectRef globalObject = JSContextGetGlobalObject(ctx);
  300. if (!globalObject)
  301. return;
  302. JSObjectSetProperty(ctx, globalObject, JSRetainPtr<JSStringRef>(Adopt, JSStringCreateWithUTF8CString("__worldID")).get(), JSValueMakeNumber(ctx, worldIDForWorld(world)), kJSPropertyAttributeReadOnly, 0);
  303. }
  304. - (void)webView:(WebView *)sender didClearWindowObjectForFrame:(WebFrame *)frame inScriptWorld:(WebScriptWorld *)world
  305. {
  306. if (world == [WebScriptWorld standardWorld])
  307. [self didClearWindowObjectInStandardWorldForFrame:frame];
  308. else
  309. [self didClearWindowObjectForFrame:frame inIsolatedWorld:world];
  310. }
  311. - (void)webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame
  312. {
  313. if (!done && gTestRunner->dumpFrameLoadCallbacks()) {
  314. NSString *string = [NSString stringWithFormat:@"%@ - didReceiveTitle: %@", [frame _drt_descriptionSuitableForTestResult], title];
  315. printf ("%s\n", [string UTF8String]);
  316. }
  317. if (gTestRunner->dumpTitleChanges())
  318. printf("TITLE CHANGED: '%s'\n", [title UTF8String]);
  319. }
  320. - (void)webView:(WebView *)sender didReceiveServerRedirectForProvisionalLoadForFrame:(WebFrame *)frame
  321. {
  322. if (!done && gTestRunner->dumpFrameLoadCallbacks()) {
  323. NSString *string = [NSString stringWithFormat:@"%@ - didReceiveServerRedirectForProvisionalLoadForFrame", [frame _drt_descriptionSuitableForTestResult]];
  324. printf ("%s\n", [string UTF8String]);
  325. }
  326. }
  327. - (void)webView:(WebView *)sender didChangeLocationWithinPageForFrame:(WebFrame *)frame
  328. {
  329. if (!done && gTestRunner->dumpFrameLoadCallbacks()) {
  330. NSString *string = [NSString stringWithFormat:@"%@ - didChangeLocationWithinPageForFrame", [frame _drt_descriptionSuitableForTestResult]];
  331. printf ("%s\n", [string UTF8String]);
  332. }
  333. }
  334. - (void)webView:(WebView *)sender willPerformClientRedirectToURL:(NSURL *)URL delay:(NSTimeInterval)seconds fireDate:(NSDate *)date forFrame:(WebFrame *)frame
  335. {
  336. if (!done && gTestRunner->dumpFrameLoadCallbacks()) {
  337. NSString *string = [NSString stringWithFormat:@"%@ - willPerformClientRedirectToURL: %@ ", [frame _drt_descriptionSuitableForTestResult], [URL _drt_descriptionSuitableForTestResult]];
  338. printf ("%s\n", [string UTF8String]);
  339. }
  340. if (!done && gTestRunner->dumpUserGestureInFrameLoadCallbacks()) {
  341. NSString *string = [NSString stringWithFormat:@"%@ - in willPerformClientRedirect", [frame _drt_printFrameUserGestureStatus]];
  342. printf ("%s\n", [string UTF8String]);
  343. }
  344. }
  345. - (void)webView:(WebView *)sender didCancelClientRedirectForFrame:(WebFrame *)frame
  346. {
  347. if (!done && gTestRunner->dumpFrameLoadCallbacks()) {
  348. NSString *string = [NSString stringWithFormat:@"%@ - didCancelClientRedirectForFrame", [frame _drt_descriptionSuitableForTestResult]];
  349. printf ("%s\n", [string UTF8String]);
  350. }
  351. }
  352. - (void)webView:(WebView *)sender didFinishDocumentLoadForFrame:(WebFrame *)frame
  353. {
  354. if (!done && gTestRunner->dumpFrameLoadCallbacks()) {
  355. NSString *string = [NSString stringWithFormat:@"%@ - didFinishDocumentLoadForFrame", [frame _drt_descriptionSuitableForTestResult]];
  356. printf ("%s\n", [string UTF8String]);
  357. } else if (!done) {
  358. unsigned pendingFrameUnloadEvents = [frame _pendingFrameUnloadEventCount];
  359. if (pendingFrameUnloadEvents) {
  360. NSString *string = [NSString stringWithFormat:@"%@ - has %u onunload handler(s)", [frame _drt_descriptionSuitableForTestResult], pendingFrameUnloadEvents];
  361. printf ("%s\n", [string UTF8String]);
  362. }
  363. }
  364. }
  365. - (void)webView:(WebView *)sender didHandleOnloadEventsForFrame:(WebFrame *)frame
  366. {
  367. if (!done && gTestRunner->dumpFrameLoadCallbacks()) {
  368. NSString *string = [NSString stringWithFormat:@"%@ - didHandleOnloadEventsForFrame", [frame _drt_descriptionSuitableForTestResult]];
  369. printf ("%s\n", [string UTF8String]);
  370. }
  371. }
  372. - (void)webViewDidDisplayInsecureContent:(WebView *)sender
  373. {
  374. if (!done && gTestRunner->dumpFrameLoadCallbacks())
  375. printf ("didDisplayInsecureContent\n");
  376. }
  377. - (void)webView:(WebView *)sender didRunInsecureContent:(WebSecurityOrigin *)origin
  378. {
  379. if (!done && gTestRunner->dumpFrameLoadCallbacks())
  380. printf ("didRunInsecureContent\n");
  381. }
  382. - (void)webView:(WebView *)sender didDetectXSS:(NSURL *)insecureURL
  383. {
  384. if (!done && gTestRunner->dumpFrameLoadCallbacks())
  385. printf ("didDetectXSS\n");
  386. }
  387. - (void)webViewProgressFinishedNotification:(NSNotification *)notification
  388. {
  389. if (!done && gTestRunner->dumpProgressFinishedCallback())
  390. printf ("postProgressFinishedNotification\n");
  391. }
  392. @end