2011-05-11 Antoine Labour <piman@chromium.org>
[WebKit-https.git] / Source / WebCore / loader / SubresourceLoader.cpp
1 /*
2  * Copyright (C) 2006, 2007, 2009 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 "ResourceHandle.h"
37 #include "SecurityOrigin.h"
38 #include "SubresourceLoaderClient.h"
39 #include <wtf/RefCountedLeakCounter.h>
40
41 namespace WebCore {
42
43 #ifndef NDEBUG    
44 static WTF::RefCountedLeakCounter subresourceLoaderCounter("SubresourceLoader");
45 #endif
46
47 SubresourceLoader::SubresourceLoader(Frame* frame, SubresourceLoaderClient* client, bool sendResourceLoadCallbacks, bool shouldContentSniff)
48     : ResourceLoader(frame, sendResourceLoadCallbacks, shouldContentSniff)
49     , m_client(client)
50     , m_loadingMultipartContent(false)
51 {
52 #ifndef NDEBUG
53     subresourceLoaderCounter.increment();
54 #endif
55 }
56
57 SubresourceLoader::~SubresourceLoader()
58 {
59 #ifndef NDEBUG
60     subresourceLoaderCounter.decrement();
61 #endif
62 }
63
64 PassRefPtr<SubresourceLoader> SubresourceLoader::create(Frame* frame, SubresourceLoaderClient* client, const ResourceRequest& request, SecurityCheckPolicy securityCheck, bool sendResourceLoadCallbacks, bool shouldContentSniff, const String& optionalOutgoingReferrer, bool shouldBufferData)
65 {
66     if (!frame)
67         return 0;
68
69     FrameLoader* fl = frame->loader();
70     if (securityCheck == DoSecurityCheck && (fl->state() == FrameStateProvisional || !fl->activeDocumentLoader() || fl->activeDocumentLoader()->isStopping()))
71         return 0;
72
73     ResourceRequest newRequest = request;
74
75     if (securityCheck == DoSecurityCheck && !frame->document()->securityOrigin()->canDisplay(request.url())) {
76         FrameLoader::reportLocalLoadFailed(frame, request.url().string());
77         return 0;
78     }
79
80     // Note: We skip the Content-Security-Policy check here because we check
81     // the Content-Security-Policy at the CachedResourceLoader layer so we can
82     // handle different resource types differently.
83
84     String outgoingReferrer;
85     String outgoingOrigin;
86     if (optionalOutgoingReferrer.isNull()) {
87         outgoingReferrer = fl->outgoingReferrer();
88         outgoingOrigin = fl->outgoingOrigin();
89     } else {
90         outgoingReferrer = optionalOutgoingReferrer;
91         outgoingOrigin = SecurityOrigin::createFromString(outgoingReferrer)->toString();
92     }
93
94     if (SecurityOrigin::shouldHideReferrer(request.url(), outgoingReferrer))
95         newRequest.clearHTTPReferrer();
96     else if (!request.httpReferrer())
97         newRequest.setHTTPReferrer(outgoingReferrer);
98     FrameLoader::addHTTPOriginIfNeeded(newRequest, outgoingOrigin);
99
100     fl->addExtraFieldsToSubresourceRequest(newRequest);
101
102     RefPtr<SubresourceLoader> subloader(adoptRef(new SubresourceLoader(frame, client, sendResourceLoadCallbacks, shouldContentSniff)));
103     subloader->setShouldBufferData(shouldBufferData);
104     subloader->documentLoader()->addSubresourceLoader(subloader.get());
105     if (!subloader->init(newRequest))
106         return 0;
107
108     return subloader.release();
109 }
110
111 void SubresourceLoader::willSendRequest(ResourceRequest& newRequest, const ResourceResponse& redirectResponse)
112 {
113     // Store the previous URL because the call to ResourceLoader::willSendRequest will modify it.
114     KURL previousURL = request().url();
115     
116     ResourceLoader::willSendRequest(newRequest, redirectResponse);
117     if (!previousURL.isNull() && !newRequest.isNull() && previousURL != newRequest.url() && m_client)
118         m_client->willSendRequest(this, newRequest, redirectResponse);
119 }
120
121 void SubresourceLoader::didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
122 {
123     RefPtr<SubresourceLoader> protect(this);
124
125     if (m_client)
126         m_client->didSendData(this, bytesSent, totalBytesToBeSent);
127 }
128
129 void SubresourceLoader::didReceiveResponse(const ResourceResponse& r)
130 {
131     ASSERT(!r.isNull());
132
133     if (r.isMultipart())
134         m_loadingMultipartContent = true;
135
136     // Reference the object in this method since the additional processing can do
137     // anything including removing the last reference to this object; one example of this is 3266216.
138     RefPtr<SubresourceLoader> protect(this);
139
140     if (m_client)
141         m_client->didReceiveResponse(this, r);
142     
143     // The loader can cancel a load if it receives a multipart response for a non-image
144     if (reachedTerminalState())
145         return;
146     ResourceLoader::didReceiveResponse(r);
147     
148     RefPtr<SharedBuffer> buffer = resourceData();
149     if (m_loadingMultipartContent && buffer && buffer->size()) {
150         // Since a subresource loader does not load multipart sections progressively,
151         // deliver the previously received data to the loader all at once now.
152         // Then clear the data to make way for the next multipart section.
153         if (m_client)
154             m_client->didReceiveData(this, buffer->data(), buffer->size());
155         clearResourceData();
156         
157         // After the first multipart section is complete, signal to delegates that this load is "finished" 
158         m_documentLoader->subresourceLoaderFinishedLoadingOnePart(this);
159         didFinishLoadingOnePart(0);
160     }
161 }
162
163 void SubresourceLoader::didReceiveData(const char* data, int length, long long encodedDataLength, 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     ResourceLoader::didReceiveData(data, length, encodedDataLength, allAtOnce);
170
171     // A subresource loader does not load multipart sections progressively.
172     // So don't deliver any data to the loader yet.
173     if (!m_loadingMultipartContent && m_client)
174         m_client->didReceiveData(this, data, length);
175 }
176
177 void SubresourceLoader::didReceiveCachedMetadata(const char* data, int length)
178 {
179     // Reference the object in this method since the additional processing can do
180     // anything including removing the last reference to this object; one example of this is 3266216.
181     RefPtr<SubresourceLoader> protect(this);
182     
183     if (m_client)
184         m_client->didReceiveCachedMetadata(this, data, length);
185 }
186
187 void SubresourceLoader::didFinishLoading(double finishTime)
188 {
189     if (cancelled())
190         return;
191     ASSERT(!reachedTerminalState());
192
193     // Calling removeSubresourceLoader will likely result in a call to deref, so we must protect ourselves.
194     RefPtr<SubresourceLoader> protect(this);
195
196     if (m_client)
197         m_client->didFinishLoading(this, finishTime);
198     
199     m_handle = 0;
200
201     if (cancelled())
202         return;
203     m_documentLoader->removeSubresourceLoader(this);
204     ResourceLoader::didFinishLoading(finishTime);
205 }
206
207 void SubresourceLoader::didFail(const ResourceError& error)
208 {
209     if (cancelled())
210         return;
211     ASSERT(!reachedTerminalState());
212
213     // Calling removeSubresourceLoader will likely result in a call to deref, so we must protect ourselves.
214     RefPtr<SubresourceLoader> protect(this);
215
216     if (m_client)
217         m_client->didFail(this, error);
218     
219     m_handle = 0;
220     
221     if (cancelled())
222         return;
223     m_documentLoader->removeSubresourceLoader(this);
224     ResourceLoader::didFail(error);
225 }
226
227 void SubresourceLoader::didCancel(const ResourceError& error)
228 {
229     ASSERT(!reachedTerminalState());
230
231     // Calling removeSubresourceLoader will likely result in a call to deref, so we must protect ourselves.
232     RefPtr<SubresourceLoader> protect(this);
233
234     if (m_client)
235         m_client->didFail(this, error);
236     
237     if (cancelled())
238         return;
239     
240     // The only way the subresource loader can reach the terminal state here is if the run loop spins when calling
241     // m_client->didFail. This should in theory not happen which is why the assert is here. 
242     ASSERT(!reachedTerminalState());
243     if (reachedTerminalState())
244         return;
245     
246     m_documentLoader->removeSubresourceLoader(this);
247     ResourceLoader::didCancel(error);
248 }
249
250 bool SubresourceLoader::shouldUseCredentialStorage()
251 {
252     RefPtr<SubresourceLoader> protect(this);
253
254     bool shouldUse;
255     if (m_client && m_client->getShouldUseCredentialStorage(this, shouldUse))
256         return shouldUse;
257
258     return ResourceLoader::shouldUseCredentialStorage();
259 }
260
261 void SubresourceLoader::didReceiveAuthenticationChallenge(const AuthenticationChallenge& challenge)
262 {
263     RefPtr<SubresourceLoader> protect(this);
264
265     ASSERT(handle()->hasAuthenticationChallenge());
266
267     if (m_client)
268         m_client->didReceiveAuthenticationChallenge(this, challenge);
269     
270     // The SubResourceLoaderClient may have cancelled this ResourceLoader in response to the challenge.  
271     // If that's the case, don't call didReceiveAuthenticationChallenge.
272     if (reachedTerminalState())
273         return;
274
275     // It may have also handled authentication on its own.
276     if (!handle()->hasAuthenticationChallenge())
277         return;
278
279     ResourceLoader::didReceiveAuthenticationChallenge(challenge);
280 }
281
282 void SubresourceLoader::receivedCancellation(const AuthenticationChallenge& challenge)
283 {
284     ASSERT(!reachedTerminalState());
285         
286     RefPtr<SubresourceLoader> protect(this);
287
288     if (m_client)
289         m_client->receivedCancellation(this, challenge);
290     
291     ResourceLoader::receivedCancellation(challenge);
292 }
293     
294
295 }