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