67a832834c3f3b66a6f44de97c9ae3babad68bcc
[WebKit-https.git] / WebCore / loader / mac / WebSubresourceLoader.mm
1 /*
2  * Copyright (C) 2005, 2006 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 "config.h"
30 #import "WebSubresourceLoader.h"
31
32 #import "FrameLoader.h"
33 #import "FrameMac.h"
34 #import "LoaderNSURLExtras.h"
35 #import "LoaderNSURLRequestExtras.h"
36 #import "WebCoreFrameBridge.h"
37 #import "WebCoreResourceLoader.h"
38 #import "WebCoreSystemInterface.h"
39 #import "WebFormDataStream.h"
40 #import <Foundation/NSURLResponse.h>
41 #import <wtf/Assertions.h>
42
43 using namespace WebCore;
44
45 @interface WebCoreSubresourceHandle : NSObject <WebCoreResourceHandle>
46 {
47     SubresourceLoader* m_loader;
48 }
49 - (id)initWithLoader:(SubresourceLoader*)loader;
50 @end
51
52 namespace WebCore {
53
54 SubresourceLoader::SubresourceLoader(Frame* frame, id <WebCoreResourceLoader> l)
55     : WebResourceLoader(frame)
56     , m_coreLoader(l)
57     , m_loadingMultipartContent(false)
58 {
59     frameLoader()->addSubresourceLoader(this);
60 }
61
62 SubresourceLoader::~SubresourceLoader()
63 {
64 }
65
66 id <WebCoreResourceHandle> SubresourceLoader::create(Frame* frame, id <WebCoreResourceLoader> rLoader,
67     NSMutableURLRequest *newRequest, NSString *method, NSDictionary *customHeaders, NSString *referrer)
68 {
69     FrameLoader* fl = frame->loader();
70     if (fl->state() == WebFrameStateProvisional)
71         return nil;
72
73     [newRequest setHTTPMethod:method];
74
75     wkSupportsMultipartXMixedReplace(newRequest);
76
77     NSEnumerator *e = [customHeaders keyEnumerator];
78     NSString *key;
79     while ((key = [e nextObject]))
80         [newRequest addValue:[customHeaders objectForKey:key] forHTTPHeaderField:key];
81
82     // Use the original request's cache policy for two reasons:
83     // 1. For POST requests, we mutate the cache policy for the main resource,
84     //    but we do not want this to apply to subresources
85     // 2. Delegates that modify the cache policy using willSendRequest: should
86     //    not affect any other resources. Such changes need to be done
87     //    per request.
88     if (isConditionalRequest(newRequest))
89         [newRequest setCachePolicy:NSURLRequestReloadIgnoringCacheData];
90     else
91         [newRequest setCachePolicy:[fl->originalRequest() cachePolicy]];
92     setHTTPReferrer(newRequest, referrer);
93     
94     fl->addExtraFieldsToRequest(newRequest, false, false);
95
96     RefPtr<SubresourceLoader> loader(new SubresourceLoader(frame, rLoader));
97     if (!loader->load(newRequest))
98         return nil;
99     return loader->handle();
100 }
101
102 id <WebCoreResourceHandle> SubresourceLoader::create(Frame* frame, id <WebCoreResourceLoader> rLoader,
103     NSString *method, NSURL *URL, NSDictionary *customHeaders, NSString *referrer)
104 {
105     NSMutableURLRequest *newRequest = [[NSMutableURLRequest alloc] initWithURL:URL];
106     id <WebCoreResourceHandle> handle = create(frame, rLoader, newRequest, method, customHeaders, referrer);
107     [newRequest release];
108     return handle;
109 }
110
111 id <WebCoreResourceHandle> SubresourceLoader::create(Frame* frame, id <WebCoreResourceLoader> rLoader,
112     NSString *method, NSURL *URL, NSDictionary *customHeaders, NSArray *postData, NSString *referrer)
113 {
114     NSMutableURLRequest *newRequest = [[NSMutableURLRequest alloc] initWithURL:URL];
115     webSetHTTPBody(newRequest, postData);
116     id <WebCoreResourceHandle> handle = create(frame, rLoader, newRequest, method, customHeaders, referrer);
117     [newRequest release];
118     return handle;
119 }
120
121 NSURLRequest *SubresourceLoader::willSendRequest(NSURLRequest *newRequest, NSURLResponse *redirectResponse)
122 {
123     NSURL *oldURL = [request() URL];
124     NSURLRequest *clientRequest = WebResourceLoader::willSendRequest(newRequest, redirectResponse);
125     if (clientRequest && oldURL != [clientRequest URL] && ![oldURL isEqual:[clientRequest URL]])
126         [m_coreLoader.get() redirectedToURL:[clientRequest URL]];
127     return clientRequest;
128 }
129
130 void SubresourceLoader::didReceiveResponse(NSURLResponse *r)
131 {
132     ASSERT(r);
133
134     if ([[r MIMEType] isEqualToString:@"multipart/x-mixed-replace"])
135         m_loadingMultipartContent = true;
136
137     // Reference the object in this method since the additional processing can do
138     // anything including removing the last reference to this object; one example of this is 3266216.
139     RefPtr<SubresourceLoader> protect(this);
140
141     [m_coreLoader.get() receivedResponse:r];
142     // The coreLoader can cancel a load if it receives a multipart response for a non-image
143     if (reachedTerminalState())
144         return;
145     WebResourceLoader::didReceiveResponse(r);
146     
147     if (m_loadingMultipartContent && [resourceData() length]) {
148         // Since a subresource loader does not load multipart sections progressively,
149         // deliver the previously received data to the coreLoader all at once now.
150         // Then clear the data to make way for the next multipart section.
151         [m_coreLoader.get() addData:resourceData()];
152         clearResourceData();
153         
154         // After the first multipart section is complete, signal to delegates that this load is "finished" 
155         didFinishLoadingOnePart();
156     }
157 }
158
159 void SubresourceLoader::didReceiveData(NSData *data, long long lengthReceived, bool allAtOnce)
160 {
161     // Reference the object in this method since the additional processing can do
162     // anything including removing the last reference to this object; one example of this is 3266216.
163     RefPtr<SubresourceLoader> protect(this);
164
165     // A subresource loader does not load multipart sections progressively.
166     // So don't deliver any data to the coreLoader yet.
167     if (!m_loadingMultipartContent)
168         [m_coreLoader.get() addData:data];
169     WebResourceLoader::didReceiveData(data, lengthReceived, allAtOnce);
170 }
171
172 void SubresourceLoader::didFinishLoading()
173 {
174     if (cancelled())
175         return;
176     ASSERT(!reachedTerminalState());
177
178     // Calling removeSubresourceLoader will likely result in a call to deref, so we must protect ourselves.
179     RefPtr<SubresourceLoader> protect(this);
180
181     [m_coreLoader.get() finishWithData:resourceData()];
182     if (cancelled())
183         return;
184     frameLoader()->removeSubresourceLoader(this);
185     WebResourceLoader::didFinishLoading();
186 }
187
188 void SubresourceLoader::didFail(NSError *error)
189 {
190     if (cancelled())
191         return;
192     ASSERT(!reachedTerminalState());
193
194     // Calling removeSubresourceLoader will likely result in a call to deref, so we must protect ourselves.
195     RefPtr<SubresourceLoader> protect(this);
196
197     [m_coreLoader.get() reportError];
198     if (cancelled())
199         return;
200     frameLoader()->removeSubresourceLoader(this);
201     WebResourceLoader::didFail(error);
202 }
203
204 void SubresourceLoader::didCancel(NSError *error)
205 {
206     ASSERT(!reachedTerminalState());
207
208     // Calling removeSubresourceLoader will likely result in a call to deref, so we must protect ourselves.
209     RefPtr<SubresourceLoader> protect(this);
210
211     [m_coreLoader.get() cancel];
212     if (cancelled())
213         return;
214     frameLoader()->removeSubresourceLoader(this);
215     WebResourceLoader::didCancel(error);
216 }
217
218 id <WebCoreResourceHandle> SubresourceLoader::handle()
219 {
220     return [[[WebCoreSubresourceHandle alloc] initWithLoader:this] autorelease];
221 }
222
223 }
224
225 @implementation WebCoreSubresourceHandle
226
227 - (id)initWithLoader:(SubresourceLoader*)loader
228 {
229     self = [self init];
230     if (!self)
231         return nil;
232     loader->ref();
233     m_loader = loader;
234     return self;
235 }
236
237 - (void)dealloc
238 {
239     m_loader->deref();
240     [super dealloc];
241 }
242
243 - (void)finalize
244 {
245     m_loader->deref();
246     [super finalize];
247 }
248
249 - (void)cancel
250 {
251     m_loader->cancel();
252 }
253
254 @end