Unreviewed, rolling out r215608.
[WebKit-https.git] / Source / WebKit / mac / WebView / WebResource.mm
1 /*
2  * Copyright (C) 2005-2017 Apple 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 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 "WebResourceInternal.h"
30
31 #import "WebFrameInternal.h"
32 #import "WebKitLogging.h"
33 #import "WebKitVersionChecks.h"
34 #import "WebNSDictionaryExtras.h"
35 #import "WebNSObjectExtras.h"
36 #import "WebNSURLExtras.h"
37 #import <JavaScriptCore/InitializeThreading.h>
38 #import <wtf/PassRefPtr.h>
39 #import <WebCore/ArchiveResource.h>
40 #import <WebCore/LegacyWebArchive.h>
41 #import <WebCore/RuntimeApplicationChecks.h>
42 #import <WebCore/TextEncoding.h>
43 #import <WebCore/ThreadCheck.h>
44 #import <WebCore/WebCoreObjCExtras.h>
45 #import <WebCore/WebCoreURLResponse.h>
46 #import <wtf/MainThread.h>
47 #import <wtf/RunLoop.h>
48
49 using namespace WebCore;
50
51 static NSString * const WebResourceDataKey =              @"WebResourceData";
52 static NSString * const WebResourceFrameNameKey =         @"WebResourceFrameName";
53 static NSString * const WebResourceMIMETypeKey =          @"WebResourceMIMEType";
54 static NSString * const WebResourceURLKey =               @"WebResourceURL";
55 static NSString * const WebResourceTextEncodingNameKey =  @"WebResourceTextEncodingName";
56 static NSString * const WebResourceResponseKey =          @"WebResourceResponse";
57
58 @interface WebResourcePrivate : NSObject {
59 @public
60     RefPtr<ArchiveResource> coreResource;
61 }
62 - (instancetype)initWithCoreResource:(Ref<ArchiveResource>&&)coreResource;
63 @end
64
65 @implementation WebResourcePrivate
66
67 + (void)initialize
68 {
69 #if !PLATFORM(IOS)
70     JSC::initializeThreading();
71     WTF::initializeMainThreadToProcessMainThread();
72     RunLoop::initializeMainRunLoop();
73 #endif
74 }
75
76 - (instancetype)init
77 {
78     return [super init];
79 }
80
81 - (instancetype)initWithCoreResource:(Ref<ArchiveResource>&&)passedResource
82 {
83     self = [super init];
84     if (!self)
85         return nil;
86     coreResource = WTFMove(passedResource);
87     return self;
88 }
89
90 - (void)dealloc
91 {
92     if (WebCoreObjCScheduleDeallocateOnMainThread([WebResourcePrivate class], self))
93         return;
94     [super dealloc];
95 }
96
97 @end
98
99 @implementation WebResource
100
101 - (instancetype)init
102 {
103     self = [super init];
104     if (!self)
105         return nil;
106     _private = [[WebResourcePrivate alloc] init];
107     return self;
108 }
109
110 - (instancetype)initWithData:(NSData *)data URL:(NSURL *)URL MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)textEncodingName frameName:(NSString *)frameName
111 {
112     return [self _initWithData:data URL:URL MIMEType:MIMEType textEncodingName:textEncodingName frameName:frameName response:nil copyData:YES];
113 }
114
115 - (instancetype)initWithCoder:(NSCoder *)decoder
116 {
117     WebCoreThreadViolationCheckRoundTwo();
118
119     self = [super init];
120     if (!self)
121         return nil;
122
123     NSData *data = nil;
124     NSURL *url = nil;
125     NSString *mimeType = nil, *textEncoding = nil, *frameName = nil;
126     NSURLResponse *response = nil;
127     
128     @try {
129         id object = [decoder decodeObjectForKey:WebResourceDataKey];
130         if ([object isKindOfClass:[NSData class]])
131             data = object;
132         object = [decoder decodeObjectForKey:WebResourceURLKey];
133         if ([object isKindOfClass:[NSURL class]])
134             url = object;
135         object = [decoder decodeObjectForKey:WebResourceMIMETypeKey];
136         if ([object isKindOfClass:[NSString class]])
137             mimeType = object;
138         object = [decoder decodeObjectForKey:WebResourceTextEncodingNameKey];
139         if ([object isKindOfClass:[NSString class]])
140             textEncoding = object;
141         object = [decoder decodeObjectForKey:WebResourceFrameNameKey];
142         if ([object isKindOfClass:[NSString class]])
143             frameName = object;
144         object = [decoder decodeObjectForKey:WebResourceResponseKey];
145         if ([object isKindOfClass:[NSURLResponse class]])
146             response = object;
147     } @catch(id) {
148         [self release];
149         return nil;
150     }
151
152     auto coreResource = ArchiveResource::create(SharedBuffer::wrapNSData(data), url, mimeType, textEncoding, frameName, response);
153     if (!coreResource) {
154         [self release];
155         return nil;
156     }
157
158     _private = [[WebResourcePrivate alloc] initWithCoreResource:coreResource.releaseNonNull()];
159     return self;
160 }
161
162 - (void)encodeWithCoder:(NSCoder *)encoder
163 {
164     auto* resource = _private->coreResource.get();
165     
166     NSData *data = nil;
167     NSURL *url = nil;
168     NSString *mimeType = nil, *textEncoding = nil, *frameName = nil;
169     NSURLResponse *response = nil;
170     
171     if (resource) {
172         data = resource->data().createNSData().get();
173         url = resource->url();
174         mimeType = resource->mimeType();
175         textEncoding = resource->textEncoding();
176         frameName = resource->frameName();
177         response = resource->response().nsURLResponse();
178     }
179     [encoder encodeObject:data forKey:WebResourceDataKey];
180     [encoder encodeObject:url forKey:WebResourceURLKey];
181     [encoder encodeObject:mimeType forKey:WebResourceMIMETypeKey];
182     [encoder encodeObject:textEncoding forKey:WebResourceTextEncodingNameKey];
183     [encoder encodeObject:frameName forKey:WebResourceFrameNameKey];
184     [encoder encodeObject:response forKey:WebResourceResponseKey];
185 }
186
187 - (void)dealloc
188 {
189     [_private release];
190     [super dealloc];
191 }
192
193 - (id)copyWithZone:(NSZone *)zone
194 {
195     return [self retain];
196 }
197
198 - (NSData *)data
199 {
200     WebCoreThreadViolationCheckRoundTwo();
201
202     if (!_private->coreResource)
203         return nil;
204     return _private->coreResource->data().createNSData().autorelease();
205 }
206
207 - (NSURL *)URL
208 {
209     WebCoreThreadViolationCheckRoundTwo();
210
211     if (!_private->coreResource)
212         return nil;
213     return _private->coreResource->url();
214 }
215
216 - (NSString *)MIMEType
217 {
218     WebCoreThreadViolationCheckRoundTwo();
219
220     if (!_private->coreResource)
221         return nil;
222     NSString *mimeType = _private->coreResource->mimeType();
223     return mimeType;
224 }
225
226 - (NSString *)textEncodingName
227 {
228     WebCoreThreadViolationCheckRoundTwo();
229
230     if (!_private->coreResource)
231         return nil;
232     NSString *textEncodingName = _private->coreResource->textEncoding();
233     return textEncodingName;
234 }
235
236 - (NSString *)frameName
237 {
238     WebCoreThreadViolationCheckRoundTwo();
239
240     if (!_private->coreResource)
241         return nil;
242     NSString *frameName = _private->coreResource->frameName();
243     return frameName;
244 }
245
246 - (NSString *)description
247 {
248     return [NSString stringWithFormat:@"<%@ %@>", NSStringFromClass(self.class), self.URL];
249 }
250
251 @end
252
253 @implementation WebResource (WebResourceInternal)
254
255 - (id)_initWithCoreResource:(Ref<ArchiveResource>&&)coreResource
256 {
257     self = [super init];
258     if (!self)
259         return nil;
260
261     _private = [[WebResourcePrivate alloc] initWithCoreResource:WTFMove(coreResource)];
262     return self;
263 }
264
265 - (WebCore::ArchiveResource&)_coreResource
266 {
267     return *_private->coreResource;
268 }
269
270 @end
271
272 @implementation WebResource (WebResourcePrivate)
273
274 // SPI for Mail (5066325)
275 // FIXME: This "ignoreWhenUnarchiving" concept is an ugly one - can we find a cleaner solution for those who need this SPI?
276 - (void)_ignoreWhenUnarchiving
277 {
278     WebCoreThreadViolationCheckRoundTwo();
279
280     if (!_private->coreResource)
281         return;
282     _private->coreResource->ignoreWhenUnarchiving();
283 }
284
285 - (id)_initWithData:(NSData *)data 
286                 URL:(NSURL *)URL 
287            MIMEType:(NSString *)MIMEType 
288    textEncodingName:(NSString *)textEncodingName 
289           frameName:(NSString *)frameName 
290            response:(NSURLResponse *)response
291            copyData:(BOOL)copyData
292 {
293     WebCoreThreadViolationCheckRoundTwo();
294
295     self = [super init];
296     if (!self)
297         return nil;
298     
299     if (!data || !URL || !MIMEType) {
300         [self release];
301         return nil;
302     }
303
304     auto coreResource = ArchiveResource::create(SharedBuffer::wrapNSData(copyData ? [[data copy] autorelease] : data), URL, MIMEType, textEncodingName, frameName, response);
305     if (!coreResource) {
306         [self release];
307         return nil;
308     }
309
310     _private = [[WebResourcePrivate alloc] initWithCoreResource:coreResource.releaseNonNull()];
311     return self;
312 }
313
314 - (id)_initWithData:(NSData *)data URL:(NSURL *)URL response:(NSURLResponse *)response
315 {
316     // Pass NO for copyData since the data doesn't need to be copied since we know that callers will no longer modify it.
317     // Copying it will also cause a performance regression.
318     return [self _initWithData:data
319                            URL:URL
320                       MIMEType:[response MIMEType]
321               textEncodingName:[response textEncodingName]
322                      frameName:nil
323                       response:response
324                       copyData:NO];
325 }
326
327 - (NSString *)_suggestedFilename
328 {
329     WebCoreThreadViolationCheckRoundTwo();
330
331     if (!_private->coreResource)
332         return nil;
333     NSString *suggestedFilename = _private->coreResource->response().suggestedFilename();
334     return suggestedFilename;
335 }
336
337 #if !PLATFORM(IOS)
338 - (NSFileWrapper *)_fileWrapperRepresentation
339 {
340     NSFileWrapper *wrapper = [[[NSFileWrapper alloc] initRegularFileWithContents:[self data]] autorelease];
341     NSString *filename = [self _suggestedFilename];
342     if (!filename || ![filename length])
343         filename = [[self URL] _webkit_suggestedFilenameWithMIMEType:[self MIMEType]];
344     [wrapper setPreferredFilename:filename];
345     return wrapper;
346 }
347 #endif
348
349 - (NSURLResponse *)_response
350 {
351     WebCoreThreadViolationCheckRoundTwo();
352
353     NSURLResponse *response = nil;
354     if (_private->coreResource)
355         response = _private->coreResource->response().nsURLResponse();
356     return response ? response : [[[NSURLResponse alloc] init] autorelease];        
357 }
358
359 - (NSString *)_stringValue
360 {
361     WebCoreThreadViolationCheckRoundTwo();
362
363     WebCore::TextEncoding encoding;
364     if (_private->coreResource)
365         encoding = _private->coreResource->textEncoding();
366     if (!encoding.isValid())
367         encoding = WindowsLatin1Encoding();
368     
369     SharedBuffer* coreData = _private->coreResource ? &_private->coreResource->data() : nullptr;
370     return encoding.decode(reinterpret_cast<const char*>(coreData ? coreData->data() : nullptr), coreData ? coreData->size() : 0);
371 }
372
373 @end