Reviewed by Maciej.
[WebKit-https.git] / WebKit / Loader / WebFrameLoader.m
1 /*
2  * Copyright (C) 2006 Apple Computer, 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
29 #import "WebFrameLoader.h"
30
31 #import "WebDataProtocol.h"
32 #import "WebDataSourceInternal.h"
33 #import "WebFrameBridge.h"
34 #import "WebFrameInternal.h"
35 #import "WebFrameLoadDelegate.h"
36 #import "WebIconDatabasePrivate.h"
37 #import "WebKitErrorsPrivate.h"
38 #import "WebKitLogging.h"
39 #import "WebKitNSStringExtras.h"
40 #import "WebMainResourceLoader.h"
41 #import "WebNSDictionaryExtras.h"
42 #import "WebNSURLExtras.h"
43 #import "WebPreferences.h"
44 #import "WebResourcePrivate.h"
45 #import "WebScriptDebugServerPrivate.h"
46 #import "WebViewInternal.h"
47 #import <JavaScriptCore/Assertions.h>
48 #import <WebKit/DOMHTML.h>
49
50 @implementation WebFrameLoader
51
52 - (id)initWithClient:(WebFrame <WebFrameLoaderClient> *)c
53 {
54     self = [super init];
55     if (self) {
56         client = c;
57         state = WebFrameStateCommittedPage;
58     }
59     return self;    
60 }
61
62 - (void)dealloc
63 {
64     // FIXME: should these even exist?
65     [mainResourceLoader release];
66     [subresourceLoaders release];
67     [plugInStreamLoaders release];
68     [documentLoadState release];
69     [provisionalDocumentLoadState release];
70  
71     ASSERT(!policyDocumentLoadState);
72     
73     [super dealloc];
74 }
75
76 - (WebDocumentLoadState *)activeDocumentLoadState
77 {
78     if (state == WebFrameStateProvisional)
79         return provisionalDocumentLoadState;
80     
81     return documentLoadState;    
82 }
83
84 - (WebDataSource *)activeDataSource
85 {
86     return [client _dataSourceForDocumentLoadState:[self activeDocumentLoadState]];
87 }
88
89 - (WebResource *)_archivedSubresourceForURL:(NSURL *)URL
90 {
91     return [[self activeDataSource] _archivedSubresourceForURL:URL];
92 }
93
94 - (void)addPlugInStreamLoader:(WebLoader *)loader
95 {
96     if (!plugInStreamLoaders)
97         plugInStreamLoaders = [[NSMutableArray alloc] init];
98     [plugInStreamLoaders addObject:loader];
99     [[self activeDocumentLoadState] setLoading:YES];
100 }
101
102 - (void)removePlugInStreamLoader:(WebLoader *)loader
103 {
104     [plugInStreamLoaders removeObject:loader];
105     [[self activeDocumentLoadState] updateLoading];
106 }    
107
108 - (void)defersCallbacksChanged
109 {
110     [self setDefersCallbacks:[[client webView] defersCallbacks]];
111 }
112
113 - (BOOL)defersCallbacks
114 {
115     return [[client webView] defersCallbacks];
116 }
117
118 - (void)setDefersCallbacks:(BOOL)defers
119 {
120     [mainResourceLoader setDefersCallbacks:defers];
121     
122     NSEnumerator *e = [subresourceLoaders objectEnumerator];
123     WebLoader *loader;
124     while ((loader = [e nextObject]))
125         [loader setDefersCallbacks:defers];
126     
127     e = [plugInStreamLoaders objectEnumerator];
128     while ((loader = [e nextObject]))
129         [loader setDefersCallbacks:defers];
130
131     [self deliverArchivedResourcesAfterDelay];
132 }
133
134 - (void)stopLoadingPlugIns
135 {
136     [plugInStreamLoaders makeObjectsPerformSelector:@selector(cancel)];
137     [plugInStreamLoaders removeAllObjects];   
138 }
139
140 - (BOOL)isLoadingMainResource
141 {
142     return mainResourceLoader != nil;
143 }
144
145 - (BOOL)isLoadingSubresources
146 {
147     return [subresourceLoaders count];
148 }
149
150 - (BOOL)isLoadingPlugIns
151 {
152     return [plugInStreamLoaders count];
153 }
154
155 - (BOOL)isLoading
156 {
157     return [self isLoadingMainResource] || [self isLoadingSubresources] || [self isLoadingPlugIns];
158 }
159
160 - (void)stopLoadingSubresources
161 {
162     NSArray *loaders = [subresourceLoaders copy];
163     [loaders makeObjectsPerformSelector:@selector(cancel)];
164     [loaders release];
165     [subresourceLoaders removeAllObjects];
166 }
167
168 - (void)addSubresourceLoader:(WebLoader *)loader
169 {
170     ASSERT(!provisionalDocumentLoadState);
171     if (subresourceLoaders == nil)
172         subresourceLoaders = [[NSMutableArray alloc] init];
173     [subresourceLoaders addObject:loader];
174     [[self activeDocumentLoadState] setLoading:YES];
175 }
176
177 - (void)removeSubresourceLoader:(WebLoader *)loader
178 {
179     [subresourceLoaders removeObject:loader];
180     [[self activeDocumentLoadState] updateLoading];
181 }
182
183 - (NSData *)mainResourceData
184 {
185     return [mainResourceLoader resourceData];
186 }
187
188 - (void)releaseMainResourceLoader
189 {
190     [mainResourceLoader release];
191     mainResourceLoader = nil;
192 }
193
194 - (void)cancelMainResourceLoad
195 {
196     [mainResourceLoader cancel];
197 }
198
199 - (BOOL)startLoadingMainResourceWithRequest:(NSMutableURLRequest *)request identifier:(id)identifier
200 {
201     mainResourceLoader = [[WebMainResourceLoader alloc] initWithFrameLoader:self];
202     
203     [mainResourceLoader setIdentifier:identifier];
204     [client _addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:NO];
205     if (![mainResourceLoader loadWithRequest:request]) {
206         // FIXME: if this should really be caught, we should just ASSERT this doesn't happen;
207         // should it be caught by other parts of WebKit or other parts of the app?
208         LOG_ERROR("could not create WebResourceHandle for URL %@ -- should be caught by policy handler level", [request URL]);
209         [mainResourceLoader release];
210         mainResourceLoader = nil;
211         return NO;
212     }
213     
214     return YES;
215 }
216
217 - (void)stopLoadingWithError:(NSError *)error
218 {
219     [mainResourceLoader cancelWithError:error];
220 }
221
222 - (WebDataSource *)dataSource
223 {
224     return [client _dataSourceForDocumentLoadState:documentLoadState]; 
225 }
226
227 - (void)_setDocumentLoadState:(WebDocumentLoadState *)loadState
228 {
229     if (loadState == nil && documentLoadState == nil)
230         return;
231     
232     ASSERT(loadState != documentLoadState);
233     
234     [client _prepareForDataSourceReplacement];
235     [documentLoadState detachFromFrameLoader];
236     
237     [loadState retain];
238     [documentLoadState release];
239     documentLoadState = loadState;
240 }
241
242 - (WebDocumentLoadState *)documentLoadState
243 {
244     return documentLoadState;
245 }
246
247 - (WebDataSource *)policyDataSource
248 {
249     return [client _dataSourceForDocumentLoadState:policyDocumentLoadState];     
250 }
251
252 - (void)_setPolicyDocumentLoadState:(WebDocumentLoadState *)loadState
253 {
254     [loadState retain];
255     [policyDocumentLoadState release];
256     policyDocumentLoadState = loadState;
257 }
258    
259 - (void)clearDataSource
260 {
261     [self _setDocumentLoadState:nil];
262 }
263
264 - (WebDataSource *)provisionalDataSource 
265 {
266     return [client _dataSourceForDocumentLoadState:provisionalDocumentLoadState]; 
267 }
268
269 - (WebDocumentLoadState *)provisionalDocumentLoadState
270 {
271     return provisionalDocumentLoadState;
272 }
273
274 - (void)_setProvisionalDocumentLoadState:(WebDocumentLoadState *)loadState
275 {
276     ASSERT(!loadState || !provisionalDocumentLoadState);
277
278     if (provisionalDocumentLoadState != documentLoadState)
279         [provisionalDocumentLoadState detachFromFrameLoader];
280
281     [loadState retain];
282     [provisionalDocumentLoadState release];
283     provisionalDocumentLoadState = loadState;
284 }
285
286 - (void)_clearProvisionalDataSource
287 {
288     [self _setProvisionalDocumentLoadState:nil];
289 }
290
291 - (WebFrameState)state
292 {
293     return state;
294 }
295
296 #ifndef NDEBUG
297 static const char * const stateNames[] = {
298     "WebFrameStateProvisional",
299     "WebFrameStateCommittedPage",
300     "WebFrameStateComplete"
301 };
302 #endif
303
304 static CFAbsoluteTime _timeOfLastCompletedLoad;
305
306 + (CFAbsoluteTime)timeOfLastCompletedLoad
307 {
308     return _timeOfLastCompletedLoad;
309 }
310
311 - (void)_setState:(WebFrameState)newState
312 {
313     LOG(Loading, "%@:  transition from %s to %s", [client name], stateNames[state], stateNames[newState]);
314     if ([client webView])
315         LOG(Timing, "%@:  transition from %s to %s, %f seconds since start of document load", [client name], stateNames[state], stateNames[newState], CFAbsoluteTimeGetCurrent() - [[[[[client webView] mainFrame] dataSource] _documentLoadState] loadingStartedTime]);
316     
317     if (newState == WebFrameStateComplete && client == [[client webView] mainFrame])
318         LOG(DocumentLoad, "completed %@ (%f seconds)", [[[self dataSource] request] URL], CFAbsoluteTimeGetCurrent() - [[[self dataSource] _documentLoadState] loadingStartedTime]);
319     
320     state = newState;
321     
322     if (state == WebFrameStateProvisional)
323         [client _provisionalLoadStarted];
324     else if (state == WebFrameStateComplete) {
325         [client _frameLoadCompleted];
326         _timeOfLastCompletedLoad = CFAbsoluteTimeGetCurrent();
327         [[self dataSource] _stopRecordingResponses];
328     }
329 }
330
331 - (void)clearProvisionalLoad
332 {
333     [self _setProvisionalDocumentLoadState:nil];
334     [[client webView] _progressCompleted:client];
335     [self _setState:WebFrameStateComplete];
336 }
337
338 - (void)markLoadComplete
339 {
340     [self _setState:WebFrameStateComplete];
341 }
342
343 - (void)commitProvisionalLoad
344 {
345     [self stopLoadingSubresources];
346     [self stopLoadingPlugIns];
347
348     [self _setDocumentLoadState:provisionalDocumentLoadState];
349     [self _setProvisionalDocumentLoadState:nil];
350     [self _setState:WebFrameStateCommittedPage];
351 }
352
353 - (void)stopLoading
354 {
355     [[self provisionalDocumentLoadState] stopLoading];
356     [[self documentLoadState] stopLoading];
357     [self _clearProvisionalDataSource];
358     [self clearArchivedResources];
359 }
360
361 // FIXME: poor method name; also why is this not part of startProvisionalLoad:?
362 - (void)startLoading
363 {
364     [[self provisionalDataSource] _startLoading];
365 }
366
367 - (void)startProvisionalLoad:(WebDataSource *)ds
368 {
369     [self _setProvisionalDocumentLoadState:[ds _documentLoadState]];
370     [self _setState:WebFrameStateProvisional];
371 }
372
373 - (void)setupForReplace
374 {
375     [self _setState:WebFrameStateProvisional];
376     WebDocumentLoadState *old = provisionalDocumentLoadState;
377     provisionalDocumentLoadState = documentLoadState;
378     documentLoadState = nil;
379     [old release];
380     
381     [client _detachChildren];
382 }
383
384 - (id)_identifierForInitialRequest:(NSURLRequest *)clientRequest
385 {
386     return [[self activeDataSource] _identifierForInitialRequest:clientRequest];
387 }
388
389 - (NSURLRequest *)_willSendRequest:(NSMutableURLRequest *)clientRequest forResource:(id)identifier redirectResponse:(NSURLResponse *)redirectResponse
390 {
391     return [[self activeDataSource] _willSendRequest:clientRequest forResource:identifier redirectResponse:redirectResponse];
392 }
393
394 - (void)_didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)currentWebChallenge forResource:(id)identifier
395 {
396     [[self activeDataSource] _didReceiveAuthenticationChallenge:currentWebChallenge forResource:identifier];
397 }
398
399 - (void)_didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)currentWebChallenge forResource:(id)identifier
400 {
401     [[self activeDataSource] _didCancelAuthenticationChallenge:currentWebChallenge forResource:identifier];
402 }
403
404 - (void)_didReceiveResponse:(NSURLResponse *)r forResource:(id)identifier
405 {
406     [[self activeDataSource] _didReceiveResponse:r forResource:identifier];
407 }
408
409 - (void)_didReceiveData:(NSData *)data contentLength:(int)lengthReceived forResource:(id)identifier
410 {
411     [[self activeDataSource] _didReceiveData:data contentLength:lengthReceived forResource:identifier];
412 }
413
414 - (void)_didFinishLoadingForResource:(id)identifier
415 {
416     [[self activeDataSource] _didFinishLoadingForResource:identifier];
417 }
418
419 - (void)_didFailLoadingWithError:(NSError *)error forResource:(id)identifier
420 {
421     [[self activeDataSource] _didFailLoadingWithError:error forResource:identifier];
422 }
423
424 - (BOOL)_privateBrowsingEnabled
425 {
426     return [[[client webView] preferences] privateBrowsingEnabled];
427 }
428
429 - (void)_finishedLoadingResource
430 {
431     [client _checkLoadComplete];
432 }
433
434 - (void)_receivedError:(NSError *)error
435 {
436     [client _checkLoadComplete];
437 }
438
439 - (NSURLRequest *)_originalRequest
440 {
441     return [[self activeDocumentLoadState] originalRequestCopy];
442 }
443
444 - (WebFrame *)webFrame
445 {
446     return client;
447 }
448
449 - (void)_receivedMainResourceError:(NSError *)error complete:(BOOL)isComplete
450 {
451     WebDataSource *ds = [self activeDataSource];
452     [ds retain];
453     [ds _receivedMainResourceError:error complete:isComplete];
454     [ds release];
455 }
456
457 - (NSURLRequest *)initialRequest
458 {
459     return [[self activeDataSource] initialRequest];
460 }
461
462 - (void)_receivedData:(NSData *)data
463 {
464     [[self activeDocumentLoadState] receivedData:data];
465 }
466
467 - (void)_setRequest:(NSURLRequest *)request
468 {
469     [[self activeDocumentLoadState] setRequest:request];
470 }
471
472 - (void)_downloadWithLoadingConnection:(NSURLConnection *)connection request:(NSURLRequest *)request response:(NSURLResponse *)r proxy:(id)proxy
473 {
474     [[self activeDataSource] _downloadWithLoadingConnection:connection request:request response:r proxy:proxy];
475 }
476
477 - (WebFrameBridge *)bridge
478 {
479     return [client _bridge];
480 }
481
482 - (void)_handleFallbackContent
483 {
484     [[self bridge] handleFallbackContent];
485 }
486
487 - (BOOL)_isStopping
488 {
489     return [[self activeDocumentLoadState] isStopping];
490 }
491
492 - (void)_setupForReplaceByMIMEType:(NSString *)newMIMEType
493 {
494     [[self activeDocumentLoadState] setupForReplaceByMIMEType:newMIMEType];
495 }
496
497 - (void)_setResponse:(NSURLResponse *)response
498 {
499     [[self activeDocumentLoadState] setResponse:response];
500 }
501
502 - (void)_mainReceivedError:(NSError *)error complete:(BOOL)isComplete
503 {
504     [[self activeDocumentLoadState] mainReceivedError:error complete:isComplete];
505 }
506
507 - (void)_finishedLoading
508 {
509     WebDataSource *ds = [self activeDataSource];
510     
511     [self retain];
512     [[self activeDocumentLoadState] finishedLoading];
513
514     if ([ds _mainDocumentError] || ![ds webFrame]) {
515         [self release];
516         return;
517     }
518
519     [[self activeDocumentLoadState] setPrimaryLoadComplete:YES];
520     if ([WebScriptDebugServer listenerCount])
521         [[WebScriptDebugServer sharedScriptDebugServer] webView:[client webView] didLoadMainResourceForDataSource:[self activeDataSource]];
522     [client _checkLoadComplete];
523
524     [self release];
525 }
526
527 - (void)_notifyIconChanged:(NSURL *)iconURL
528 {
529     ASSERT([[WebIconDatabase sharedIconDatabase] _isEnabled]);
530     ASSERT(client == [[client webView] mainFrame]);
531
532     [[client webView] _willChangeValueForKey:_WebMainFrameIconKey];
533     
534     NSImage *icon = [[WebIconDatabase sharedIconDatabase] iconForURL:[[[self activeDataSource] _URL] _web_originalDataAsString] withSize:WebIconSmallSize];
535     
536     [[[client webView] _frameLoadDelegateForwarder] webView:[client webView]
537                                                didReceiveIcon:icon
538                                                      forFrame:client];
539     
540     [[client webView] _didChangeValueForKey:_WebMainFrameIconKey];
541 }
542
543 - (NSURL *)_URL
544 {
545     return [[self activeDataSource] _URL];
546 }
547
548 - (NSError *)cancelledErrorWithRequest:(NSURLRequest *)request
549 {
550     return [NSError _webKitErrorWithDomain:NSURLErrorDomain
551                                       code:NSURLErrorCancelled
552                                        URL:[request URL]];
553 }
554
555 - (NSError *)fileDoesNotExistErrorWithResponse:(NSURLResponse *)response
556 {
557     return [NSError _webKitErrorWithDomain:NSURLErrorDomain
558                                                 code:NSURLErrorFileDoesNotExist
559                                                  URL:[response URL]];    
560 }
561
562 - (void)clearArchivedResources
563 {
564     [pendingArchivedResources removeAllObjects];
565     [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(deliverArchivedResources) object:nil];
566 }
567
568 - (void)deliverArchivedResources
569 {
570     if (![pendingArchivedResources count] || [self defersCallbacks])
571         return;
572         
573     NSEnumerator *keyEnum = [pendingArchivedResources keyEnumerator];
574     WebLoader *loader;
575     while ((loader = [keyEnum nextObject])) {
576         WebResource *resource = [pendingArchivedResources objectForKey:loader];
577         [loader didReceiveResponse:[resource _response]];
578         NSData *data = [resource data];
579         [loader didReceiveData:data lengthReceived:[data length] allAtOnce:YES];
580         [loader didFinishLoading];
581     }
582     
583     [pendingArchivedResources removeAllObjects];
584 }
585
586 - (void)deliverArchivedResourcesAfterDelay
587 {
588     if (![pendingArchivedResources count] || [self defersCallbacks])
589         return;
590     
591     [self performSelector:@selector(deliverArchivedResources) withObject:nil afterDelay:0];
592 }
593
594 static BOOL isCaseInsensitiveEqual(NSString *a, NSString *b)
595 {
596     return [a caseInsensitiveCompare:b] == NSOrderedSame;
597 }
598
599 // The following 2 methods are copied from [NSHTTPURLProtocol _cachedResponsePassesValidityChecks] and modified for our needs.
600 // FIXME: It would be nice to eventually to share this code somehow.
601 - (BOOL)_canUseResourceForRequest:(NSURLRequest *)theRequest
602 {
603     NSURLRequestCachePolicy policy = [theRequest cachePolicy];
604     
605     if (policy == NSURLRequestReturnCacheDataElseLoad) {
606         return YES;
607     } else if (policy == NSURLRequestReturnCacheDataDontLoad) {
608         return YES;
609     } else if (policy == NSURLRequestReloadIgnoringCacheData) {
610         return NO;
611     } else if ([theRequest valueForHTTPHeaderField:@"must-revalidate"] != nil) {
612         return NO;
613     } else if ([theRequest valueForHTTPHeaderField:@"proxy-revalidate"] != nil) {
614         return NO;
615     } else if ([theRequest valueForHTTPHeaderField:@"If-Modified-Since"] != nil) {
616         return NO;
617     } else if ([theRequest valueForHTTPHeaderField:@"Cache-Control"] != nil) {
618         return NO;
619     } else if (isCaseInsensitiveEqual(@"POST", [theRequest HTTPMethod])) {
620         return NO;
621     } else {
622         return YES;
623     }
624 }
625
626 - (BOOL)_canUseResourceWithResponse:(NSURLResponse *)theResponse
627 {
628     if (WKGetNSURLResponseMustRevalidate(theResponse)) {
629         return NO;
630     } else if (WKGetNSURLResponseCalculatedExpiration(theResponse) - CFAbsoluteTimeGetCurrent() < 1) {
631         return NO;
632     } else {
633         return YES;
634     }
635 }
636
637 - (NSMutableDictionary *)pendingArchivedResources
638 {
639     if (!pendingArchivedResources)
640         pendingArchivedResources = [[NSMutableDictionary alloc] init];
641     
642     return pendingArchivedResources;
643 }
644
645 - (BOOL)willUseArchiveForRequest:(NSURLRequest *)r originalURL:(NSURL *)originalURL loader:(WebLoader *)loader
646 {
647     if ([[r URL] isEqual:originalURL] && [self _canUseResourceForRequest:r]) {
648         WebResource *resource = [self _archivedSubresourceForURL:originalURL];
649         if (resource && [self _canUseResourceWithResponse:[resource _response]]) {
650             [[self pendingArchivedResources] _webkit_setObject:resource forUncopiedKey:loader];
651             // Deliver the resource after a delay because callers don't expect to receive callbacks while calling this method.
652             [self deliverArchivedResourcesAfterDelay];
653             return YES;
654         }
655     }
656     return NO;
657 }
658
659 - (BOOL)archiveLoadPendingForLoader:(WebLoader *)loader
660 {
661     return [pendingArchivedResources objectForKey:loader] != nil;
662 }
663
664 - (void)cancelPendingArchiveLoadForLoader:(WebLoader *)loader
665 {
666     [pendingArchivedResources removeObjectForKey:loader];
667     
668     if (![pendingArchivedResources count])
669         [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(deliverArchivedResources) object:nil];
670 }
671
672 - (void)_addExtraFieldsToRequest:(NSMutableURLRequest *)request mainResource:(BOOL)mainResource alwaysFromRequest:(BOOL)f
673 {
674     [client _addExtraFieldsToRequest:request mainResource:mainResource alwaysFromRequest:f];
675 }
676
677 - (void)cannotShowMIMETypeForURL:(NSURL *)URL
678 {
679     [client _handleUnimplementablePolicyWithErrorCode:WebKitErrorCannotShowMIMEType forURL:URL];    
680 }
681
682 - (NSError *)interruptForPolicyChangeErrorWithRequest:(NSURLRequest *)request
683 {
684     return [NSError _webKitErrorWithDomain:WebKitErrorDomain code:WebKitErrorFrameLoadInterruptedByPolicyChange URL:[request URL]];
685 }
686
687 - (BOOL)isHostedByObjectElement
688 {
689     // Handle <object> fallback for error cases.            
690     DOMHTMLElement *hostElement = [client frameElement];
691     return hostElement && [hostElement isKindOfClass:[DOMHTMLObjectElement class]];
692 }
693
694 - (BOOL)isLoadingMainFrame
695 {
696     return [client _isMainFrame];
697 }
698
699 + (BOOL)_canShowMIMEType:(NSString *)MIMEType
700 {
701     return [WebView canShowMIMEType:MIMEType];
702 }
703
704 + (BOOL)_representationExistsForURLScheme:(NSString *)URLScheme
705 {
706     return [WebView _representationExistsForURLScheme:URLScheme];
707 }
708
709 + (NSString *)_generatedMIMETypeForURLScheme:(NSString *)URLScheme
710 {
711     return [WebView _generatedMIMETypeForURLScheme:URLScheme];
712 }
713
714 - (void)_checkNavigationPolicyForRequest:(NSURLRequest *)newRequest andCall:(id)obj withSelector:(SEL)sel
715 {
716     [client _checkNavigationPolicyForRequest:newRequest
717                                     dataSource:[self activeDataSource]
718                                      formState:nil
719                                        andCall:obj
720                                   withSelector:sel];
721 }
722
723 - (void)_checkContentPolicyForMIMEType:(NSString *)MIMEType andCall:(id)obj withSelector:(SEL)sel
724 {
725     WebPolicyDecisionListener *l = [[WebPolicyDecisionListener alloc] _initWithTarget:obj action:sel];
726     listener = l;
727     
728     [l retain];
729     [[self activeDataSource] _decidePolicyForMIMEType:MIMEType decisionListener:l];
730     [l release];
731 }
732
733 - (void)cancelContentPolicy
734 {
735     [listener _invalidate];
736     [listener release];
737     listener = nil;
738 }
739
740 - (void)_loadRequest:(NSURLRequest *)request archive:(WebArchive *)archive
741 {
742     WebFrameLoadType loadType;
743     
744     policyDocumentLoadState = [client _createDocumentLoadStateWithRequest:request];
745     WebDataSource *newDataSource = [client _dataSourceForDocumentLoadState:policyDocumentLoadState];
746
747     NSMutableURLRequest *r = [newDataSource request];
748     [client _addExtraFieldsToRequest:r mainResource:YES alwaysFromRequest:NO];
749     if ([client _shouldTreatURLAsSameAsCurrent:[request URL]]) {
750         [r setCachePolicy:NSURLRequestReloadIgnoringCacheData];
751         loadType = WebFrameLoadTypeSame;
752     } else
753         loadType = WebFrameLoadTypeStandard;
754     
755     [newDataSource _setOverrideEncoding:[[self dataSource] _overrideEncoding]];
756     [newDataSource _addToUnarchiveState:archive];
757     
758     // When we loading alternate content for an unreachable URL that we're
759     // visiting in the b/f list, we treat it as a reload so the b/f list 
760     // is appropriately maintained.
761     if ([client _shouldReloadToHandleUnreachableURLFromRequest:request]) {
762         ASSERT(loadType == WebFrameLoadTypeStandard);
763         loadType = WebFrameLoadTypeReload;
764     }
765     
766     [client _loadDataSource:newDataSource withLoadType:loadType formState:nil];
767 }
768
769 - (void)_loadRequest:(NSURLRequest *)request triggeringAction:(NSDictionary *)action loadType:(WebFrameLoadType)loadType formState:(WebFormState *)formState
770 {
771     policyDocumentLoadState = [client _createDocumentLoadStateWithRequest:request];
772     WebDataSource *newDataSource = [client _dataSourceForDocumentLoadState:policyDocumentLoadState];
773
774     [newDataSource _setTriggeringAction:action];
775
776     [newDataSource _setOverrideEncoding:[[self dataSource] _overrideEncoding]];
777
778     [client _loadDataSource:newDataSource withLoadType:loadType formState:formState];
779 }
780
781 - (void)_reloadAllowingStaleDataWithOverrideEncoding:(NSString *)encoding
782 {
783     WebDataSource *ds = [self dataSource];
784     if (ds == nil)
785         return;
786
787     NSMutableURLRequest *request = [[ds request] mutableCopy];
788     NSURL *unreachableURL = [ds unreachableURL];
789     if (unreachableURL != nil)
790         [request setURL:unreachableURL];
791
792     [request setCachePolicy:NSURLRequestReturnCacheDataElseLoad];
793     policyDocumentLoadState = [client _createDocumentLoadStateWithRequest:request];
794     WebDataSource *newDataSource = [client _dataSourceForDocumentLoadState:policyDocumentLoadState];
795     [request release];
796     
797     [newDataSource _setOverrideEncoding:encoding];
798
799     [client _loadDataSource:newDataSource withLoadType:WebFrameLoadTypeReloadAllowingStaleData formState:nil];
800 }
801
802 - (void)reload
803 {
804     WebDataSource *ds = [self dataSource];
805     if (ds == nil)
806         return;
807
808     NSMutableURLRequest *initialRequest = [ds request];
809     
810     // If a window is created by javascript, its main frame can have an empty but non-nil URL.
811     // Reloading in this case will lose the current contents (see 4151001).
812     if ([[[[ds request] URL] absoluteString] length] == 0)
813         return;
814
815     // Replace error-page URL with the URL we were trying to reach.
816     NSURL *unreachableURL = [initialRequest _webDataRequestUnreachableURL];
817     if (unreachableURL != nil)
818         initialRequest = [NSURLRequest requestWithURL:unreachableURL];
819     
820     policyDocumentLoadState = [client _createDocumentLoadStateWithRequest:initialRequest];
821     WebDataSource *newDataSource = [client _dataSourceForDocumentLoadState:policyDocumentLoadState];
822     NSMutableURLRequest *request = [newDataSource request];
823
824     [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
825
826     // If we're about to rePOST, set up action so the app can warn the user
827     if ([[request HTTPMethod] _webkit_isCaseInsensitiveEqualToString:@"POST"]) {
828         NSDictionary *action = [client _actionInformationForNavigationType:WebNavigationTypeFormResubmitted event:nil originalURL:[request URL]];
829         [newDataSource _setTriggeringAction:action];
830     }
831
832     [newDataSource _setOverrideEncoding:[ds _overrideEncoding]];
833     
834     [client _loadDataSource:newDataSource withLoadType:WebFrameLoadTypeReload formState:nil];
835 }
836
837 - (void)didReceiveServerRedirectForProvisionalLoadForFrame
838 {
839     [client _didReceiveServerRedirectForProvisionalLoadForFrame];
840 }
841
842 - (void)finishedLoadingDocumentLoadState:(WebDocumentLoadState *)loadState
843 {
844     [[client _dataSourceForDocumentLoadState:loadState] _finishedLoading];
845 }
846
847 - (void)commitProvisitionalLoad
848 {
849     [client _commitProvisionalLoad:nil];
850 }
851
852 - (void)committedLoadWithDocumentLoadState:(WebDocumentLoadState *)loadState data:(NSData *)data
853 {
854     [[client _dataSourceForDocumentLoadState:loadState] _receivedData:data];
855 }
856
857 - (BOOL)isReplacing
858 {
859     return [client _loadType] == WebFrameLoadTypeReplace;
860 }
861
862 - (void)setReplacing
863 {
864     [client _setLoadType:WebFrameLoadTypeReplace];
865 }
866
867 - (void)revertToProvisionalWithDocumentLoadState:(WebDocumentLoadState *)loadState
868 {
869     [[client _dataSourceForDocumentLoadState:loadState] _revertToProvisionalState];
870 }
871
872 - (void)documentLoadState:(WebDocumentLoadState *)loadState setMainDocumentError:(NSError *)error
873 {
874     [[client _dataSourceForDocumentLoadState:loadState] _setMainDocumentError:error];
875 }
876
877 - (void)documentLoadState:(WebDocumentLoadState *)loadState mainReceivedCompleteError:(NSError *)error
878 {
879     [loadState setPrimaryLoadComplete:YES];
880     if ([WebScriptDebugServer listenerCount])
881         [[WebScriptDebugServer sharedScriptDebugServer] webView:[client webView] didLoadMainResourceForDataSource:[self activeDataSource]];
882     [client _checkLoadComplete];
883 }
884
885 - (void)finalSetupForReplaceWithDocumentLoadState:(WebDocumentLoadState *)loadState
886 {
887     [[client _dataSourceForDocumentLoadState:loadState] _clearUnarchivingState];
888 }
889
890 - (void)prepareForLoadStart
891 {
892     [[client webView] _progressStarted:client];
893     [[client webView] _didStartProvisionalLoadForFrame:client];
894     [[[client webView] _frameLoadDelegateForwarder] webView:[client webView]
895                                didStartProvisionalLoadForFrame:client];    
896 }
897
898 - (BOOL)subframeIsLoading
899 {
900     return [client _subframeIsLoading];
901 }
902
903 @end