ae282b9d12eea83c5c6e0c08073190c0c4a5ed77
[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 <WebKit/WebFrameLoader.h>
30
31 #import <JavaScriptCore/Assertions.h>
32 #import <WebKit/WebDataSourceInternal.h>
33 #import <WebKit/WebFrameInternal.h>
34 #import <WebKit/WebIconLoader.h>
35 #import <WebKit/WebMainResourceLoader.h>
36 #import <WebKit/WebKitLogging.h>
37 #import <WebKit/WebViewInternal.h>
38 #import <WebKit/WebKitErrorsPrivate.h>
39 #import <WebKit/WebResourcePrivate.h>
40
41 @implementation WebFrameLoader
42
43 - (id)initWithWebFrame:(WebFrame *)wf
44 {
45     self = [super init];
46     if (self) {
47         webFrame = wf;
48         state = WebFrameStateCommittedPage;
49     }
50     return self;    
51 }
52
53 - (void)dealloc
54 {
55     // FIXME: should these even exist?
56     [mainResourceLoader release];
57     [subresourceLoaders release];
58     [plugInStreamLoaders release];
59     [iconLoader release];
60     [dataSource release];
61     [provisionalDataSource release];
62     
63     [super dealloc];
64 }
65
66 - (BOOL)hasIconLoader
67 {
68     return iconLoader != nil;
69 }
70
71 - (void)loadIconWithRequest:(NSURLRequest *)request
72 {
73     ASSERT(!iconLoader);
74     iconLoader = [[WebIconLoader alloc] initWithRequest:request];
75     [iconLoader setFrameLoader:self];
76     [iconLoader loadWithRequest:request];
77 }
78
79 - (void)stopLoadingIcon
80 {
81     [iconLoader stopLoading];
82 }
83
84 - (void)addPlugInStreamLoader:(WebLoader *)loader
85 {
86     if (!plugInStreamLoaders)
87         plugInStreamLoaders = [[NSMutableArray alloc] init];
88     [plugInStreamLoaders addObject:loader];
89 }
90
91 - (void)removePlugInStreamLoader:(WebLoader *)loader
92 {
93     [plugInStreamLoaders removeObject:loader];
94 }    
95
96 - (void)setDefersCallbacks:(BOOL)defers
97 {
98     [mainResourceLoader setDefersCallbacks:defers];
99     
100     NSEnumerator *e = [subresourceLoaders objectEnumerator];
101     WebLoader *loader;
102     while ((loader = [e nextObject]))
103         [loader setDefersCallbacks:defers];
104     
105     e = [plugInStreamLoaders objectEnumerator];
106     while ((loader = [e nextObject]))
107         [loader setDefersCallbacks:defers];
108
109     [self deliverArchivedResourcesAfterDelay];
110 }
111
112 - (void)stopLoadingPlugIns
113 {
114     [plugInStreamLoaders makeObjectsPerformSelector:@selector(cancel)];
115     [plugInStreamLoaders removeAllObjects];   
116 }
117
118 - (BOOL)isLoadingMainResource
119 {
120     return mainResourceLoader != nil;
121 }
122
123 - (BOOL)isLoadingSubresources
124 {
125     return [subresourceLoaders count];
126 }
127
128 - (BOOL)isLoadingPlugIns
129 {
130     return [plugInStreamLoaders count];
131 }
132
133 - (BOOL)isLoading
134 {
135     return [self isLoadingMainResource] || [self isLoadingSubresources] || [self isLoadingPlugIns];
136 }
137
138 - (void)stopLoadingSubresources
139 {
140     NSArray *loaders = [subresourceLoaders copy];
141     [loaders makeObjectsPerformSelector:@selector(cancel)];
142     [loaders release];
143     [subresourceLoaders removeAllObjects];
144 }
145
146 - (void)addSubresourceLoader:(WebLoader *)loader
147 {
148     if (subresourceLoaders == nil)
149         subresourceLoaders = [[NSMutableArray alloc] init];
150     [subresourceLoaders addObject:loader];
151 }
152
153 - (void)removeSubresourceLoader:(WebLoader *)loader
154 {
155     [subresourceLoaders removeObject:loader];
156 }
157
158 - (NSData *)mainResourceData
159 {
160     return [mainResourceLoader resourceData];
161 }
162
163 - (void)releaseMainResourceLoader
164 {
165     [mainResourceLoader release];
166     mainResourceLoader = nil;
167 }
168
169 - (void)cancelMainResourceLoad
170 {
171     [mainResourceLoader cancel];
172 }
173
174 - (BOOL)startLoadingMainResourceWithRequest:(NSMutableURLRequest *)request identifier:(id)identifier
175 {
176     mainResourceLoader = [[WebMainResourceLoader alloc] initWithFrameLoader:self];
177     
178     [mainResourceLoader setIdentifier:identifier];
179     [[provisionalDataSource webFrame] _addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:NO];
180     if (![mainResourceLoader loadWithRequest:request]) {
181         // FIXME: if this should really be caught, we should just ASSERT this doesn't happen;
182         // should it be caught by other parts of WebKit or other parts of the app?
183         LOG_ERROR("could not create WebResourceHandle for URL %@ -- should be caught by policy handler level", [request URL]);
184         [mainResourceLoader release];
185         mainResourceLoader = nil;
186         return NO;
187     }
188     
189     return YES;
190 }
191
192 - (void)stopLoadingWithError:(NSError *)error
193 {
194     [mainResourceLoader cancelWithError:error];
195 }
196
197 - (WebDataSource *)dataSource
198 {
199     return dataSource; 
200 }
201
202 - (void)_setDataSource:(WebDataSource *)ds
203 {
204     if (ds == nil && dataSource == nil)
205         return;
206     
207     ASSERT(ds != dataSource);
208     
209     [webFrame _prepareForDataSourceReplacement];
210     [dataSource _setWebFrame:nil];
211     
212     [ds retain];
213     [dataSource release];
214     dataSource = ds;
215
216     [ds _setWebFrame:webFrame];
217 }
218
219 - (void)clearDataSource
220 {
221     [self _setDataSource:nil];
222 }
223
224 - (WebDataSource *)provisionalDataSource 
225 {
226     return provisionalDataSource; 
227 }
228
229 - (void)_setProvisionalDataSource: (WebDataSource *)d
230 {
231     ASSERT(!d || !provisionalDataSource);
232
233     if (provisionalDataSource != dataSource)
234         [provisionalDataSource _setWebFrame:nil];
235
236     [d retain];
237     [provisionalDataSource release];
238     provisionalDataSource = d;
239
240     [d _setWebFrame:webFrame];
241 }
242
243 - (void)_clearProvisionalDataSource
244 {
245     [self _setProvisionalDataSource:nil];
246 }
247
248 - (WebFrameState)state
249 {
250     return state;
251 }
252
253 #ifndef NDEBUG
254 static const char * const stateNames[] = {
255     "WebFrameStateProvisional",
256     "WebFrameStateCommittedPage",
257     "WebFrameStateComplete"
258 };
259 #endif
260
261 static CFAbsoluteTime _timeOfLastCompletedLoad;
262
263 + (CFAbsoluteTime)timeOfLastCompletedLoad
264 {
265     return _timeOfLastCompletedLoad;
266 }
267
268 - (void)_setState:(WebFrameState)newState
269 {
270     LOG(Loading, "%@:  transition from %s to %s", [webFrame name], stateNames[state], stateNames[newState]);
271     if ([webFrame webView])
272         LOG(Timing, "%@:  transition from %s to %s, %f seconds since start of document load", [webFrame name], stateNames[state], stateNames[newState], CFAbsoluteTimeGetCurrent() - [[[[webFrame webView] mainFrame] dataSource] _loadingStartedTime]);
273     
274     if (newState == WebFrameStateComplete && webFrame == [[webFrame webView] mainFrame])
275         LOG(DocumentLoad, "completed %@ (%f seconds)", [[[self dataSource] request] URL], CFAbsoluteTimeGetCurrent() - [[self dataSource] _loadingStartedTime]);
276     
277     state = newState;
278     
279     if (state == WebFrameStateProvisional)
280         [webFrame _provisionalLoadStarted];
281     else if (state == WebFrameStateComplete) {
282         [webFrame _frameLoadCompleted];
283         _timeOfLastCompletedLoad = CFAbsoluteTimeGetCurrent();
284         [dataSource _stopRecordingResponses];
285     }
286 }
287
288 - (void)clearProvisionalLoad
289 {
290     [self _setProvisionalDataSource:nil];
291     [[webFrame webView] _progressCompleted:webFrame];
292     [self _setState:WebFrameStateComplete];
293 }
294
295 - (void)markLoadComplete
296 {
297     [self _setState:WebFrameStateComplete];
298 }
299
300 - (void)clearIconLoader
301 {
302     [iconLoader release];
303     iconLoader = nil;
304 }
305
306 - (void)commitProvisionalLoad
307 {
308     [self stopLoadingSubresources];
309     [self stopLoadingPlugIns];
310     [self clearIconLoader];
311
312     [self _setDataSource:provisionalDataSource];
313     [self _setProvisionalDataSource:nil];
314     [self _setState:WebFrameStateCommittedPage];
315 }
316
317 - (void)stopLoading
318 {
319     [provisionalDataSource _stopLoading];
320     [dataSource _stopLoading];
321     [self _clearProvisionalDataSource];
322     [self clearArchivedResources];
323 }
324
325 // FIXME: poor method name; also why is this not part of startProvisionalLoad:?
326 - (void)startLoading
327 {
328     [provisionalDataSource _startLoading];
329 }
330
331 - (void)startProvisionalLoad:(WebDataSource *)ds
332 {
333     [self _setProvisionalDataSource:ds];
334     [self _setState:WebFrameStateProvisional];
335 }
336
337 - (void)setupForReplace
338 {
339     [self _setState:WebFrameStateProvisional];
340     WebDataSource *old = provisionalDataSource;
341     provisionalDataSource = dataSource;
342     dataSource = nil;
343     [old release];
344     
345     [webFrame _detachChildren];
346 }
347
348 - (WebDataSource *)activeDataSource
349 {
350     if (state == WebFrameStateProvisional)
351         return provisionalDataSource;
352
353     return dataSource;
354 }
355
356 - (WebResource *)_archivedSubresourceForURL:(NSURL *)URL
357 {
358     return [[self activeDataSource] _archivedSubresourceForURL:URL];
359 }
360
361 - (BOOL)_defersCallbacks
362 {
363     return [[self activeDataSource] _defersCallbacks];
364 }
365
366 - (id)_identifierForInitialRequest:(NSURLRequest *)clientRequest
367 {
368     return [[self activeDataSource] _identifierForInitialRequest:clientRequest];
369 }
370
371 - (NSURLRequest *)_willSendRequest:(NSMutableURLRequest *)clientRequest forResource:(id)identifier redirectResponse:(NSURLResponse *)redirectResponse
372 {
373     return [[self activeDataSource] _willSendRequest:clientRequest forResource:identifier redirectResponse:redirectResponse];
374 }
375
376 - (void)_didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)currentWebChallenge forResource:(id)identifier
377 {
378     return [[self activeDataSource] _didReceiveAuthenticationChallenge:currentWebChallenge forResource:identifier];
379 }
380
381 - (void)_didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)currentWebChallenge forResource:(id)identifier
382 {
383     return [[self activeDataSource] _didCancelAuthenticationChallenge:currentWebChallenge forResource:identifier];
384 }
385
386 - (void)_didReceiveResponse:(NSURLResponse *)r forResource:(id)identifier
387 {
388     return [[self activeDataSource] _didReceiveResponse:r forResource:identifier];
389 }
390
391 - (void)_didReceiveData:(NSData *)data contentLength:(int)lengthReceived forResource:(id)identifier
392 {
393     return [[self activeDataSource] _didReceiveData:data contentLength:lengthReceived forResource:identifier];
394 }
395
396 - (void)_didFinishLoadingForResource:(id)identifier
397 {
398     return [[self activeDataSource] _didFinishLoadingForResource:identifier];
399 }
400
401 - (void)_didFailLoadingWithError:(NSError *)error forResource:(id)identifier
402 {
403     return [[self activeDataSource] _didFailLoadingWithError:error forResource:identifier];
404 }
405
406 - (BOOL)_privateBrowsingEnabled
407 {
408     return [[self activeDataSource] _privateBrowsingEnabled];
409 }
410
411 - (void)_addPlugInStreamLoader:(WebLoader *)loader
412 {
413     return [[self activeDataSource] _addPlugInStreamLoader:loader];
414 }
415
416 - (void)_removePlugInStreamLoader:(WebLoader *)loader
417 {
418     return [[self activeDataSource] _removePlugInStreamLoader:loader];
419 }
420
421 - (void)_finishedLoadingResource
422 {
423     return [[self activeDataSource] _finishedLoadingResource];
424 }
425
426 - (void)_receivedError:(NSError *)error
427 {
428     return [[self activeDataSource] _receivedError:error];
429 }
430
431 - (void)_addSubresourceLoader:(WebLoader *)loader
432 {
433     return [[self activeDataSource] _addSubresourceLoader:loader];
434 }
435
436 - (void)_removeSubresourceLoader:(WebLoader *)loader
437 {
438     return [[self activeDataSource] _removeSubresourceLoader:loader];
439 }
440
441 - (NSURLRequest *)_originalRequest
442 {
443     return [[self activeDataSource] _originalRequest];
444 }
445
446 - (WebFrame *)webFrame
447 {
448     return [[self activeDataSource] webFrame];
449 }
450
451 - (void)_receivedMainResourceError:(NSError *)error complete:(BOOL)isComplete
452 {
453     WebDataSource *ds = [self activeDataSource];
454     [ds retain];
455     [ds _receivedMainResourceError:error complete:isComplete];
456     [ds release];
457 }
458
459 - (NSURLRequest *)initialRequest
460 {
461     return [[self activeDataSource] initialRequest];
462 }
463
464 - (void)_receivedData:(NSData *)data
465 {
466     [[self activeDataSource] _receivedData:data];
467 }
468
469 - (void)_setRequest:(NSURLRequest *)request
470 {
471     [[self activeDataSource] _setRequest:request];
472 }
473
474 - (void)_downloadWithLoadingConnection:(NSURLConnection *)connection request:(NSURLRequest *)request response:(NSURLResponse *)r proxy:(WKNSURLConnectionDelegateProxyPtr)proxy
475 {
476     [[self activeDataSource] _downloadWithLoadingConnection:connection request:request response:r proxy:proxy];
477 }
478
479 - (void)_handleFallbackContent
480 {
481     [[self activeDataSource] _handleFallbackContent];
482 }
483
484 - (BOOL)_isStopping
485 {
486     return [[self activeDataSource] _isStopping];
487 }
488
489 - (void)_decidePolicyForMIMEType:(NSString *)MIMEType decisionListener:(WebPolicyDecisionListener *)listener
490 {
491     [[self activeDataSource] _decidePolicyForMIMEType:MIMEType decisionListener:listener];
492 }
493
494 - (void)_setupForReplaceByMIMEType:(NSString *)newMIMEType
495 {
496     [[self activeDataSource] _setupForReplaceByMIMEType:newMIMEType];
497 }
498
499 - (void)_setResponse:(NSURLResponse *)response
500 {
501     [[self activeDataSource] _setResponse:response];
502 }
503
504 - (void)_mainReceivedError:(NSError *)error complete:(BOOL)isComplete
505 {
506     [[self activeDataSource] _mainReceivedError:error complete:isComplete];
507 }
508
509 - (void)_finishedLoading
510 {
511     [[self activeDataSource] _finishedLoading];
512 }
513
514 - (void)_mainReceivedBytesSoFar:(unsigned)bytesSoFar complete:(BOOL)isComplete
515 {
516     [[self activeDataSource] _mainReceivedBytesSoFar:bytesSoFar complete:isComplete];
517 }
518
519 - (void)_iconLoaderReceivedPageIcon:(WebIconLoader *)iLoader
520 {
521     ASSERT(iLoader == iconLoader);
522     [[self activeDataSource] _iconLoaderReceivedPageIcon:iLoader];
523 }
524
525 - (NSURL *)_URL
526 {
527     return [[self activeDataSource] _URL];
528 }
529
530 - (NSError *)cancelledErrorWithRequest:(NSURLRequest *)request
531 {
532     return [NSError _webKitErrorWithDomain:NSURLErrorDomain
533                                       code:NSURLErrorCancelled
534                                        URL:[request URL]];
535 }
536
537 - (NSError *)fileDoesNotExistErrorWithResponse:(NSURLResponse *)response
538 {
539     return [NSError _webKitErrorWithDomain:NSURLErrorDomain
540                                                 code:NSURLErrorFileDoesNotExist
541                                                  URL:[response URL]];    
542 }
543
544 - (void)clearArchivedResources
545 {
546     [pendingArchivedResources removeAllObjects];
547     [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(deliverArchivedResources) object:nil];
548 }
549
550 - (void)deliverArchivedResources
551 {
552     if (![pendingArchivedResources count] || [self _defersCallbacks])
553         return;
554         
555     NSEnumerator *keyEnum = [pendingArchivedResources keyEnumerator];
556     WebLoader *loader;
557     while ((loader = [keyEnum nextObject])) {
558         WebResource *resource = [pendingArchivedResources objectForKey:loader];
559         [loader didReceiveResponse:[resource _response]];
560         NSData *data = [resource data];
561         [loader didReceiveData:data lengthReceived:[data length] allAtOnce:YES];
562         [loader didFinishLoading];
563     }
564     
565     [pendingArchivedResources removeAllObjects];
566 }
567
568 - (void)deliverArchivedResourcesAfterDelay
569 {
570     if (![pendingArchivedResources count] || [self _defersCallbacks])
571         return;
572     
573     [self performSelector:@selector(deliverArchivedResources) withObject:nil afterDelay:0];
574 }
575
576 static BOOL isCaseInsensitiveEqual(NSString *a, NSString *b)
577 {
578     return [a caseInsensitiveCompare:b] == NSOrderedSame;
579 }
580
581 // The following 2 methods are copied from [NSHTTPURLProtocol _cachedResponsePassesValidityChecks] and modified for our needs.
582 // FIXME: It would be nice to eventually to share this code somehow.
583 - (BOOL)_canUseResourceForRequest:(NSURLRequest *)theRequest
584 {
585     NSURLRequestCachePolicy policy = [theRequest cachePolicy];
586     
587     if (policy == NSURLRequestReturnCacheDataElseLoad) {
588         return YES;
589     } else if (policy == NSURLRequestReturnCacheDataDontLoad) {
590         return YES;
591     } else if (policy == NSURLRequestReloadIgnoringCacheData) {
592         return NO;
593     } else if ([theRequest valueForHTTPHeaderField:@"must-revalidate"] != nil) {
594         return NO;
595     } else if ([theRequest valueForHTTPHeaderField:@"proxy-revalidate"] != nil) {
596         return NO;
597     } else if ([theRequest valueForHTTPHeaderField:@"If-Modified-Since"] != nil) {
598         return NO;
599     } else if ([theRequest valueForHTTPHeaderField:@"Cache-Control"] != nil) {
600         return NO;
601     } else if (isCaseInsensitiveEqual(@"POST", [theRequest HTTPMethod])) {
602         return NO;
603     } else {
604         return YES;
605     }
606 }
607
608 - (BOOL)_canUseResourceWithResponse:(NSURLResponse *)theResponse
609 {
610     if (WKGetNSURLResponseMustRevalidate(theResponse)) {
611         return NO;
612     } else if (WKGetNSURLResponseCalculatedExpiration(theResponse) - CFAbsoluteTimeGetCurrent() < 1) {
613         return NO;
614     } else {
615         return YES;
616     }
617 }
618
619 - (NSMutableDictionary *)pendingArchivedResources
620 {
621     if (!pendingArchivedResources)
622         pendingArchivedResources = [[NSMutableDictionary alloc] init];
623     
624     return pendingArchivedResources;
625 }
626
627 - (BOOL)willUseArchiveForRequest:(NSURLRequest *)r originalURL:(NSURL *)originalURL loader:(WebLoader *)loader
628 {
629     if ([[r URL] isEqual:originalURL] && [self _canUseResourceForRequest:r]) {
630         WebResource *resource = [self _archivedSubresourceForURL:originalURL];
631         if (resource && [self _canUseResourceWithResponse:[resource _response]]) {
632             [[self pendingArchivedResources] setObject:resource forKey:loader];
633             // Deliver the resource after a delay because callers don't expect to receive callbacks while calling this method.
634             [self deliverArchivedResourcesAfterDelay];
635             return YES;
636         }
637     }
638     return NO;
639 }
640
641 - (BOOL)archiveLoadPendingForLoader:(WebLoader *)loader
642 {
643     return [pendingArchivedResources objectForKey:loader] != nil;
644 }
645
646 - (void)cancelPendingArchiveLoadForLoader:(WebLoader *)loader
647 {
648     [pendingArchivedResources removeObjectForKey:loader];
649     
650     if (![pendingArchivedResources count])
651         [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(deliverArchivedResources) object:nil];
652 }
653
654 - (void)_addExtraFieldsToRequest:(NSMutableURLRequest *)request mainResource:(BOOL)mainResource alwaysFromRequest:(BOOL)f
655 {
656     [webFrame _addExtraFieldsToRequest:request mainResource:mainResource alwaysFromRequest:f];
657 }
658
659 @end