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