57e06c14c41ac58410588e8fa43db6d12e3aa8b3
[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 "WebHistory.h"
37 #import "WebIconDatabasePrivate.h"
38 #import "WebKitErrorsPrivate.h"
39 #import "WebKitLogging.h"
40 #import "WebKitNSStringExtras.h"
41 #import "WebMainResourceLoader.h"
42 #import "WebNSDictionaryExtras.h"
43 #import "WebNSURLExtras.h"
44 #import "WebPreferences.h"
45 #import "WebResourcePrivate.h"
46 #import "WebScriptDebugServerPrivate.h"
47 #import "WebViewInternal.h"
48 #import <JavaScriptCore/Assertions.h>
49 #import <WebKit/DOMHTML.h>
50
51 @implementation WebFrameLoader
52
53 - (id)initWithClient:(WebFrame <WebFrameLoaderClient> *)c
54 {
55     self = [super init];
56     if (self) {
57         client = c;
58         state = WebFrameStateCommittedPage;
59     }
60     return self;    
61 }
62
63 - (void)dealloc
64 {
65     // FIXME: should these even exist?
66     [mainResourceLoader release];
67     [subresourceLoaders release];
68     [plugInStreamLoaders release];
69     [documentLoadState release];
70     [provisionalDocumentLoadState release];
71  
72     ASSERT(!policyDocumentLoadState);
73     
74     [super dealloc];
75 }
76
77 - (WebDocumentLoadState *)activeDocumentLoadState
78 {
79     if (state == WebFrameStateProvisional)
80         return provisionalDocumentLoadState;
81     
82     return documentLoadState;    
83 }
84
85 - (WebDataSource *)activeDataSource
86 {
87     return [client _dataSourceForDocumentLoadState:[self activeDocumentLoadState]];
88 }
89
90 - (WebResource *)_archivedSubresourceForURL:(NSURL *)URL
91 {
92     return [[self activeDataSource] _archivedSubresourceForURL:URL];
93 }
94
95 - (void)addPlugInStreamLoader:(WebLoader *)loader
96 {
97     if (!plugInStreamLoaders)
98         plugInStreamLoaders = [[NSMutableArray alloc] init];
99     [plugInStreamLoaders addObject:loader];
100     [[self activeDocumentLoadState] setLoading:YES];
101 }
102
103 - (void)removePlugInStreamLoader:(WebLoader *)loader
104 {
105     [plugInStreamLoaders removeObject:loader];
106     [[self activeDocumentLoadState] updateLoading];
107 }    
108
109 - (void)defersCallbacksChanged
110 {
111     [self setDefersCallbacks:[[client webView] defersCallbacks]];
112 }
113
114 - (BOOL)defersCallbacks
115 {
116     return [[client webView] defersCallbacks];
117 }
118
119 - (void)setDefersCallbacks:(BOOL)defers
120 {
121     [mainResourceLoader setDefersCallbacks:defers];
122     
123     NSEnumerator *e = [subresourceLoaders objectEnumerator];
124     WebLoader *loader;
125     while ((loader = [e nextObject]))
126         [loader setDefersCallbacks:defers];
127     
128     e = [plugInStreamLoaders objectEnumerator];
129     while ((loader = [e nextObject]))
130         [loader setDefersCallbacks:defers];
131
132     [self deliverArchivedResourcesAfterDelay];
133 }
134
135 - (void)stopLoadingPlugIns
136 {
137     [plugInStreamLoaders makeObjectsPerformSelector:@selector(cancel)];
138     [plugInStreamLoaders removeAllObjects];   
139 }
140
141 - (BOOL)isLoadingMainResource
142 {
143     return mainResourceLoader != nil;
144 }
145
146 - (BOOL)isLoadingSubresources
147 {
148     return [subresourceLoaders count];
149 }
150
151 - (BOOL)isLoadingPlugIns
152 {
153     return [plugInStreamLoaders count];
154 }
155
156 - (BOOL)isLoading
157 {
158     return [self isLoadingMainResource] || [self isLoadingSubresources] || [self isLoadingPlugIns];
159 }
160
161 - (void)stopLoadingSubresources
162 {
163     NSArray *loaders = [subresourceLoaders copy];
164     [loaders makeObjectsPerformSelector:@selector(cancel)];
165     [loaders release];
166     [subresourceLoaders removeAllObjects];
167 }
168
169 - (void)addSubresourceLoader:(WebLoader *)loader
170 {
171     ASSERT(!provisionalDocumentLoadState);
172     if (subresourceLoaders == nil)
173         subresourceLoaders = [[NSMutableArray alloc] init];
174     [subresourceLoaders addObject:loader];
175     [[self activeDocumentLoadState] setLoading:YES];
176 }
177
178 - (void)removeSubresourceLoader:(WebLoader *)loader
179 {
180     [subresourceLoaders removeObject:loader];
181     [[self activeDocumentLoadState] updateLoading];
182 }
183
184 - (NSData *)mainResourceData
185 {
186     return [mainResourceLoader resourceData];
187 }
188
189 - (void)releaseMainResourceLoader
190 {
191     [mainResourceLoader release];
192     mainResourceLoader = nil;
193 }
194
195 - (void)cancelMainResourceLoad
196 {
197     [mainResourceLoader cancel];
198 }
199
200 - (BOOL)startLoadingMainResourceWithRequest:(NSMutableURLRequest *)request identifier:(id)identifier
201 {
202     mainResourceLoader = [[WebMainResourceLoader alloc] initWithFrameLoader:self];
203     
204     [mainResourceLoader setIdentifier:identifier];
205     [client _addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:NO];
206     if (![mainResourceLoader loadWithRequest:request]) {
207         // FIXME: if this should really be caught, we should just ASSERT this doesn't happen;
208         // should it be caught by other parts of WebKit or other parts of the app?
209         LOG_ERROR("could not create WebResourceHandle for URL %@ -- should be caught by policy handler level", [request URL]);
210         [mainResourceLoader release];
211         mainResourceLoader = nil;
212         return NO;
213     }
214     
215     return YES;
216 }
217
218 - (void)stopLoadingWithError:(NSError *)error
219 {
220     [mainResourceLoader cancelWithError:error];
221 }
222
223 - (WebDataSource *)dataSource
224 {
225     return [client _dataSourceForDocumentLoadState:documentLoadState]; 
226 }
227
228 - (void)_setDocumentLoadState:(WebDocumentLoadState *)loadState
229 {
230     if (loadState == nil && documentLoadState == nil)
231         return;
232     
233     ASSERT(loadState != documentLoadState);
234     
235     [client _prepareForDataSourceReplacement];
236     [documentLoadState detachFromFrameLoader];
237     
238     [loadState retain];
239     [documentLoadState release];
240     documentLoadState = loadState;
241 }
242
243 - (WebDocumentLoadState *)documentLoadState
244 {
245     return documentLoadState;
246 }
247
248 - (WebDataSource *)policyDataSource
249 {
250     return [client _dataSourceForDocumentLoadState:policyDocumentLoadState];     
251 }
252
253 - (void)_setPolicyDocumentLoadState:(WebDocumentLoadState *)loadState
254 {
255     [loadState retain];
256     [policyDocumentLoadState release];
257     policyDocumentLoadState = loadState;
258 }
259    
260 - (void)clearDataSource
261 {
262     [self _setDocumentLoadState:nil];
263 }
264
265 - (WebDataSource *)provisionalDataSource 
266 {
267     return [client _dataSourceForDocumentLoadState:provisionalDocumentLoadState]; 
268 }
269
270 - (WebDocumentLoadState *)provisionalDocumentLoadState
271 {
272     return provisionalDocumentLoadState;
273 }
274
275 - (void)_setProvisionalDocumentLoadState:(WebDocumentLoadState *)loadState
276 {
277     ASSERT(!loadState || !provisionalDocumentLoadState);
278
279     if (provisionalDocumentLoadState != documentLoadState)
280         [provisionalDocumentLoadState detachFromFrameLoader];
281
282     [loadState retain];
283     [provisionalDocumentLoadState release];
284     provisionalDocumentLoadState = loadState;
285 }
286
287 - (void)_clearProvisionalDataSource
288 {
289     [self _setProvisionalDocumentLoadState:nil];
290 }
291
292 - (WebFrameState)state
293 {
294     return state;
295 }
296
297 #ifndef NDEBUG
298 static const char * const stateNames[] = {
299     "WebFrameStateProvisional",
300     "WebFrameStateCommittedPage",
301     "WebFrameStateComplete"
302 };
303 #endif
304
305 static CFAbsoluteTime _timeOfLastCompletedLoad;
306
307 + (CFAbsoluteTime)timeOfLastCompletedLoad
308 {
309     return _timeOfLastCompletedLoad;
310 }
311
312 - (void)_setState:(WebFrameState)newState
313 {
314     LOG(Loading, "%@:  transition from %s to %s", [client name], stateNames[state], stateNames[newState]);
315     if ([client webView])
316         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]);
317     
318     if (newState == WebFrameStateComplete && client == [[client webView] mainFrame])
319         LOG(DocumentLoad, "completed %@ (%f seconds)", [[[self dataSource] request] URL], CFAbsoluteTimeGetCurrent() - [[[self dataSource] _documentLoadState] loadingStartedTime]);
320     
321     state = newState;
322     
323     if (state == WebFrameStateProvisional)
324         [client _provisionalLoadStarted];
325     else if (state == WebFrameStateComplete) {
326         [client _frameLoadCompleted];
327         _timeOfLastCompletedLoad = CFAbsoluteTimeGetCurrent();
328         [[self documentLoadState] stopRecordingResponses];
329     }
330 }
331
332 - (void)clearProvisionalLoad
333 {
334     [self _setProvisionalDocumentLoadState:nil];
335     [[client webView] _progressCompleted:client];
336     [self _setState:WebFrameStateComplete];
337 }
338
339 - (void)markLoadComplete
340 {
341     [self _setState:WebFrameStateComplete];
342 }
343
344 - (void)commitProvisionalLoad
345 {
346     [self stopLoadingSubresources];
347     [self stopLoadingPlugIns];
348
349     [self _setDocumentLoadState:provisionalDocumentLoadState];
350     [self _setProvisionalDocumentLoadState:nil];
351     [self _setState:WebFrameStateCommittedPage];
352 }
353
354 - (void)stopLoading
355 {
356     [[self provisionalDocumentLoadState] stopLoading];
357     [[self documentLoadState] stopLoading];
358     [self _clearProvisionalDataSource];
359     [self clearArchivedResources];
360 }
361
362 // FIXME: poor method name; also why is this not part of startProvisionalLoad:?
363 - (void)startLoading
364 {
365     [[self provisionalDataSource] _startLoading];
366 }
367
368 - (void)startProvisionalLoad:(WebDataSource *)ds
369 {
370     [self _setProvisionalDocumentLoadState:[ds _documentLoadState]];
371     [self _setState:WebFrameStateProvisional];
372 }
373
374 - (void)setupForReplace
375 {
376     [self _setState:WebFrameStateProvisional];
377     WebDocumentLoadState *old = provisionalDocumentLoadState;
378     provisionalDocumentLoadState = documentLoadState;
379     documentLoadState = nil;
380     [old release];
381     
382     [client _detachChildren];
383 }
384
385 - (id)_identifierForInitialRequest:(NSURLRequest *)clientRequest
386 {
387     return [[self activeDataSource] _identifierForInitialRequest:clientRequest];
388 }
389
390 - (NSURLRequest *)_willSendRequest:(NSMutableURLRequest *)clientRequest forResource:(id)identifier redirectResponse:(NSURLResponse *)redirectResponse
391 {
392     return [[self activeDataSource] _willSendRequest:clientRequest forResource:identifier redirectResponse:redirectResponse];
393 }
394
395 - (void)_didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)currentWebChallenge forResource:(id)identifier
396 {
397     [[self activeDataSource] _didReceiveAuthenticationChallenge:currentWebChallenge forResource:identifier];
398 }
399
400 - (void)_didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)currentWebChallenge forResource:(id)identifier
401 {
402     [[self activeDataSource] _didCancelAuthenticationChallenge:currentWebChallenge forResource:identifier];
403 }
404
405 - (void)_didReceiveResponse:(NSURLResponse *)r forResource:(id)identifier
406 {
407     [[self activeDataSource] _didReceiveResponse:r forResource:identifier];
408 }
409
410 - (void)_didReceiveData:(NSData *)data contentLength:(int)lengthReceived forResource:(id)identifier
411 {
412     [[self activeDataSource] _didReceiveData:data contentLength:lengthReceived forResource:identifier];
413 }
414
415 - (void)_didFinishLoadingForResource:(id)identifier
416 {
417     [[self activeDataSource] _didFinishLoadingForResource:identifier];
418 }
419
420 - (void)_didFailLoadingWithError:(NSError *)error forResource:(id)identifier
421 {
422     [[self activeDataSource] _didFailLoadingWithError:error forResource:identifier];
423 }
424
425 - (BOOL)_privateBrowsingEnabled
426 {
427     return [[[client webView] preferences] privateBrowsingEnabled];
428 }
429
430 - (void)_finishedLoadingResource
431 {
432     [client _checkLoadComplete];
433 }
434
435 - (void)_receivedError:(NSError *)error
436 {
437     [client _checkLoadComplete];
438 }
439
440 - (NSURLRequest *)_originalRequest
441 {
442     return [[self activeDocumentLoadState] originalRequestCopy];
443 }
444
445 - (WebFrame *)webFrame
446 {
447     return client;
448 }
449
450 - (void)_receivedMainResourceError:(NSError *)error complete:(BOOL)isComplete
451 {
452     WebDataSource *ds = [self activeDataSource];
453     [ds retain];
454     [ds _receivedMainResourceError:error complete:isComplete];
455     [ds release];
456 }
457
458 - (NSURLRequest *)initialRequest
459 {
460     return [[self activeDataSource] initialRequest];
461 }
462
463 - (void)_receivedData:(NSData *)data
464 {
465     [[self activeDocumentLoadState] receivedData:data];
466 }
467
468 - (void)_setRequest:(NSURLRequest *)request
469 {
470     [[self activeDocumentLoadState] setRequest:request];
471 }
472
473 - (void)_downloadWithLoadingConnection:(NSURLConnection *)connection request:(NSURLRequest *)request response:(NSURLResponse *)r proxy:(id)proxy
474 {
475     [[self activeDataSource] _downloadWithLoadingConnection:connection request:request response:r proxy:proxy];
476 }
477
478 - (WebFrameBridge *)bridge
479 {
480     return [client _bridge];
481 }
482
483 - (void)_handleFallbackContent
484 {
485     [[self bridge] handleFallbackContent];
486 }
487
488 - (BOOL)_isStopping
489 {
490     return [[self activeDocumentLoadState] isStopping];
491 }
492
493 - (void)_setupForReplaceByMIMEType:(NSString *)newMIMEType
494 {
495     [[self activeDocumentLoadState] setupForReplaceByMIMEType:newMIMEType];
496 }
497
498 - (void)_setResponse:(NSURLResponse *)response
499 {
500     [[self activeDocumentLoadState] setResponse:response];
501 }
502
503 - (void)_mainReceivedError:(NSError *)error complete:(BOOL)isComplete
504 {
505     [[self activeDocumentLoadState] mainReceivedError:error complete:isComplete];
506 }
507
508 - (void)_finishedLoading
509 {
510     WebDataSource *ds = [self activeDataSource];
511     
512     [self retain];
513     [[self activeDocumentLoadState] finishedLoading];
514
515     if ([ds _mainDocumentError] || ![ds webFrame]) {
516         [self release];
517         return;
518     }
519
520     [[self activeDocumentLoadState] setPrimaryLoadComplete:YES];
521     if ([WebScriptDebugServer listenerCount])
522         [[WebScriptDebugServer sharedScriptDebugServer] webView:[client webView] didLoadMainResourceForDataSource:[self activeDataSource]];
523     [client _checkLoadComplete];
524
525     [self release];
526 }
527
528 - (void)_notifyIconChanged:(NSURL *)iconURL
529 {
530     ASSERT([[WebIconDatabase sharedIconDatabase] _isEnabled]);
531     ASSERT(client == [[client webView] mainFrame]);
532
533     [[client webView] _willChangeValueForKey:_WebMainFrameIconKey];
534     
535     NSImage *icon = [[WebIconDatabase sharedIconDatabase] iconForURL:[[[self activeDataSource] _URL] _web_originalDataAsString] withSize:WebIconSmallSize];
536     
537     [[[client webView] _frameLoadDelegateForwarder] webView:[client webView]
538                                                didReceiveIcon:icon
539                                                      forFrame:client];
540     
541     [[client webView] _didChangeValueForKey:_WebMainFrameIconKey];
542 }
543
544 - (NSURL *)_URL
545 {
546     return [[self activeDataSource] _URL];
547 }
548
549 - (NSError *)cancelledErrorWithRequest:(NSURLRequest *)request
550 {
551     return [NSError _webKitErrorWithDomain:NSURLErrorDomain
552                                       code:NSURLErrorCancelled
553                                        URL:[request URL]];
554 }
555
556 - (NSError *)fileDoesNotExistErrorWithResponse:(NSURLResponse *)response
557 {
558     return [NSError _webKitErrorWithDomain:NSURLErrorDomain
559                                                 code:NSURLErrorFileDoesNotExist
560                                                  URL:[response URL]];    
561 }
562
563 - (void)clearArchivedResources
564 {
565     [pendingArchivedResources removeAllObjects];
566     [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(deliverArchivedResources) object:nil];
567 }
568
569 - (void)deliverArchivedResources
570 {
571     if (![pendingArchivedResources count] || [self defersCallbacks])
572         return;
573         
574     NSEnumerator *keyEnum = [pendingArchivedResources keyEnumerator];
575     WebLoader *loader;
576     while ((loader = [keyEnum nextObject])) {
577         WebResource *resource = [pendingArchivedResources objectForKey:loader];
578         [loader didReceiveResponse:[resource _response]];
579         NSData *data = [resource data];
580         [loader didReceiveData:data lengthReceived:[data length] allAtOnce:YES];
581         [loader didFinishLoading];
582     }
583     
584     [pendingArchivedResources removeAllObjects];
585 }
586
587 - (void)deliverArchivedResourcesAfterDelay
588 {
589     if (![pendingArchivedResources count] || [self defersCallbacks])
590         return;
591     
592     [self performSelector:@selector(deliverArchivedResources) withObject:nil afterDelay:0];
593 }
594
595 static BOOL isCaseInsensitiveEqual(NSString *a, NSString *b)
596 {
597     return [a caseInsensitiveCompare:b] == NSOrderedSame;
598 }
599
600 // The following 2 methods are copied from [NSHTTPURLProtocol _cachedResponsePassesValidityChecks] and modified for our needs.
601 // FIXME: It would be nice to eventually to share this code somehow.
602 - (BOOL)_canUseResourceForRequest:(NSURLRequest *)theRequest
603 {
604     NSURLRequestCachePolicy policy = [theRequest cachePolicy];
605     
606     if (policy == NSURLRequestReturnCacheDataElseLoad) {
607         return YES;
608     } else if (policy == NSURLRequestReturnCacheDataDontLoad) {
609         return YES;
610     } else if (policy == NSURLRequestReloadIgnoringCacheData) {
611         return NO;
612     } else if ([theRequest valueForHTTPHeaderField:@"must-revalidate"] != nil) {
613         return NO;
614     } else if ([theRequest valueForHTTPHeaderField:@"proxy-revalidate"] != nil) {
615         return NO;
616     } else if ([theRequest valueForHTTPHeaderField:@"If-Modified-Since"] != nil) {
617         return NO;
618     } else if ([theRequest valueForHTTPHeaderField:@"Cache-Control"] != nil) {
619         return NO;
620     } else if (isCaseInsensitiveEqual(@"POST", [theRequest HTTPMethod])) {
621         return NO;
622     } else {
623         return YES;
624     }
625 }
626
627 - (BOOL)_canUseResourceWithResponse:(NSURLResponse *)theResponse
628 {
629     if (WKGetNSURLResponseMustRevalidate(theResponse)) {
630         return NO;
631     } else if (WKGetNSURLResponseCalculatedExpiration(theResponse) - CFAbsoluteTimeGetCurrent() < 1) {
632         return NO;
633     } else {
634         return YES;
635     }
636 }
637
638 - (NSMutableDictionary *)pendingArchivedResources
639 {
640     if (!pendingArchivedResources)
641         pendingArchivedResources = [[NSMutableDictionary alloc] init];
642     
643     return pendingArchivedResources;
644 }
645
646 - (BOOL)willUseArchiveForRequest:(NSURLRequest *)r originalURL:(NSURL *)originalURL loader:(WebLoader *)loader
647 {
648     if ([[r URL] isEqual:originalURL] && [self _canUseResourceForRequest:r]) {
649         WebResource *resource = [self _archivedSubresourceForURL:originalURL];
650         if (resource && [self _canUseResourceWithResponse:[resource _response]]) {
651             [[self pendingArchivedResources] _webkit_setObject:resource forUncopiedKey:loader];
652             // Deliver the resource after a delay because callers don't expect to receive callbacks while calling this method.
653             [self deliverArchivedResourcesAfterDelay];
654             return YES;
655         }
656     }
657     return NO;
658 }
659
660 - (BOOL)archiveLoadPendingForLoader:(WebLoader *)loader
661 {
662     return [pendingArchivedResources objectForKey:loader] != nil;
663 }
664
665 - (void)cancelPendingArchiveLoadForLoader:(WebLoader *)loader
666 {
667     [pendingArchivedResources removeObjectForKey:loader];
668     
669     if (![pendingArchivedResources count])
670         [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(deliverArchivedResources) object:nil];
671 }
672
673 - (void)_addExtraFieldsToRequest:(NSMutableURLRequest *)request mainResource:(BOOL)mainResource alwaysFromRequest:(BOOL)f
674 {
675     [client _addExtraFieldsToRequest:request mainResource:mainResource alwaysFromRequest:f];
676 }
677
678 - (void)cannotShowMIMETypeForURL:(NSURL *)URL
679 {
680     [self handleUnimplementablePolicyWithErrorCode:WebKitErrorCannotShowMIMEType forURL:URL];    
681 }
682
683 - (NSError *)interruptForPolicyChangeErrorWithRequest:(NSURLRequest *)request
684 {
685     return [NSError _webKitErrorWithDomain:WebKitErrorDomain code:WebKitErrorFrameLoadInterruptedByPolicyChange URL:[request URL]];
686 }
687
688 - (BOOL)isHostedByObjectElement
689 {
690     // Handle <object> fallback for error cases.            
691     DOMHTMLElement *hostElement = [client frameElement];
692     return hostElement && [hostElement isKindOfClass:[DOMHTMLObjectElement class]];
693 }
694
695 - (BOOL)isLoadingMainFrame
696 {
697     return [client _isMainFrame];
698 }
699
700 + (BOOL)_canShowMIMEType:(NSString *)MIMEType
701 {
702     return [WebView canShowMIMEType:MIMEType];
703 }
704
705 + (BOOL)_representationExistsForURLScheme:(NSString *)URLScheme
706 {
707     return [WebView _representationExistsForURLScheme:URLScheme];
708 }
709
710 + (NSString *)_generatedMIMETypeForURLScheme:(NSString *)URLScheme
711 {
712     return [WebView _generatedMIMETypeForURLScheme:URLScheme];
713 }
714
715 - (void)_checkNavigationPolicyForRequest:(NSURLRequest *)newRequest andCall:(id)obj withSelector:(SEL)sel
716 {
717     [self checkNavigationPolicyForRequest:newRequest
718                               dataSource:[self activeDataSource]
719                                 formState:nil
720                                   andCall:obj
721                              withSelector:sel];
722 }
723
724 - (void)_checkContentPolicyForMIMEType:(NSString *)MIMEType andCall:(id)obj withSelector:(SEL)sel
725 {
726     WebPolicyDecisionListener *l = [[WebPolicyDecisionListener alloc] _initWithTarget:obj action:sel];
727     listener = l;
728     
729     [l retain];
730     [[self activeDataSource] _decidePolicyForMIMEType:MIMEType decisionListener:l];
731     [l release];
732 }
733
734 - (void)cancelContentPolicy
735 {
736     [listener _invalidate];
737     [listener release];
738     listener = nil;
739 }
740
741 - (BOOL)shouldReloadToHandleUnreachableURLFromRequest:(NSURLRequest *)request
742 {
743     NSURL *unreachableURL = [request _webDataRequestUnreachableURL];
744     if (unreachableURL == nil) {
745         return NO;
746     }
747     
748     if (policyLoadType != WebFrameLoadTypeForward
749         && policyLoadType != WebFrameLoadTypeBack
750         && policyLoadType != WebFrameLoadTypeIndexedBackForward) {
751         return NO;
752     }
753     
754     // We only treat unreachableURLs specially during the delegate callbacks
755     // for provisional load errors and navigation policy decisions. The former
756     // case handles well-formed URLs that can't be loaded, and the latter
757     // case handles malformed URLs and unknown schemes. Loading alternate content
758     // at other times behaves like a standard load.
759     WebDataSource *compareDataSource = nil;
760     if (delegateIsDecidingNavigationPolicy || delegateIsHandlingUnimplementablePolicy) {
761         compareDataSource = [self policyDataSource];
762     } else if (delegateIsHandlingProvisionalLoadError) {
763         compareDataSource = [self provisionalDataSource];
764     }
765     
766     return compareDataSource != nil && [unreachableURL isEqual:[[compareDataSource request] URL]];
767 }
768
769 - (void)_loadRequest:(NSURLRequest *)request archive:(WebArchive *)archive
770 {
771     WebFrameLoadType type;
772     
773     policyDocumentLoadState = [client _createDocumentLoadStateWithRequest:request];
774     WebDataSource *newDataSource = [client _dataSourceForDocumentLoadState:policyDocumentLoadState];
775
776     NSMutableURLRequest *r = [newDataSource request];
777     [client _addExtraFieldsToRequest:r mainResource:YES alwaysFromRequest:NO];
778     if ([client _shouldTreatURLAsSameAsCurrent:[request URL]]) {
779         [r setCachePolicy:NSURLRequestReloadIgnoringCacheData];
780         type = WebFrameLoadTypeSame;
781     } else
782         type = WebFrameLoadTypeStandard;
783     
784     [policyDocumentLoadState setOverrideEncoding:[[self documentLoadState] overrideEncoding]];
785     [newDataSource _addToUnarchiveState:archive];
786     
787     // When we loading alternate content for an unreachable URL that we're
788     // visiting in the b/f list, we treat it as a reload so the b/f list 
789     // is appropriately maintained.
790     if ([self shouldReloadToHandleUnreachableURLFromRequest:request]) {
791         ASSERT(type == WebFrameLoadTypeStandard);
792         type = WebFrameLoadTypeReload;
793     }
794     
795     [self loadDataSource:newDataSource withLoadType:type formState:nil];
796 }
797
798 - (void)_loadRequest:(NSURLRequest *)request triggeringAction:(NSDictionary *)action loadType:(WebFrameLoadType)type formState:(WebFormState *)formState
799 {
800     policyDocumentLoadState = [client _createDocumentLoadStateWithRequest:request];
801     WebDataSource *newDataSource = [client _dataSourceForDocumentLoadState:policyDocumentLoadState];
802
803     [policyDocumentLoadState setTriggeringAction:action];
804
805     [policyDocumentLoadState setOverrideEncoding:[[self documentLoadState] overrideEncoding]];
806
807     [self loadDataSource:newDataSource withLoadType:type formState:formState];
808 }
809
810 - (void)_reloadAllowingStaleDataWithOverrideEncoding:(NSString *)encoding
811 {
812     WebDataSource *ds = [self dataSource];
813     if (ds == nil)
814         return;
815
816     NSMutableURLRequest *request = [[ds request] mutableCopy];
817     NSURL *unreachableURL = [ds unreachableURL];
818     if (unreachableURL != nil)
819         [request setURL:unreachableURL];
820
821     [request setCachePolicy:NSURLRequestReturnCacheDataElseLoad];
822     policyDocumentLoadState = [client _createDocumentLoadStateWithRequest:request];
823     WebDataSource *newDataSource = [client _dataSourceForDocumentLoadState:policyDocumentLoadState];
824     [request release];
825     
826     [policyDocumentLoadState setOverrideEncoding:encoding];
827
828     [self loadDataSource:newDataSource withLoadType:WebFrameLoadTypeReloadAllowingStaleData formState:nil];
829 }
830
831 - (void)reload
832 {
833     WebDataSource *ds = [self dataSource];
834     if (ds == nil)
835         return;
836
837     NSMutableURLRequest *initialRequest = [ds request];
838     
839     // If a window is created by javascript, its main frame can have an empty but non-nil URL.
840     // Reloading in this case will lose the current contents (see 4151001).
841     if ([[[[ds request] URL] absoluteString] length] == 0)
842         return;
843
844     // Replace error-page URL with the URL we were trying to reach.
845     NSURL *unreachableURL = [initialRequest _webDataRequestUnreachableURL];
846     if (unreachableURL != nil)
847         initialRequest = [NSURLRequest requestWithURL:unreachableURL];
848     
849     policyDocumentLoadState = [client _createDocumentLoadStateWithRequest:initialRequest];
850     WebDataSource *newDataSource = [client _dataSourceForDocumentLoadState:policyDocumentLoadState];
851     NSMutableURLRequest *request = [newDataSource request];
852
853     [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
854
855     // If we're about to rePOST, set up action so the app can warn the user
856     if ([[request HTTPMethod] _webkit_isCaseInsensitiveEqualToString:@"POST"]) {
857         NSDictionary *action = [client _actionInformationForNavigationType:WebNavigationTypeFormResubmitted event:nil originalURL:[request URL]];
858         [policyDocumentLoadState setTriggeringAction:action];
859     }
860
861     [policyDocumentLoadState setOverrideEncoding:[[ds _documentLoadState] overrideEncoding]];
862     
863     [self loadDataSource:newDataSource withLoadType:WebFrameLoadTypeReload formState:nil];
864 }
865
866 - (void)didReceiveServerRedirectForProvisionalLoadForFrame
867 {
868     [client _didReceiveServerRedirectForProvisionalLoadForFrame];
869 }
870
871 - (void)finishedLoadingDocumentLoadState:(WebDocumentLoadState *)loadState
872 {
873     [[client _dataSourceForDocumentLoadState:loadState] _finishedLoading];
874 }
875
876 - (void)commitProvisitionalLoad
877 {
878     [client _commitProvisionalLoad:nil];
879 }
880
881 - (void)committedLoadWithDocumentLoadState:(WebDocumentLoadState *)loadState data:(NSData *)data
882 {
883     [[client _dataSourceForDocumentLoadState:loadState] _receivedData:data];
884 }
885
886 - (BOOL)isReplacing
887 {
888     return loadType == WebFrameLoadTypeReplace;
889 }
890
891 - (void)setReplacing
892 {
893     loadType = WebFrameLoadTypeReplace;
894 }
895
896 - (void)revertToProvisionalWithDocumentLoadState:(WebDocumentLoadState *)loadState
897 {
898     [[client _dataSourceForDocumentLoadState:loadState] _revertToProvisionalState];
899 }
900
901 - (void)documentLoadState:(WebDocumentLoadState *)loadState setMainDocumentError:(NSError *)error
902 {
903     [[client _dataSourceForDocumentLoadState:loadState] _setMainDocumentError:error];
904 }
905
906 - (void)documentLoadState:(WebDocumentLoadState *)loadState mainReceivedCompleteError:(NSError *)error
907 {
908     [loadState setPrimaryLoadComplete:YES];
909     if ([WebScriptDebugServer listenerCount])
910         [[WebScriptDebugServer sharedScriptDebugServer] webView:[client webView] didLoadMainResourceForDataSource:[self activeDataSource]];
911     [client _checkLoadComplete];
912 }
913
914 - (void)finalSetupForReplaceWithDocumentLoadState:(WebDocumentLoadState *)loadState
915 {
916     [[client _dataSourceForDocumentLoadState:loadState] _clearUnarchivingState];
917 }
918
919 - (void)prepareForLoadStart
920 {
921     [[client webView] _progressStarted:client];
922     [[client webView] _didStartProvisionalLoadForFrame:client];
923     [[[client webView] _frameLoadDelegateForwarder] webView:[client webView]
924                                didStartProvisionalLoadForFrame:client];    
925 }
926
927 - (BOOL)subframeIsLoading
928 {
929     return [client _subframeIsLoading];
930 }
931
932 - (void)willChangeTitleForDocumentLoadState:(WebDocumentLoadState *)loadState
933 {
934     // FIXME: should do this only in main frame case, right?
935     [[client webView] _willChangeValueForKey:_WebMainFrameTitleKey];
936 }
937
938 - (void)didChangeTitleForDocumentLoadState:(WebDocumentLoadState *)loadState
939 {
940     // FIXME: should do this only in main frame case, right?
941     [[client webView] _didChangeValueForKey:_WebMainFrameTitleKey];
942
943     // The title doesn't get communicated to the WebView until we are committed.
944     if ([loadState isCommitted]) {
945         NSURL *URLForHistory = [[client _dataSourceForDocumentLoadState:loadState] _URLForHistory];
946         if (URLForHistory != nil) {
947             WebHistoryItem *entry = [[WebHistory optionalSharedHistory] itemForURL:URLForHistory];
948             [entry setTitle:[loadState title]];
949         
950             // Must update the entries in the back-forward list too.  This must go through the WebFrame because
951             // it has the right notion of the current b/f item.
952             [client _setTitle:[loadState title]];
953         
954             [[client webView] setMainFrameDocumentReady:YES];    // update observers with new DOMDocument
955             [[[client webView] _frameLoadDelegateForwarder] webView:[client webView]
956                                                       didReceiveTitle:[loadState title]
957                                                              forFrame:client];
958         }
959     }
960 }
961
962 - (WebFrameLoadType)loadType
963 {
964     return loadType;
965 }
966
967 - (void)setLoadType:(WebFrameLoadType)type
968 {
969     loadType = type;
970 }
971
972 - (void)invalidatePendingPolicyDecisionCallingDefaultAction:(BOOL)call
973 {
974     [listener _invalidate];
975     [listener release];
976     listener = nil;
977
978     NSURLRequest *request = policyRequest;
979     NSString *frameName = policyFrameName;
980     id target = policyTarget;
981     SEL selector = policySelector;
982     WebFormState *formState = policyFormState;
983
984     policyRequest = nil;
985     policyFrameName = nil;
986     policyTarget = nil;
987     policySelector = nil;
988     policyFormState = nil;
989
990     if (call) {
991         if (frameName)
992             objc_msgSend(target, selector, nil, nil, nil);
993         else
994             objc_msgSend(target, selector, nil, nil);
995     }
996
997     [request release];
998     [frameName release];
999     [target release];
1000     [formState release];
1001 }
1002
1003 - (void)checkNewWindowPolicyForRequest:(NSURLRequest *)request action:(NSDictionary *)action frameName:(NSString *)frameName formState:(WebFormState *)formState andCall:(id)target withSelector:(SEL)selector
1004 {
1005     WebPolicyDecisionListener *decisionListener = [[WebPolicyDecisionListener alloc]
1006         _initWithTarget:self action:@selector(_continueAfterNewWindowPolicy:)];
1007
1008     policyRequest = [request retain];
1009     policyTarget = [target retain];
1010     policyFrameName = [frameName retain];
1011     policySelector = selector;
1012     listener = [decisionListener retain];
1013     policyFormState = [formState retain];
1014
1015     WebView *wv = [client webView];
1016     [[wv _policyDelegateForwarder] webView:wv
1017             decidePolicyForNewWindowAction:action
1018                                    request:request
1019                               newFrameName:frameName
1020                           decisionListener:decisionListener];
1021     
1022     [decisionListener release];
1023 }
1024
1025 -(void)_continueAfterNewWindowPolicy:(WebPolicyAction)policy
1026 {
1027     NSURLRequest *request = [[policyRequest retain] autorelease];
1028     NSString *frameName = [[policyFrameName retain] autorelease];
1029     id target = [[policyTarget retain] autorelease];
1030     SEL selector = policySelector;
1031     WebFormState *formState = [[policyFormState retain] autorelease];
1032
1033     // will release policy* objects, hence the above retains
1034     [self invalidatePendingPolicyDecisionCallingDefaultAction:NO];
1035
1036     BOOL shouldContinue = NO;
1037
1038     switch (policy) {
1039     case WebPolicyIgnore:
1040         break;
1041     case WebPolicyDownload:
1042         // FIXME: should download full request
1043         [[client webView] _downloadURL:[request URL]];
1044         break;
1045     case WebPolicyUse:
1046         shouldContinue = YES;
1047         break;
1048     default:
1049         ASSERT_NOT_REACHED();
1050     }
1051
1052     objc_msgSend(target, selector, shouldContinue ? request : nil, frameName, formState);
1053 }
1054
1055 - (void)checkNavigationPolicyForRequest:(NSURLRequest *)request
1056                              dataSource:(WebDataSource *)dataSource
1057                               formState:(WebFormState *)formState
1058                                 andCall:(id)target
1059                            withSelector:(SEL)selector
1060 {
1061     NSDictionary *action = [[dataSource _documentLoadState] triggeringAction];
1062     if (action == nil) {
1063         action = [client _actionInformationForNavigationType:WebNavigationTypeOther event:nil originalURL:[request URL]];
1064         [[dataSource _documentLoadState]  setTriggeringAction:action];
1065     }
1066         
1067     // Don't ask more than once for the same request or if we are loading an empty URL.
1068     // This avoids confusion on the part of the client.
1069     if ([request isEqual:[[dataSource _documentLoadState] lastCheckedRequest]] || [[request URL] _web_isEmpty]) {
1070         [target performSelector:selector withObject:request withObject:nil];
1071         return;
1072     }
1073     
1074     // We are always willing to show alternate content for unreachable URLs;
1075     // treat it like a reload so it maintains the right state for b/f list.
1076     if ([request _webDataRequestUnreachableURL] != nil) {
1077         if (policyLoadType == WebFrameLoadTypeForward
1078                 || policyLoadType == WebFrameLoadTypeBack
1079                 || policyLoadType == WebFrameLoadTypeIndexedBackForward) {
1080             policyLoadType = WebFrameLoadTypeReload;
1081         }
1082         [target performSelector:selector withObject:request withObject:nil];
1083         return;
1084     }
1085     
1086     [[dataSource _documentLoadState] setLastCheckedRequest:request];
1087
1088     WebPolicyDecisionListener *decisionListener = [[WebPolicyDecisionListener alloc] _initWithTarget:self action:@selector(continueAfterNavigationPolicy:)];
1089     
1090     ASSERT(policyRequest == nil);
1091     policyRequest = [request retain];
1092     ASSERT(policyTarget == nil);
1093     policyTarget = [target retain];
1094     policySelector = selector;
1095     ASSERT(listener == nil);
1096     listener = [decisionListener retain];
1097     ASSERT(policyFormState == nil);
1098     policyFormState = [formState retain];
1099
1100     WebView *wv = [client webView];
1101     delegateIsDecidingNavigationPolicy = YES;
1102     [[wv _policyDelegateForwarder] webView:wv
1103            decidePolicyForNavigationAction:action
1104                                    request:request
1105                                      frame:client
1106                           decisionListener:decisionListener];
1107     delegateIsDecidingNavigationPolicy = NO;
1108     
1109     [decisionListener release];
1110 }
1111
1112 - (void)continueAfterNavigationPolicy:(WebPolicyAction)policy
1113 {
1114     NSURLRequest *request = [[policyRequest retain] autorelease];
1115     id target = [[policyTarget retain] autorelease];
1116     SEL selector = policySelector;
1117     WebFormState *formState = [[policyFormState retain] autorelease];
1118     
1119     // will release policy* objects, hence the above retains
1120     [self invalidatePendingPolicyDecisionCallingDefaultAction:NO];
1121
1122     BOOL shouldContinue = NO;
1123
1124     switch (policy) {
1125     case WebPolicyIgnore:
1126         break;
1127     case WebPolicyDownload:
1128         // FIXME: should download full request
1129         [[client webView] _downloadURL:[request URL]];
1130         break;
1131     case WebPolicyUse:
1132         if (![WebView _canHandleRequest:request]) {
1133             [self handleUnimplementablePolicyWithErrorCode:WebKitErrorCannotShowURL forURL:[request URL]];
1134         } else {
1135             shouldContinue = YES;
1136         }
1137         break;
1138     default:
1139         ASSERT_NOT_REACHED();
1140     }
1141
1142     [target performSelector:selector withObject:(shouldContinue ? request : nil) withObject:formState];
1143 }
1144
1145 // Called after the FormsDelegate is done processing willSubmitForm:
1146 - (void)continueAfterWillSubmitForm:(WebPolicyAction)policy
1147 {
1148     if (listener) {
1149         [listener _invalidate];
1150         [listener release];
1151         listener = nil;
1152     }
1153     [self startLoading];
1154 }
1155
1156 - (void)continueLoadRequestAfterNavigationPolicy:(NSURLRequest *)request formState:(WebFormState *)formState
1157 {
1158     // If we loaded an alternate page to replace an unreachableURL, we'll get in here with a
1159     // nil policyDataSource because loading the alternate page will have passed
1160     // through this method already, nested; otherwise, policyDataSource should still be set.
1161     ASSERT([self policyDataSource] || [[self provisionalDataSource] unreachableURL] != nil);
1162
1163     BOOL isTargetItem = [client _provisionalItemIsTarget];
1164
1165     // Two reasons we can't continue:
1166     //    1) Navigation policy delegate said we can't so request is nil. A primary case of this 
1167     //       is the user responding Cancel to the form repost nag sheet.
1168     //    2) User responded Cancel to an alert popped up by the before unload event handler.
1169     // The "before unload" event handler runs only for the main frame.
1170     BOOL canContinue = request && ([[client webView] mainFrame] != client || [[self bridge] shouldClose]);
1171
1172     if (!canContinue) {
1173         // If we were waiting for a quick redirect, but the policy delegate decided to ignore it, then we 
1174         // need to report that the client redirect was cancelled.
1175         if ([client _quickRedirectComing])
1176             [client _clientRedirectCancelledOrFinished:NO];
1177
1178         [self _setPolicyDocumentLoadState:nil];
1179         // If the navigation request came from the back/forward menu, and we punt on it, we have the 
1180         // problem that we have optimistically moved the b/f cursor already, so move it back.  For sanity, 
1181         // we only do this when punting a navigation for the target frame or top-level frame.  
1182         if ((isTargetItem || [[client webView] mainFrame] == client)
1183             && (policyLoadType == WebFrameLoadTypeForward
1184                 || policyLoadType == WebFrameLoadTypeBack
1185                 || policyLoadType == WebFrameLoadTypeIndexedBackForward))
1186             [(WebFrame <WebFrameLoaderClient> *)[[client webView] mainFrame] _resetBackForwardList];
1187         return;
1188     }
1189     
1190     WebFrameLoadType type = policyLoadType;
1191     WebDataSource *dataSource = [[self policyDataSource] retain];
1192     
1193     [self stopLoading];
1194     loadType = type;
1195
1196     [self startProvisionalLoad:dataSource];
1197
1198     [dataSource release];
1199     [self _setPolicyDocumentLoadState:nil];
1200     
1201     if (client == [[client webView] mainFrame])
1202         LOG(DocumentLoad, "loading %@", [[[self provisionalDataSource] request] URL]);
1203
1204     if (type == WebFrameLoadTypeForward || type == WebFrameLoadTypeBack || type == WebFrameLoadTypeIndexedBackForward) {
1205         if ([client _loadProvisionalItemFromPageCache])
1206             return;
1207     }
1208
1209     if (formState) {
1210         // It's a bit of a hack to reuse the WebPolicyDecisionListener for the continuation
1211         // mechanism across the willSubmitForm callout.
1212         listener = [[WebPolicyDecisionListener alloc] _initWithTarget:self action:@selector(continueAfterWillSubmitForm:)];
1213         [[[client webView] _formDelegate] frame:client sourceFrame:[formState sourceFrame] willSubmitForm:[formState form] withValues:[formState values] submissionListener:listener];
1214     } 
1215     else {
1216         [self continueAfterWillSubmitForm:WebPolicyUse];
1217     }
1218 }
1219
1220 - (void)loadDataSource:(WebDataSource *)newDataSource withLoadType:(WebFrameLoadType)type formState:(WebFormState *)formState
1221 {
1222     ASSERT([client webView] != nil);
1223
1224     // Unfortunately the view must be non-nil, this is ultimately due
1225     // to parser requiring a FrameView.  We should fix this dependency.
1226
1227     ASSERT([client frameView] != nil);
1228
1229     policyLoadType = type;
1230
1231     WebFrame *parentFrame = [client parentFrame];
1232     if (parentFrame)
1233         [[newDataSource _documentLoadState] setOverrideEncoding:[[[parentFrame dataSource] _documentLoadState] overrideEncoding]];
1234
1235     WebDocumentLoadStateMac *loadState = (WebDocumentLoadStateMac *)[newDataSource _documentLoadState];
1236     [loadState setFrameLoader:self];
1237     [loadState setDataSource:newDataSource];
1238
1239     [self invalidatePendingPolicyDecisionCallingDefaultAction:YES];
1240
1241     [self _setPolicyDocumentLoadState:[newDataSource _documentLoadState]];
1242
1243     [self checkNavigationPolicyForRequest:[newDataSource request]
1244                                dataSource:newDataSource
1245                                 formState:formState
1246                                   andCall:self
1247                              withSelector:@selector(continueLoadRequestAfterNavigationPolicy:formState:)];
1248 }
1249
1250 - (void)handleUnimplementablePolicyWithErrorCode:(int)code forURL:(NSURL *)URL
1251 {
1252     NSError *error = [NSError _webKitErrorWithDomain:WebKitErrorDomain code:code URL:URL];
1253     WebView *wv = [client webView];
1254     delegateIsHandlingUnimplementablePolicy = YES;
1255     [[wv _policyDelegateForwarder] webView:wv unableToImplementPolicyWithError:error frame:client];    
1256     delegateIsHandlingUnimplementablePolicy = NO;
1257 }
1258
1259 - (BOOL)delegateIsHandlingProvisionalLoadError
1260 {
1261     return delegateIsHandlingProvisionalLoadError;
1262 }
1263
1264 - (void)setDelegateIsHandlingProvisionalLoadError:(BOOL)is
1265 {
1266     delegateIsHandlingProvisionalLoadError = is;
1267 }
1268
1269 @end