2 * Copyright (C) 2005 Apple Computer, Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
29 #import "WebDataSource.h"
31 #import "WebArchive.h"
32 #import "WebArchiver.h"
33 #import "WebDOMOperationsPrivate.h"
34 #import "WebDataProtocol.h"
35 #import "WebDataSourceInternal.h"
36 #import "WebDefaultResourceLoadDelegate.h"
37 #import "WebDocument.h"
38 #import "WebDownloadInternal.h"
39 #import "WebFrameBridge.h"
40 #import "WebFrameInternal.h"
41 #import "WebFrameLoader.h"
42 #import "WebFrameLoadDelegate.h"
43 #import "WebFrameView.h"
44 #import "WebHTMLRepresentation.h"
45 #import "WebHTMLViewPrivate.h"
46 #import "WebHistory.h"
47 #import "WebHistoryItemPrivate.h"
48 #import "WebIconDatabasePrivate.h"
49 #import "WebKitErrorsPrivate.h"
50 #import "WebKitLogging.h"
51 #import "WebKitNSStringExtras.h"
52 #import "WebKitStatisticsPrivate.h"
53 #import "WebNSObjectExtras.h"
54 #import "WebNSURLExtras.h"
55 #import "WebNSURLRequestExtras.h"
56 #import "WebPDFRepresentation.h"
57 #import "WebPreferences.h"
58 #import "WebResourceLoadDelegate.h"
59 #import "WebResourcePrivate.h"
60 #import "WebScriptDebugServerPrivate.h"
61 #import "WebUnarchivingState.h"
62 #import "WebViewInternal.h"
63 #import <Foundation/NSURLConnection.h>
64 #import <Foundation/NSURLRequest.h>
65 #import <JavaScriptCore/Assertions.h>
66 #import <WebKit/DOMHTML.h>
67 #import <WebKit/DOMPrivate.h>
68 #import <WebKitSystemInterface.h>
69 #import "WebDocumentLoadStateMac.h"
71 @interface WebDataSourcePrivate : NSObject
75 WebDocumentLoadStateMac *loadState;
77 id <WebDocumentRepresentation> representation;
79 BOOL loadingFromPageCache;
80 WebUnarchivingState *unarchivingState;
81 NSMutableDictionary *subresources;
82 BOOL representationFinishedLoading;
87 @implementation WebDataSourcePrivate
91 ASSERT(![loadState isLoading]);
95 [representation release];
96 [unarchivingState release];
103 @interface WebDataSource (WebFileInternal)
106 @implementation WebDataSource (WebFileInternal)
108 - (void)_setRepresentation: (id<WebDocumentRepresentation>)representation
110 [_private->representation release];
111 _private->representation = [representation retain];
112 _private->representationFinishedLoading = NO;
115 static inline void addTypesFromClass(NSMutableDictionary *allTypes, Class class, NSArray *supportTypes)
117 NSEnumerator *enumerator = [supportTypes objectEnumerator];
118 ASSERT(enumerator != nil);
119 NSString *mime = nil;
120 while ((mime = [enumerator nextObject]) != nil) {
121 // Don't clobber previously-registered classes.
122 if ([allTypes objectForKey:mime] == nil)
123 [allTypes setObject:class forKey:mime];
127 + (Class)_representationClassForMIMEType:(NSString *)MIMEType
130 return [WebView _viewClass:nil andRepresentationClass:&repClass forMIMEType:MIMEType] ? repClass : nil;
135 @implementation WebDataSource (WebPrivate)
137 - (NSError *)_mainDocumentError
139 return [_private->loadState mainDocumentError];
142 - (void)_addSubframeArchives:(NSArray *)subframeArchives
144 NSEnumerator *enumerator = [subframeArchives objectEnumerator];
146 while ((archive = [enumerator nextObject]) != nil)
147 [self _addToUnarchiveState:archive];
150 - (NSFileWrapper *)_fileWrapperForURL:(NSURL *)URL
152 if ([URL isFileURL]) {
153 NSString *path = [[URL path] stringByResolvingSymlinksInPath];
154 return [[[NSFileWrapper alloc] initWithPath:path] autorelease];
157 WebResource *resource = [self subresourceForURL:URL];
159 return [resource _fileWrapperRepresentation];
161 NSCachedURLResponse *cachedResponse = [[self _webView] _cachedResponseForURL:URL];
162 if (cachedResponse) {
163 NSFileWrapper *wrapper = [[[NSFileWrapper alloc] initRegularFileWithContents:[cachedResponse data]] autorelease];
164 [wrapper setPreferredFilename:[[cachedResponse response] suggestedFilename]];
173 @implementation WebDataSource (WebInternal)
175 - (void)_finishedLoading
177 _private->representationFinishedLoading = YES;
178 [[self representation] finishedLoadingWithDataSource:self];
181 - (void)_receivedData:(NSData *)data
183 [[self representation] receivedData:data withDataSource:self];
184 [[[[self webFrame] frameView] documentView] dataSourceUpdated:self];
187 - (void)_setMainDocumentError:(NSError *)error
189 if (!_private->representationFinishedLoading) {
190 _private->representationFinishedLoading = YES;
191 [[self representation] receivedError:error withDataSource:self];
195 - (void)_clearUnarchivingState
197 [_private->unarchivingState release];
198 _private->unarchivingState = nil;
201 - (void)_revertToProvisionalState
203 [self _setRepresentation:nil];
206 + (NSMutableDictionary *)_repTypesAllowImageTypeOmission:(BOOL)allowImageTypeOmission
208 static NSMutableDictionary *repTypes = nil;
209 static BOOL addedImageTypes = NO;
212 repTypes = [[NSMutableDictionary alloc] init];
213 addTypesFromClass(repTypes, [WebHTMLRepresentation class], [WebHTMLRepresentation supportedNonImageMIMETypes]);
215 // Since this is a "secret default" we don't both registering it.
216 BOOL omitPDFSupport = [[NSUserDefaults standardUserDefaults] boolForKey:@"WebKitOmitPDFSupport"];
218 addTypesFromClass(repTypes, [WebPDFRepresentation class], [WebPDFRepresentation supportedMIMETypes]);
221 if (!addedImageTypes && !allowImageTypeOmission) {
222 addTypesFromClass(repTypes, [WebHTMLRepresentation class], [WebHTMLRepresentation supportedImageMIMETypes]);
223 addedImageTypes = YES;
229 - (void)_decidePolicyForMIMEType:(NSString *)MIMEType decisionListener:(WebPolicyDecisionListener *)listener
231 WebView *wv = [self _webView];
232 [[wv _policyDelegateForwarder] webView:wv decidePolicyForMIMEType:MIMEType
233 request:[self request]
234 frame:[self webFrame]
235 decisionListener:listener];
238 - (void)_receivedMainResourceError:(NSError *)error complete:(BOOL)isComplete
241 WebFrameBridge *bridge = [[self webFrame] _bridge];
243 // Retain the bridge because the stop may release the last reference to it.
247 // FIXME: Don't want to do this if an entirely new load is going, so should check
248 // that both data sources on the frame are either self or nil.
249 // Can't call [self _bridge] because we might not have commited yet
251 // FIXME: WebKitErrorPlugInWillHandleLoad is a workaround for the cancel we do to prevent loading plugin content twice. See <rdar://problem/4258008>
252 if ([error code] != NSURLErrorCancelled && [error code] != WebKitErrorPlugInWillHandleLoad)
253 [bridge handleFallbackContent];
258 [[self webFrame] _receivedMainResourceError:error];
259 [_private->loadState mainReceivedError:error complete:isComplete];
262 - (void)_downloadWithLoadingConnection:(NSURLConnection *)connection request:(NSURLRequest *)request response:(NSURLResponse *)r proxy:(WKNSURLConnectionDelegateProxyPtr) proxy
264 [WebDownload _downloadWithLoadingConnection:connection
267 delegate:[[self _webView] downloadDelegate]
271 - (void)_didFailLoadingWithError:(NSError *)error forResource:(id)identifier
273 WebView *webView = [self _webView];
275 [webView _completeProgressForIdentifier:identifier];
278 [[webView _resourceLoadDelegateForwarder] webView:webView resource:identifier didFailLoadingWithError:error fromDataSource:self];
281 - (void)_didFinishLoadingForResource:(id)identifier
283 WebView *webView = [self _webView];
285 [webView _completeProgressForIdentifier:identifier];
287 if ([webView _resourceLoadDelegateImplementations].delegateImplementsDidFinishLoadingFromDataSource)
288 [[webView resourceLoadDelegate] webView:webView resource:identifier didFinishLoadingFromDataSource:self];
290 [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier didFinishLoadingFromDataSource:self];
293 - (void)_didReceiveData:(NSData *)data contentLength:(int)lengthReceived forResource:(id)identifier
295 WebView *webView = [self _webView];
297 [webView _incrementProgressForIdentifier:identifier data:data];
299 if ([webView _resourceLoadDelegateImplementations].delegateImplementsDidReceiveContentLength)
300 [[webView resourceLoadDelegate] webView:webView resource:identifier didReceiveContentLength:(WebNSUInteger)lengthReceived fromDataSource:self];
302 [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier didReceiveContentLength:(WebNSUInteger)lengthReceived fromDataSource:self];
305 - (void)_didReceiveResponse:(NSURLResponse *)r forResource:(id)identifier
307 WebView *webView = [self _webView];
309 [_private->loadState addResponse:r];
311 [webView _incrementProgressForIdentifier:identifier response:r];
313 if ([webView _resourceLoadDelegateImplementations].delegateImplementsDidReceiveResponse)
314 [[webView resourceLoadDelegate] webView:webView resource:identifier didReceiveResponse:r fromDataSource:self];
316 [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier didReceiveResponse:r fromDataSource:self];
319 - (void)_didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)currentWebChallenge forResource:(id)identifier
321 WebView *webView = [self _webView];
323 if ([webView _resourceLoadDelegateImplementations].delegateImplementsDidCancelAuthenticationChallenge)
324 [[webView resourceLoadDelegate] webView:webView resource:identifier didCancelAuthenticationChallenge:currentWebChallenge fromDataSource:self];
326 [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier didCancelAuthenticationChallenge:currentWebChallenge fromDataSource:self];
329 - (void)_didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)currentWebChallenge forResource:(id)identifier
331 WebView *webView = [self _webView];
333 if ([webView _resourceLoadDelegateImplementations].delegateImplementsDidReceiveAuthenticationChallenge)
334 [[webView resourceLoadDelegate] webView:webView resource:identifier didReceiveAuthenticationChallenge:currentWebChallenge fromDataSource:self];
336 [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier didReceiveAuthenticationChallenge:currentWebChallenge fromDataSource:self];
339 - (NSURLRequest *)_willSendRequest:(NSMutableURLRequest *)clientRequest forResource:(id)identifier redirectResponse:(NSURLResponse *)redirectResponse
341 WebView *webView = [self _webView];
343 [clientRequest _web_setHTTPUserAgent:[webView userAgentForURL:[clientRequest URL]]];
345 if ([webView _resourceLoadDelegateImplementations].delegateImplementsWillSendRequest)
346 return [[webView resourceLoadDelegate] webView:webView resource:identifier willSendRequest:clientRequest redirectResponse:redirectResponse fromDataSource:self];
348 return [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier willSendRequest:clientRequest redirectResponse:redirectResponse fromDataSource:self];
351 - (id)_identifierForInitialRequest:(NSURLRequest *)clientRequest
353 WebView *webView = [self _webView];
355 // The identifier is released after the last callback, rather than in dealloc
356 // to avoid potential cycles.
357 if ([webView _resourceLoadDelegateImplementations].delegateImplementsIdentifierForRequest)
358 return [[[webView resourceLoadDelegate] webView:webView identifierForInitialRequest:clientRequest fromDataSource:self] retain];
360 return [[[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView identifierForInitialRequest:clientRequest fromDataSource:self] retain];
363 - (WebResource *)_archivedSubresourceForURL:(NSURL *)URL
365 return [_private->unarchivingState archivedResourceForURL:URL];
368 - (void)_startLoading
370 [_private->loadState prepareForLoadStart];
372 if ([[_private->loadState frameLoader] isLoadingMainResource])
375 _private->loadingFromPageCache = NO;
378 id resourceLoadDelegate = [[self _webView] resourceLoadDelegate];
379 if ([resourceLoadDelegate respondsToSelector:@selector(webView:identifierForInitialRequest:fromDataSource:)])
380 identifier = [resourceLoadDelegate webView:[self _webView] identifierForInitialRequest:[_private->loadState originalRequest] fromDataSource:self];
382 identifier = [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:[self _webView] identifierForInitialRequest:[_private->loadState originalRequest] fromDataSource:self];
384 if (![[_private->loadState frameLoader] startLoadingMainResourceWithRequest:[_private->loadState actualRequest] identifier:identifier])
385 [_private->loadState updateLoading];
388 - (void)_replaceSelectionWithArchive:(WebArchive *)archive selectReplacement:(BOOL)selectReplacement
390 DOMDocumentFragment *fragment = [self _documentFragmentWithArchive:archive];
392 [[self _bridge] replaceSelectionWithFragment:fragment selectReplacement:selectReplacement smartReplace:NO matchStyle:NO];
395 - (DOMDocumentFragment *)_documentFragmentWithArchive:(WebArchive *)archive
398 WebResource *mainResource = [archive mainResource];
400 NSString *MIMEType = [mainResource MIMEType];
401 if ([WebView canShowMIMETypeAsHTML:MIMEType]) {
402 NSString *markupString = [[NSString alloc] initWithData:[mainResource data] encoding:NSUTF8StringEncoding];
403 // FIXME: seems poor form to do this as a side effect of getting a document fragment
404 [self _addToUnarchiveState:archive];
405 DOMDocumentFragment *fragment = [[self _bridge] documentFragmentWithMarkupString:markupString baseURLString:[[mainResource URL] _web_originalDataAsString]];
406 [markupString release];
408 } else if ([[WebFrameBridge supportedImageResourceMIMETypes] containsObject:MIMEType]) {
409 return [self _documentFragmentWithImageResource:mainResource];
416 - (DOMDocumentFragment *)_documentFragmentWithImageResource:(WebResource *)resource
418 DOMElement *imageElement = [self _imageElementWithImageResource:resource];
421 DOMDocumentFragment *fragment = [[[self _bridge] DOMDocument] createDocumentFragment];
422 [fragment appendChild:imageElement];
426 - (DOMElement *)_imageElementWithImageResource:(WebResource *)resource
431 [self addSubresource:resource];
433 DOMElement *imageElement = [[[self _bridge] DOMDocument] createElement:@"img"];
435 // FIXME: calling _web_originalDataAsString on a file URL returns an absolute path. Workaround this.
436 NSURL *URL = [resource URL];
437 [imageElement setAttribute:@"src" value:[URL isFileURL] ? [URL absoluteString] : [URL _web_originalDataAsString]];
442 // May return nil if not initialized with a URL.
445 return [[self request] URL];
448 - (void)_loadFromPageCache:(NSDictionary *)pageCache
450 [_private->loadState prepareForLoadStart];
451 _private->loadingFromPageCache = YES;
452 [_private->loadState setCommitted:YES];
453 [[self webFrame] _commitProvisionalLoad:pageCache];
456 - (WebArchive *)_popSubframeArchiveWithName:(NSString *)frameName
458 return [_private->unarchivingState popSubframeArchiveWithFrameName:frameName];
461 - (WebFrameBridge *)_bridge
463 ASSERT([_private->loadState isCommitted]);
464 return [[self webFrame] _bridge];
467 - (WebView *)_webView
469 return [[[_private->loadState frameLoader] webFrame] webView];
472 - (BOOL)_isDocumentHTML
474 NSString *MIMEType = [[self response] MIMEType];
475 return [WebView canShowMIMETypeAsHTML:MIMEType];
478 - (void)_stopLoadingWithError:(NSError *)error
480 [[_private->loadState frameLoader] stopLoadingWithError:error];
483 - (BOOL)_loadingFromPageCache
485 return _private->loadingFromPageCache;
488 -(void)_makeRepresentation
490 Class repClass = [[self class] _representationClassForMIMEType:[[self response] MIMEType]];
492 // Check if the data source was already bound?
493 if (![[self representation] isKindOfClass:repClass]) {
494 id newRep = repClass != nil ? [[repClass alloc] init] : nil;
495 [self _setRepresentation:(id <WebDocumentRepresentation>)newRep];
499 [_private->representation setDataSource:self];
502 - (NSURL *)_URLForHistory
504 // Return the URL to be used for history and B/F list.
505 // Returns nil for WebDataProtocol URLs that aren't alternates
506 // for unreachable URLs, because these can't be stored in history.
507 NSURL *URL = [[_private->loadState originalRequestCopy] URL];
508 if ([WebDataProtocol _webIsDataProtocolURL:URL])
509 URL = [[_private->loadState originalRequestCopy] _webDataRequestUnreachableURL];
511 return [URL _webkit_canonicalize];
514 - (void)_addToUnarchiveState:(WebArchive *)archive
516 if (!_private->unarchivingState)
517 _private->unarchivingState = [[WebUnarchivingState alloc] init];
518 [_private->unarchivingState addArchive:archive];
521 - (WebDocumentLoadState *)_documentLoadState
523 return _private->loadState;
526 - (id)_initWithDocumentLoadState:(WebDocumentLoadStateMac *)loadState
533 _private = [[WebDataSourcePrivate alloc] init];
535 _private->loadState = [loadState retain];
537 LOG(Loading, "creating datasource for %@", [[_private->loadState request] URL]);
538 WKSupportsMultipartXMixedReplace([_private->loadState request]);
540 ++WebDataSourceCount;
548 @implementation WebDataSource
550 -(id)initWithRequest:(NSURLRequest *)request
552 return [self _initWithDocumentLoadState:[[WebDocumentLoadState alloc] initWithRequest:request]];
557 ASSERT([[_private->loadState frameLoader] activeDataSource] != self || ![[_private->loadState frameLoader] isLoading]);
559 --WebDataSourceCount;
568 --WebDataSourceCount;
575 return [_private->loadState mainResourceData];
578 - (id <WebDocumentRepresentation>)representation
580 return _private->representation;
583 - (WebFrame *)webFrame
585 return [[_private->loadState frameLoader] webFrame];
588 -(NSURLRequest *)initialRequest
590 NSURLRequest *clientRequest = [[_private->loadState originalRequest] _webDataRequestExternalRequest];
592 clientRequest = [_private->loadState originalRequest];
593 return clientRequest;
596 -(NSMutableURLRequest *)request
598 return [_private->loadState request];
601 - (NSURLResponse *)response
603 return [_private->loadState response];
606 - (NSString *)textEncodingName
608 NSString *textEncodingName = [_private->loadState overrideEncoding];
610 if (!textEncodingName)
611 textEncodingName = [[self response] textEncodingName];
613 return textEncodingName;
618 return [_private->loadState isLoadingInAPISense];
621 // Returns nil or the page title.
622 - (NSString *)pageTitle
624 return [[self representation] title];
627 - (NSURL *)unreachableURL
629 return [[_private->loadState originalRequest] _webDataRequestUnreachableURL];
632 - (WebArchive *)webArchive
634 // it makes no sense to grab a WebArchive from an uncommitted document.
635 if (![_private->loadState isCommitted])
638 return [WebArchiver archiveFrame:[self webFrame]];
641 - (WebResource *)mainResource
643 NSURLResponse *response = [self response];
644 return [[[WebResource alloc] initWithData:[self data]
646 MIMEType:[response MIMEType]
647 textEncodingName:[response textEncodingName]
648 frameName:[[self webFrame] name]] autorelease];
651 - (NSArray *)subresources
655 [[self _bridge] getAllResourceDatas:&datas andResponses:&responses];
656 ASSERT([datas count] == [responses count]);
658 NSMutableArray *subresources = [[NSMutableArray alloc] initWithCapacity:[datas count]];
659 for (unsigned i = 0; i < [datas count]; ++i) {
660 NSURLResponse *response = [responses objectAtIndex:i];
661 [subresources addObject:[[[WebResource alloc] _initWithData:[datas objectAtIndex:i] URL:[response URL] response:response] autorelease]];
664 return [subresources autorelease];
667 - (WebResource *)subresourceForURL:(NSURL *)URL
670 NSURLResponse *response;
671 if (![[self _bridge] getData:&data andResponse:&response forURL:URL])
674 return [[[WebResource alloc] _initWithData:data URL:URL response:response] autorelease];
677 - (void)addSubresource:(WebResource *)subresource
680 if (!_private->unarchivingState)
681 _private->unarchivingState = [[WebUnarchivingState alloc] init];
682 [_private->unarchivingState addResource:subresource];