7bea4df1c250ae7f4067e4f6db67d015c0ff39ea
[WebKit-https.git] / WebCore / loader / SubresourceLoader.cpp
1 /*
2  * Copyright (C) 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 #include "config.h"
30 #include "SubresourceLoader.h"
31
32 #include "Document.h"
33 #include "Frame.h"
34 #include "Logging.h"
35 #include "ResourceHandle.h"
36 #include "ResourceRequest.h"
37 #include "SubresourceLoaderClient.h"
38 #include "SharedBuffer.h"
39 #include "FrameLoader.h"
40
41 namespace WebCore {
42
43 #ifndef NDEBUG
44 WTFLogChannel LogWebCoreSubresourceLoaderLeaks =  { 0x00000000, "", WTFLogChannelOn };
45
46 struct SubresourceLoaderCounter {
47     static unsigned count; 
48
49     ~SubresourceLoaderCounter() 
50     { 
51         if (count) 
52             LOG(WebCoreSubresourceLoaderLeaks, "LEAK: %u SubresourceLoader\n", count); 
53     }
54 };
55 unsigned SubresourceLoaderCounter::count = 0;
56 static SubresourceLoaderCounter subresourceLoaderCounter;
57 #endif
58
59 SubresourceLoader::SubresourceLoader(Frame* frame, SubresourceLoaderClient* client)
60     : ResourceLoader(frame)
61     , m_client(client)
62     , m_loadingMultipartContent(false)
63 {
64 #ifndef NDEBUG
65     ++SubresourceLoaderCounter::count;
66 #endif
67     frameLoader()->addSubresourceLoader(this);
68 }
69
70 SubresourceLoader::~SubresourceLoader()
71 {
72 #ifndef NDEBUG
73     --SubresourceLoaderCounter::count;
74 #endif
75 }
76
77 bool SubresourceLoader::load(const ResourceRequest& r)
78 {
79     m_frame->loader()->didTellBridgeAboutLoad(r.url().url());
80     
81     return ResourceLoader::load(r);
82 }
83
84 PassRefPtr<SubresourceLoader> SubresourceLoader::create(Frame* frame, SubresourceLoaderClient* client, const ResourceRequest& request)
85 {
86     if (!frame)
87         return 0;
88
89     FrameLoader* fl = frame->loader();
90     if (fl->state() == FrameStateProvisional)
91         return 0;
92
93     ResourceRequest newRequest = request;
94     
95     // Since this is a subresource, we can load any URL (we ignore the return value).
96     // But we still want to know whether we should hide the referrer or not, so we call the canLoadURL method.
97     // FIXME: is that really the rule we want for subresources?
98     bool hideReferrer;
99     fl->canLoad(request.url(), fl->outgoingReferrer(), hideReferrer);
100     if (!hideReferrer && !request.httpReferrer())
101         newRequest.setHTTPReferrer(fl->outgoingReferrer());
102
103     // Use the original request's cache policy for two reasons:
104     // 1. For POST requests, we mutate the cache policy for the main resource,
105     //    but we do not want this to apply to subresources
106     // 2. Delegates that modify the cache policy using willSendRequest: should
107     //    not affect any other resources. Such changes need to be done
108     //    per request.
109     if (newRequest.isConditional())
110         newRequest.setCachePolicy(ReloadIgnoringCacheData);
111     else
112         newRequest.setCachePolicy(fl->originalRequest().cachePolicy());
113
114     fl->addExtraFieldsToRequest(newRequest, false, false);
115
116     RefPtr<SubresourceLoader> subloader(new SubresourceLoader(frame, client));
117     if (!subloader->load(newRequest))
118         return 0;
119
120     return subloader.release();
121 }
122
123 void SubresourceLoader::willSendRequest(ResourceRequest& newRequest, const ResourceResponse& redirectResponse)
124 {
125     ResourceLoader::willSendRequest(newRequest, redirectResponse);
126     if (!newRequest.isNull() && m_originalURL != newRequest.url() && m_client)
127         m_client->willSendRequest(this, newRequest, redirectResponse);
128 }
129
130 void SubresourceLoader::didReceiveResponse(const ResourceResponse& r)
131 {
132     ASSERT(!r.isNull());
133
134     if (r.isMultipart())
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     if (m_client)
142         m_client->didReceiveResponse(this, r);
143     
144     // The loader can cancel a load if it receives a multipart response for a non-image
145     if (reachedTerminalState())
146         return;
147     ResourceLoader::didReceiveResponse(r);
148     
149     RefPtr<SharedBuffer> buffer = resourceData();
150     if (m_loadingMultipartContent && buffer && buffer->size()) {
151         // Since a subresource loader does not load multipart sections progressively,
152         // deliver the previously received data to the loader all at once now.
153         // Then clear the data to make way for the next multipart section.
154         if (m_client)
155             m_client->didReceiveData(this, buffer->data(), buffer->size());
156         clearResourceData();
157         
158         // After the first multipart section is complete, signal to delegates that this load is "finished" 
159         didFinishLoadingOnePart();
160     }
161 }
162
163 void SubresourceLoader::didReceiveData(const char* data, int length, long long lengthReceived, bool allAtOnce)
164 {
165     // Reference the object in this method since the additional processing can do
166     // anything including removing the last reference to this object; one example of this is 3266216.
167     RefPtr<SubresourceLoader> protect(this);
168
169     // A subresource loader does not load multipart sections progressively.
170     // So don't deliver any data to the loader yet.
171     if (!m_loadingMultipartContent && m_client)
172         m_client->didReceiveData(this, data, length);
173
174     ResourceLoader::didReceiveData(data, length, lengthReceived, allAtOnce);
175 }
176
177 void SubresourceLoader::didFinishLoading()
178 {
179     if (cancelled())
180         return;
181     ASSERT(!reachedTerminalState());
182
183     // Calling removeSubresourceLoader will likely result in a call to deref, so we must protect ourselves.
184     RefPtr<SubresourceLoader> protect(this);
185
186     if (m_client)
187         m_client->didFinishLoading(this);
188     
189     m_handle = 0;
190
191     if (cancelled())
192         return;
193     frameLoader()->removeSubresourceLoader(this);
194     ResourceLoader::didFinishLoading();
195 }
196
197 void SubresourceLoader::didFail(const ResourceError& error)
198 {
199     if (cancelled())
200         return;
201     ASSERT(!reachedTerminalState());
202
203     // Calling removeSubresourceLoader will likely result in a call to deref, so we must protect ourselves.
204     RefPtr<SubresourceLoader> protect(this);
205
206     if (m_client)
207         m_client->didFail(this, error);
208     
209     m_handle = 0;
210     
211     if (cancelled())
212         return;
213     frameLoader()->removeSubresourceLoader(this);
214     ResourceLoader::didFail(error);
215 }
216
217 void SubresourceLoader::didCancel(const ResourceError& error)
218 {
219     ASSERT(!reachedTerminalState());
220
221     // Calling removeSubresourceLoader will likely result in a call to deref, so we must protect ourselves.
222     RefPtr<SubresourceLoader> protect(this);
223
224     if (m_client)
225         m_client->didFail(this, error);
226     
227     if (cancelled())
228         return;
229     frameLoader()->removeSubresourceLoader(this);
230     ResourceLoader::didCancel(error);
231 }
232
233 void SubresourceLoader::stopLoading()
234 {
235     // FIXME: This should stop loading for real and not just clear the client.
236     m_client = 0;
237 }
238     
239 }