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 "WebDataProtocol.h"
34 #import "WebDataSourceInternal.h"
35 #import "WebDefaultResourceLoadDelegate.h"
36 #import "WebDocument.h"
37 #import "WebFrameBridge.h"
38 #import "WebFrameInternal.h"
39 #import "WebFrameLoader.h"
40 #import "WebFrameLoadDelegate.h"
41 #import "WebHTMLRepresentation.h"
42 #import "WebKitErrorsPrivate.h"
43 #import "WebKitLogging.h"
44 #import "WebKitStatisticsPrivate.h"
45 #import "WebNSURLExtras.h"
46 #import "WebNSURLRequestExtras.h"
47 #import "WebPDFRepresentation.h"
48 #import "WebResourceLoadDelegate.h"
49 #import "WebResourcePrivate.h"
50 #import "WebUnarchivingState.h"
51 #import "WebViewInternal.h"
52 #import <JavaScriptCore/Assertions.h>
53 #import <WebKit/DOMHTML.h>
54 #import <WebKit/DOMPrivate.h>
55 #import <WebKitSystemInterface.h>
56 #import "WebDocumentLoadStateMac.h"
58 @interface WebDataSourcePrivate : NSObject
62 WebDocumentLoadStateMac *loadState;
64 id <WebDocumentRepresentation> representation;
66 BOOL loadingFromPageCache;
67 WebUnarchivingState *unarchivingState;
68 NSMutableDictionary *subresources;
69 BOOL representationFinishedLoading;
74 @implementation WebDataSourcePrivate
78 ASSERT(![loadState isLoading]);
82 [representation release];
83 [unarchivingState release];
90 @interface WebDataSource (WebFileInternal)
93 @implementation WebDataSource (WebFileInternal)
95 - (void)_setRepresentation: (id<WebDocumentRepresentation>)representation
97 [_private->representation release];
98 _private->representation = [representation retain];
99 _private->representationFinishedLoading = NO;
102 static inline void addTypesFromClass(NSMutableDictionary *allTypes, Class class, NSArray *supportTypes)
104 NSEnumerator *enumerator = [supportTypes objectEnumerator];
105 ASSERT(enumerator != nil);
106 NSString *mime = nil;
107 while ((mime = [enumerator nextObject]) != nil) {
108 // Don't clobber previously-registered classes.
109 if ([allTypes objectForKey:mime] == nil)
110 [allTypes setObject:class forKey:mime];
114 + (Class)_representationClassForMIMEType:(NSString *)MIMEType
117 return [WebView _viewClass:nil andRepresentationClass:&repClass forMIMEType:MIMEType] ? repClass : nil;
122 @implementation WebDataSource (WebPrivate)
124 - (NSError *)_mainDocumentError
126 return [_private->loadState mainDocumentError];
129 - (void)_addSubframeArchives:(NSArray *)subframeArchives
131 NSEnumerator *enumerator = [subframeArchives objectEnumerator];
133 while ((archive = [enumerator nextObject]) != nil)
134 [self _addToUnarchiveState:archive];
137 - (NSFileWrapper *)_fileWrapperForURL:(NSURL *)URL
139 if ([URL isFileURL]) {
140 NSString *path = [[URL path] stringByResolvingSymlinksInPath];
141 return [[[NSFileWrapper alloc] initWithPath:path] autorelease];
144 WebResource *resource = [self subresourceForURL:URL];
146 return [resource _fileWrapperRepresentation];
148 NSCachedURLResponse *cachedResponse = [[self _webView] _cachedResponseForURL:URL];
149 if (cachedResponse) {
150 NSFileWrapper *wrapper = [[[NSFileWrapper alloc] initRegularFileWithContents:[cachedResponse data]] autorelease];
151 [wrapper setPreferredFilename:[[cachedResponse response] suggestedFilename]];
160 @implementation WebDataSource (WebInternal)
162 - (void)_finishedLoading
164 _private->representationFinishedLoading = YES;
165 [[self representation] finishedLoadingWithDataSource:self];
168 - (void)_receivedData:(NSData *)data
170 [[self representation] receivedData:data withDataSource:self];
171 [[[[self webFrame] frameView] documentView] dataSourceUpdated:self];
174 - (void)_setMainDocumentError:(NSError *)error
176 if (!_private->representationFinishedLoading) {
177 _private->representationFinishedLoading = YES;
178 [[self representation] receivedError:error withDataSource:self];
182 - (void)_setLoadingFromPageCache:(BOOL)loadingFromPageCache
184 _private->loadingFromPageCache = loadingFromPageCache;
187 - (void)_clearUnarchivingState
189 [_private->unarchivingState release];
190 _private->unarchivingState = nil;
193 - (void)_revertToProvisionalState
195 [self _setRepresentation:nil];
198 + (NSMutableDictionary *)_repTypesAllowImageTypeOmission:(BOOL)allowImageTypeOmission
200 static NSMutableDictionary *repTypes = nil;
201 static BOOL addedImageTypes = NO;
204 repTypes = [[NSMutableDictionary alloc] init];
205 addTypesFromClass(repTypes, [WebHTMLRepresentation class], [WebHTMLRepresentation supportedNonImageMIMETypes]);
207 // Since this is a "secret default" we don't both registering it.
208 BOOL omitPDFSupport = [[NSUserDefaults standardUserDefaults] boolForKey:@"WebKitOmitPDFSupport"];
210 addTypesFromClass(repTypes, [WebPDFRepresentation class], [WebPDFRepresentation supportedMIMETypes]);
213 if (!addedImageTypes && !allowImageTypeOmission) {
214 addTypesFromClass(repTypes, [WebHTMLRepresentation class], [WebHTMLRepresentation supportedImageMIMETypes]);
215 addedImageTypes = YES;
221 - (WebResource *)_archivedSubresourceForURL:(NSURL *)URL
223 return [_private->unarchivingState archivedResourceForURL:URL];
226 - (void)_replaceSelectionWithArchive:(WebArchive *)archive selectReplacement:(BOOL)selectReplacement
228 DOMDocumentFragment *fragment = [self _documentFragmentWithArchive:archive];
230 [[self _bridge] replaceSelectionWithFragment:fragment selectReplacement:selectReplacement smartReplace:NO matchStyle:NO];
233 - (DOMDocumentFragment *)_documentFragmentWithArchive:(WebArchive *)archive
236 WebResource *mainResource = [archive mainResource];
238 NSString *MIMEType = [mainResource MIMEType];
239 if ([WebView canShowMIMETypeAsHTML:MIMEType]) {
240 NSString *markupString = [[NSString alloc] initWithData:[mainResource data] encoding:NSUTF8StringEncoding];
241 // FIXME: seems poor form to do this as a side effect of getting a document fragment
242 [self _addToUnarchiveState:archive];
243 DOMDocumentFragment *fragment = [[self _bridge] documentFragmentWithMarkupString:markupString baseURLString:[[mainResource URL] _web_originalDataAsString]];
244 [markupString release];
246 } else if ([[WebFrameBridge supportedImageResourceMIMETypes] containsObject:MIMEType]) {
247 return [self _documentFragmentWithImageResource:mainResource];
254 - (DOMDocumentFragment *)_documentFragmentWithImageResource:(WebResource *)resource
256 DOMElement *imageElement = [self _imageElementWithImageResource:resource];
259 DOMDocumentFragment *fragment = [[[self _bridge] DOMDocument] createDocumentFragment];
260 [fragment appendChild:imageElement];
264 - (DOMElement *)_imageElementWithImageResource:(WebResource *)resource
269 [self addSubresource:resource];
271 DOMElement *imageElement = [[[self _bridge] DOMDocument] createElement:@"img"];
273 // FIXME: calling _web_originalDataAsString on a file URL returns an absolute path. Workaround this.
274 NSURL *URL = [resource URL];
275 [imageElement setAttribute:@"src" value:[URL isFileURL] ? [URL absoluteString] : [URL _web_originalDataAsString]];
280 // May return nil if not initialized with a URL.
283 return [[self request] URL];
286 - (void)_loadFromPageCache:(NSDictionary *)pageCache
288 [_private->loadState prepareForLoadStart];
289 _private->loadingFromPageCache = YES;
290 [_private->loadState setCommitted:YES];
291 [[self webFrame] _commitProvisionalLoad:pageCache];
294 - (WebArchive *)_popSubframeArchiveWithName:(NSString *)frameName
296 return [_private->unarchivingState popSubframeArchiveWithFrameName:frameName];
299 - (WebFrameBridge *)_bridge
301 ASSERT([_private->loadState isCommitted]);
302 return [[self webFrame] _bridge];
305 - (WebView *)_webView
307 return [[[_private->loadState frameLoader] webFrame] webView];
310 - (BOOL)_isDocumentHTML
312 NSString *MIMEType = [[self response] MIMEType];
313 return [WebView canShowMIMETypeAsHTML:MIMEType];
316 - (BOOL)_loadingFromPageCache
318 return _private->loadingFromPageCache;
321 -(void)_makeRepresentation
323 Class repClass = [[self class] _representationClassForMIMEType:[[self response] MIMEType]];
325 // Check if the data source was already bound?
326 if (![[self representation] isKindOfClass:repClass]) {
327 id newRep = repClass != nil ? [[repClass alloc] init] : nil;
328 [self _setRepresentation:(id <WebDocumentRepresentation>)newRep];
332 [_private->representation setDataSource:self];
335 - (NSURL *)_URLForHistory
337 // Return the URL to be used for history and B/F list.
338 // Returns nil for WebDataProtocol URLs that aren't alternates
339 // for unreachable URLs, because these can't be stored in history.
340 NSURL *URL = [[_private->loadState originalRequestCopy] URL];
341 if ([WebDataProtocol _webIsDataProtocolURL:URL])
342 URL = [[_private->loadState originalRequestCopy] _webDataRequestUnreachableURL];
344 return [URL _webkit_canonicalize];
347 - (void)_addToUnarchiveState:(WebArchive *)archive
349 if (!_private->unarchivingState)
350 _private->unarchivingState = [[WebUnarchivingState alloc] init];
351 [_private->unarchivingState addArchive:archive];
354 - (WebDocumentLoadState *)_documentLoadState
356 return _private->loadState;
359 - (id)_initWithDocumentLoadState:(WebDocumentLoadStateMac *)loadState
366 _private = [[WebDataSourcePrivate alloc] init];
368 _private->loadState = [loadState retain];
370 LOG(Loading, "creating datasource for %@", [[_private->loadState request] URL]);
371 WKSupportsMultipartXMixedReplace([_private->loadState request]);
373 ++WebDataSourceCount;
381 @implementation WebDataSource
383 -(id)initWithRequest:(NSURLRequest *)request
385 return [self _initWithDocumentLoadState:[[WebDocumentLoadState alloc] initWithRequest:request]];
390 ASSERT([[_private->loadState frameLoader] activeDataSource] != self || ![[_private->loadState frameLoader] isLoading]);
392 --WebDataSourceCount;
401 --WebDataSourceCount;
408 return [_private->loadState mainResourceData];
411 - (id <WebDocumentRepresentation>)representation
413 return _private->representation;
416 - (WebFrame *)webFrame
418 return [[_private->loadState frameLoader] webFrame];
421 -(NSURLRequest *)initialRequest
423 NSURLRequest *clientRequest = [[_private->loadState originalRequest] _webDataRequestExternalRequest];
425 clientRequest = [_private->loadState originalRequest];
426 return clientRequest;
429 -(NSMutableURLRequest *)request
431 return [_private->loadState request];
434 - (NSURLResponse *)response
436 return [_private->loadState response];
439 - (NSString *)textEncodingName
441 NSString *textEncodingName = [_private->loadState overrideEncoding];
443 if (!textEncodingName)
444 textEncodingName = [[self response] textEncodingName];
446 return textEncodingName;
451 return [_private->loadState isLoadingInAPISense];
454 // Returns nil or the page title.
455 - (NSString *)pageTitle
457 return [[self representation] title];
460 - (NSURL *)unreachableURL
462 return [[_private->loadState originalRequest] _webDataRequestUnreachableURL];
465 - (WebArchive *)webArchive
467 // it makes no sense to grab a WebArchive from an uncommitted document.
468 if (![_private->loadState isCommitted])
471 return [WebArchiver archiveFrame:[self webFrame]];
474 - (WebResource *)mainResource
476 NSURLResponse *response = [self response];
477 return [[[WebResource alloc] initWithData:[self data]
479 MIMEType:[response MIMEType]
480 textEncodingName:[response textEncodingName]
481 frameName:[[self webFrame] name]] autorelease];
484 - (NSArray *)subresources
488 [[self _bridge] getAllResourceDatas:&datas andResponses:&responses];
489 ASSERT([datas count] == [responses count]);
491 NSMutableArray *subresources = [[NSMutableArray alloc] initWithCapacity:[datas count]];
492 for (unsigned i = 0; i < [datas count]; ++i) {
493 NSURLResponse *response = [responses objectAtIndex:i];
494 [subresources addObject:[[[WebResource alloc] _initWithData:[datas objectAtIndex:i] URL:[response URL] response:response] autorelease]];
497 return [subresources autorelease];
500 - (WebResource *)subresourceForURL:(NSURL *)URL
503 NSURLResponse *response;
504 if (![[self _bridge] getData:&data andResponse:&response forURL:URL])
507 return [[[WebResource alloc] _initWithData:data URL:URL response:response] autorelease];
510 - (void)addSubresource:(WebResource *)subresource
513 if (!_private->unarchivingState)
514 _private->unarchivingState = [[WebUnarchivingState alloc] init];
515 [_private->unarchivingState addResource:subresource];