Reviewed by Darin.
[WebKit-https.git] / WebKit / WebView / WebResource.mm
1 /*
2  * Copyright (C) 2005 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/WebFrameBridge.h>
30 #import <WebKit/WebResourcePrivate.h>
31 #import <WebKit/WebNSDictionaryExtras.h>
32 #import <WebKit/WebNSURLExtras.h>
33
34 NSString *WebResourceDataKey =              @"WebResourceData";
35 NSString *WebResourceFrameNameKey =         @"WebResourceFrameName";
36 NSString *WebResourceMIMETypeKey =          @"WebResourceMIMEType";
37 NSString *WebResourceURLKey =               @"WebResourceURL";
38 NSString *WebResourceTextEncodingNameKey =  @"WebResourceTextEncodingName";
39 NSString *WebResourceResponseKey =          @"WebResourceResponse";
40
41 #define WebResourceVersion 1
42
43 @interface WebResourcePrivate : NSObject
44 {
45 @public
46     NSData *data;
47     NSURL *URL;
48     NSString *frameName;
49     NSString *MIMEType;
50     NSString *textEncodingName;
51     NSURLResponse *response;
52 }
53 @end
54
55 @implementation WebResourcePrivate
56
57 - (void)dealloc
58 {
59     [data release];
60     [URL release];
61     [frameName release];
62     [MIMEType release];
63     [textEncodingName release];
64     [response release];
65     [super dealloc];
66 }
67
68 @end
69
70 @implementation WebResource
71
72 - (id)init
73 {
74     self = [super init];
75     if (!self)
76         return nil;
77     _private = [[WebResourcePrivate alloc] init];
78     return self;
79 }
80
81 - (id)initWithData:(NSData *)data URL:(NSURL *)URL MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)textEncodingName frameName:(NSString *)frameName
82 {
83     return [self _initWithData:data URL:URL MIMEType:MIMEType textEncodingName:textEncodingName frameName:frameName response:nil copyData:YES];
84 }
85
86 - (id)initWithCoder:(NSCoder *)decoder
87 {
88     self = [self init];
89     if (!self)
90         return nil;
91
92     NS_DURING
93         _private->data = [[decoder decodeObjectForKey:WebResourceDataKey] retain];
94         _private->URL = [[decoder decodeObjectForKey:WebResourceURLKey] retain];
95         _private->MIMEType = [[decoder decodeObjectForKey:WebResourceMIMETypeKey] retain];
96         _private->textEncodingName = [[decoder decodeObjectForKey:WebResourceTextEncodingNameKey] retain];
97         _private->frameName = [[decoder decodeObjectForKey:WebResourceFrameNameKey] retain];
98         _private->response = [[decoder decodeObjectForKey:WebResourceResponseKey] retain];
99     NS_HANDLER
100         [self release];
101         return nil;
102     NS_ENDHANDLER
103     return self;
104 }
105
106 - (void)encodeWithCoder:(NSCoder *)encoder
107 {
108     [encoder encodeObject:_private->data forKey:WebResourceDataKey];
109     [encoder encodeObject:_private->URL forKey:WebResourceURLKey];
110     [encoder encodeObject:_private->MIMEType forKey:WebResourceMIMETypeKey];
111     [encoder encodeObject:_private->textEncodingName forKey:WebResourceTextEncodingNameKey];
112     [encoder encodeObject:_private->frameName forKey:WebResourceFrameNameKey];
113     [encoder encodeObject:_private->response forKey:WebResourceResponseKey];
114 }
115
116 - (void)dealloc
117 {
118     [_private release];
119     [super dealloc];
120 }
121
122 - (id)copyWithZone:(NSZone *)zone
123 {
124     return [self retain];
125 }
126
127 - (NSData *)data
128 {
129     return _private->data;
130 }
131
132 - (NSURL *)URL
133 {
134     return _private->URL;
135 }
136
137 - (NSString *)MIMEType
138 {
139     return _private->MIMEType;
140 }
141
142 - (NSString *)textEncodingName
143 {
144     return _private->textEncodingName;
145 }
146
147 - (NSString *)frameName
148 {
149     return _private->frameName;
150 }
151
152 - (id)description
153 {
154     return [NSString stringWithFormat:@"<%@ %@>", [self className], [self URL]];
155 }
156
157 @end
158
159 @implementation WebResource (WebResourcePrivate)
160
161 + (NSArray *)_resourcesFromPropertyLists:(NSArray *)propertyLists
162 {
163     if (![propertyLists isKindOfClass:[NSArray class]]) {
164         return nil;
165     }
166     NSEnumerator *enumerator = [propertyLists objectEnumerator];
167     NSMutableArray *resources = [NSMutableArray array];
168     NSDictionary *propertyList;
169     while ((propertyList = [enumerator nextObject]) != nil) {
170         WebResource *resource = [[WebResource alloc] _initWithPropertyList:propertyList];
171         if (resource) {
172             [resources addObject:resource];
173             [resource release];
174         }
175     }
176     return resources;
177 }
178
179 + (NSArray *)_propertyListsFromResources:(NSArray *)resources
180 {
181     NSEnumerator *enumerator = [resources objectEnumerator];
182     NSMutableArray *propertyLists = [NSMutableArray array];
183     WebResource *resource;
184     while ((resource = [enumerator nextObject]) != nil) {
185         [propertyLists addObject:[resource _propertyListRepresentation]];
186     }
187     return propertyLists;
188 }
189
190 - (id)_initWithData:(NSData *)data 
191                 URL:(NSURL *)URL 
192            MIMEType:(NSString *)MIMEType 
193    textEncodingName:(NSString *)textEncodingName 
194           frameName:(NSString *)frameName 
195            response:(NSURLResponse *)response
196            copyData:(BOOL)copyData
197 {
198     [self init];    
199     
200     if (!data) {
201         [self release];
202         return nil;
203     }
204     _private->data = copyData ? [data copy] : [data retain];
205     
206     if (!URL) {
207         [self release];
208         return nil;
209     }
210     _private->URL = [URL copy];
211     
212     if (!MIMEType) {
213         [self release];
214         return nil;
215     }
216     _private->MIMEType = [MIMEType copy];
217     
218     _private->textEncodingName = [textEncodingName copy];
219     _private->frameName = [frameName copy];
220     _private->response = [response retain];
221         
222     return self;
223 }
224
225 - (id)_initWithData:(NSData *)data URL:(NSURL *)URL response:(NSURLResponse *)response
226 {
227     // Pass NO for copyData since the data doesn't need to be copied since we know that callers will no longer modify it.
228     // Copying it will also cause a performance regression.
229     return [self _initWithData:data
230                            URL:URL
231                       MIMEType:[response MIMEType]
232               textEncodingName:[response textEncodingName]
233                      frameName:nil
234                       response:response
235                       copyData:NO];    
236 }
237
238 - (id)_initWithPropertyList:(id)propertyList
239 {
240     if (![propertyList isKindOfClass:[NSDictionary class]]) {
241         [self release];
242         return nil;
243     }
244     
245     NSURLResponse *response = nil;
246     NSData *responseData = [propertyList objectForKey:WebResourceResponseKey];
247     if ([responseData isKindOfClass:[NSData class]]) {
248         NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:responseData];
249         response = [unarchiver decodeObjectForKey:WebResourceResponseKey];
250         [unarchiver finishDecoding];
251         [unarchiver release];    
252     }
253
254     NSData *data = [propertyList objectForKey:WebResourceDataKey];
255     NSString *URLString = [propertyList _webkit_stringForKey:WebResourceURLKey];
256     return [self _initWithData:[data isKindOfClass:[NSData class]] ? data : nil
257                            URL:URLString ? [NSURL _web_URLWithDataAsString:URLString] : nil
258                       MIMEType:[propertyList _webkit_stringForKey:WebResourceMIMETypeKey]
259               textEncodingName:[propertyList _webkit_stringForKey:WebResourceTextEncodingNameKey]
260                      frameName:[propertyList _webkit_stringForKey:WebResourceFrameNameKey]
261                       response:response
262                       copyData:NO];
263 }
264
265 - (NSFileWrapper *)_fileWrapperRepresentation
266 {
267     NSFileWrapper *wrapper = [[[NSFileWrapper alloc] initRegularFileWithContents:_private->data] autorelease];
268     [wrapper setPreferredFilename:[_private->URL _webkit_suggestedFilenameWithMIMEType:_private->MIMEType]];
269     return wrapper;
270 }
271
272 - (id)_propertyListRepresentation
273 {
274     NSMutableDictionary *propertyList = [NSMutableDictionary dictionary];
275     [propertyList setObject:_private->data forKey:WebResourceDataKey];
276     [propertyList setObject:[_private->URL _web_originalDataAsString] forKey:WebResourceURLKey];
277     [propertyList setObject:_private->MIMEType forKey:WebResourceMIMETypeKey];
278     if (_private->textEncodingName != nil) {
279         [propertyList setObject:_private->textEncodingName forKey:WebResourceTextEncodingNameKey];
280     }
281     if (_private->frameName != nil) {
282         [propertyList setObject:_private->frameName forKey:WebResourceFrameNameKey];
283     }    
284     if (_private->response != nil) {
285         NSMutableData *responseData = [[NSMutableData alloc] init];
286         NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:responseData];
287         [archiver encodeObject:_private->response forKey:WebResourceResponseKey];
288         [archiver finishEncoding];
289         [archiver release];
290         [propertyList setObject:responseData forKey:WebResourceResponseKey];
291         [responseData release];
292     }        
293     return propertyList;
294 }
295
296 - (NSURLResponse *)_response
297 {
298     if (_private->response != nil) {
299         return _private->response;
300     }
301     return [[[NSURLResponse alloc] initWithURL:_private->URL
302                                       MIMEType:_private->MIMEType 
303                          expectedContentLength:[_private->data length]
304                               textEncodingName:_private->textEncodingName] autorelease];
305 }
306
307 - (NSString *)_stringValue
308 {
309     NSString *textEncodingName = [self textEncodingName];
310     return [WebFrameBridge stringWithData:_private->data textEncodingName:textEncodingName];
311 }
312
313 @end