WebKit:
[WebKit-https.git] / WebKit / Loader / WebSubresourceLoader.m
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/WebSubresourceLoader.h>
30
31 #import <JavaScriptCore/Assertions.h>
32 #import <WebKit/WebDataSourceInternal.h>
33 #import <WebKit/WebFormDataStream.h>
34 #import <WebKit/WebFrameInternal.h>
35 #import <WebKit/WebFrameLoader.h>
36 #import <WebKit/WebKitErrorsPrivate.h>
37 #import <WebKit/WebNSURLRequestExtras.h>
38
39 #import <Foundation/NSURLResponse.h>
40
41 #import <WebCore/WebCoreResourceLoader.h>
42 #import <WebKitSystemInterface.h>
43
44 @implementation WebSubresourceLoader
45
46 - initWithLoader:(id <WebCoreResourceLoader>)l frameLoader:(WebFrameLoader *)fl
47 {
48     [super init];
49     
50     coreLoader = [l retain];
51
52     [self setFrameLoader:fl];
53     
54     return self;
55 }
56
57 - (void)dealloc
58 {
59     [coreLoader release];
60     [super dealloc];
61 }
62
63 + (WebSubresourceLoader *)startLoadingResource:(id <WebCoreResourceLoader>)rLoader
64                                    withRequest:(NSMutableURLRequest *)newRequest
65                                  customHeaders:(NSDictionary *)customHeaders
66                                       referrer:(NSString *)referrer 
67                                 forFrameLoader:(WebFrameLoader *)fl
68 {
69     WebSubresourceLoader *loader = [[[self alloc] initWithLoader:rLoader frameLoader:fl] autorelease];
70     
71     [fl _addSubresourceLoader:loader];
72
73     NSEnumerator *e = [customHeaders keyEnumerator];
74     NSString *key;
75     while ((key = [e nextObject]))
76         [newRequest addValue:[customHeaders objectForKey:key] forHTTPHeaderField:key];
77
78     // Use the original request's cache policy for two reasons:
79     // 1. For POST requests, we mutate the cache policy for the main resource,
80     //    but we do not want this to apply to subresources
81     // 2. Delegates that modify the cache policy using willSendRequest: should
82     //    not affect any other resources. Such changes need to be done
83     //    per request.
84     if ([newRequest _web_isConditionalRequest])
85         [newRequest setCachePolicy:NSURLRequestReloadIgnoringCacheData];
86     else
87         [newRequest setCachePolicy:[[fl _originalRequest] cachePolicy]];
88     [newRequest _web_setHTTPReferrer:referrer];
89     
90     [[fl webFrame] _addExtraFieldsToRequest:newRequest mainResource:NO alwaysFromRequest:NO];
91             
92     if (![loader loadWithRequest:newRequest])
93         loader = nil;
94     
95     return loader;
96 }
97
98 + (WebSubresourceLoader *)startLoadingResource:(id <WebCoreResourceLoader>)rLoader
99                                     withMethod:(NSString *)method 
100                                            URL:(NSURL *)URL
101                                  customHeaders:(NSDictionary *)customHeaders
102                                       referrer:(NSString *)referrer
103                                  forFrameLoader:(WebFrameLoader *)fl
104 {
105     NSMutableURLRequest *newRequest = [[NSMutableURLRequest alloc] initWithURL:URL];
106
107     // setHTTPMethod is not called for GET requests to work around <rdar://4464032>.
108     if (![method isEqualToString:@"GET"])
109         [newRequest setHTTPMethod:method];
110
111     WebSubresourceLoader *loader = [self startLoadingResource:rLoader withRequest:newRequest customHeaders:customHeaders referrer:referrer forFrameLoader:fl];
112     [newRequest release];
113
114     return loader;
115 }
116
117 + (WebSubresourceLoader *)startLoadingResource:(id <WebCoreResourceLoader>)rLoader
118                                     withMethod:(NSString *)method 
119                                            URL:(NSURL *)URL
120                                  customHeaders:(NSDictionary *)customHeaders
121                                       postData:(NSArray *)postData
122                                       referrer:(NSString *)referrer
123                                 forFrameLoader:(WebFrameLoader *)fl
124 {
125     NSMutableURLRequest *newRequest = [[NSMutableURLRequest alloc] initWithURL:URL];
126
127     // setHTTPMethod is not called for GET requests to work around <rdar://4464032>.
128     if (![method isEqualToString:@"GET"])
129         [newRequest setHTTPMethod:method];
130
131     webSetHTTPBody(newRequest, postData);
132
133     WebSubresourceLoader *loader = [self startLoadingResource:rLoader withRequest:newRequest customHeaders:customHeaders referrer:referrer forFrameLoader:fl];
134     [newRequest release];
135
136     return loader;
137
138 }
139
140 - (void)receivedError:(NSError *)error
141 {
142     [frameLoader _receivedError:error];
143 }
144
145 - (NSURLRequest *)willSendRequest:(NSURLRequest *)newRequest redirectResponse:(NSURLResponse *)redirectResponse;
146 {
147     NSURL *oldURL = [request URL];
148     NSURLRequest *clientRequest = [super willSendRequest:newRequest redirectResponse:redirectResponse];
149     
150     if (clientRequest != nil && oldURL != [clientRequest URL] && ![oldURL isEqual:[clientRequest URL]])
151         [coreLoader redirectedToURL:[clientRequest URL]];
152
153     return clientRequest;
154 }
155
156 - (void)didReceiveResponse:(NSURLResponse *)r
157 {
158     ASSERT(r);
159
160     if ([[r MIMEType] isEqualToString:@"multipart/x-mixed-replace"])
161         loadingMultipartContent = YES;
162
163     // retain/release self in this delegate method since the additional processing can do
164     // anything including possibly releasing self; one example of this is 3266216
165     [self retain];
166     [coreLoader receivedResponse:r];
167     // The coreLoader can cancel a load if it receives a multipart response for a non-image
168     if (reachedTerminalState) {
169         [self release];
170         return;
171     }
172     [super didReceiveResponse:r];
173     [self release];
174     
175     if (loadingMultipartContent && [[self resourceData] length]) {
176         // A subresource loader does not load multipart sections progressively, deliver the previously received data to the coreLoader all at once
177         [coreLoader addData:[self resourceData]];
178         // Clears the data to make way for the next multipart section
179         [self clearResourceData];
180         
181         // After the first multipart section is complete, signal to delegates that this load is "finished" 
182         if (!signalledFinish)
183             [self signalFinish];
184     }
185 }
186
187 - (void)didReceiveData:(NSData *)data lengthReceived:(long long)lengthReceived
188 {
189     // retain/release self in this delegate method since the additional processing can do
190     // anything including possibly releasing self; one example of this is 3266216
191     [self retain];
192     // A subresource loader does not load multipart sections progressively, don't deliver any data to the coreLoader yet
193     if (!loadingMultipartContent)
194         [coreLoader addData:data];
195     [super didReceiveData:data lengthReceived:lengthReceived];
196     [self release];
197 }
198
199 - (void)signalFinish
200 {
201     [frameLoader _removeSubresourceLoader:self];
202     [frameLoader _finishedLoadingResource];
203     [super signalFinish];
204 }
205
206 - (void)didFinishLoading
207 {
208     // Calling _removeSubresourceLoader will likely result in a call to release, so we must retain.
209     [self retain];
210     
211     [coreLoader finishWithData:[self resourceData]];
212     
213     if (!signalledFinish)
214         [self signalFinish];
215         
216     [super didFinishLoading];
217
218     [self release];    
219 }
220
221 - (void)didFailWithError:(NSError *)error
222 {
223     // Calling _removeSubresourceLoader will likely result in a call to release, so we must retain.
224     [self retain];
225     
226     [coreLoader reportError];
227     [frameLoader _removeSubresourceLoader:self];
228     [self receivedError:error];
229     [super didFailWithError:error];
230
231     [self release];
232 }
233
234 - (void)cancel
235 {
236     // Calling _removeSubresourceLoader will likely result in a call to release, so we must retain.
237     [self retain];
238         
239     [coreLoader cancel];
240     [frameLoader _removeSubresourceLoader:self];
241     [self receivedError:[self cancelledError]];
242     [super cancel];
243
244     [self release];
245 }
246
247 @end