LayoutTests:
[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)
101         newRequest.clearHTTPReferrer();
102     else if (!request.httpReferrer())
103         newRequest.setHTTPReferrer(fl->outgoingReferrer());
104
105     // Use the original request's cache policy for two reasons:
106     // 1. For POST requests, we mutate the cache policy for the main resource,
107     //    but we do not want this to apply to subresources
108     // 2. Delegates that modify the cache policy using willSendRequest: should
109     //    not affect any other resources. Such changes need to be done
110     //    per request.
111     if (newRequest.isConditional())
112         newRequest.setCachePolicy(ReloadIgnoringCacheData);
113     else
114         newRequest.setCachePolicy(fl->originalRequest().cachePolicy());
115
116     fl->addExtraFieldsToRequest(newRequest, false, false);
117
118     RefPtr<SubresourceLoader> subloader(new SubresourceLoader(frame, client));
119     if (!subloader->load(newRequest))
120         return 0;
121
122     return subloader.release();
123 }
124
125 void SubresourceLoader::willSendRequest(ResourceRequest& newRequest, const ResourceResponse& redirectResponse)
126 {
127     ResourceLoader::willSendRequest(newRequest, redirectResponse);
128     if (!newRequest.isNull() && m_originalURL != newRequest.url() && m_client)
129         m_client->willSendRequest(this, newRequest, redirectResponse);
130 }
131
132 void SubresourceLoader::didReceiveResponse(const ResourceResponse& r)
133 {
134     ASSERT(!r.isNull());
135
136     if (r.isMultipart())
137         m_loadingMultipartContent = true;
138
139     // Reference the object in this method since the additional processing can do
140     // anything including removing the last reference to this object; one example of this is 3266216.
141     RefPtr<SubresourceLoader> protect(this);
142
143     if (m_client)
144         m_client->didReceiveResponse(this, r);
145     
146     // The loader can cancel a load if it receives a multipart response for a non-image
147     if (reachedTerminalState())
148         return;
149     ResourceLoader::didReceiveResponse(r);
150     
151     RefPtr<SharedBuffer> buffer = resourceData();
152     if (m_loadingMultipartContent && buffer && buffer->size()) {
153         // Since a subresource loader does not load multipart sections progressively,
154         // deliver the previously received data to the loader all at once now.
155         // Then clear the data to make way for the next multipart section.
156         if (m_client)
157             m_client->didReceiveData(this, buffer->data(), buffer->size());
158         clearResourceData();
159         
160         // After the first multipart section is complete, signal to delegates that this load is "finished" 
161         didFinishLoadingOnePart();
162     }
163 }
164
165 void SubresourceLoader::didReceiveData(const char* data, int length, long long lengthReceived, bool allAtOnce)
166 {
167     // Reference the object in this method since the additional processing can do
168     // anything including removing the last reference to this object; one example of this is 3266216.
169     RefPtr<SubresourceLoader> protect(this);
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     ResourceLoader::didReceiveData(data, length, lengthReceived, allAtOnce);
177 }
178
179 void SubresourceLoader::didFinishLoading()
180 {
181     if (cancelled())
182         return;
183     ASSERT(!reachedTerminalState());
184
185     // Calling removeSubresourceLoader will likely result in a call to deref, so we must protect ourselves.
186     RefPtr<SubresourceLoader> protect(this);
187
188     if (m_client)
189         m_client->didFinishLoading(this);
190     
191     m_handle = 0;
192
193     if (cancelled())
194         return;
195     frameLoader()->removeSubresourceLoader(this);
196     ResourceLoader::didFinishLoading();
197 }
198
199 void SubresourceLoader::didFail(const ResourceError& error)
200 {
201     if (cancelled())
202         return;
203     ASSERT(!reachedTerminalState());
204
205     // Calling removeSubresourceLoader will likely result in a call to deref, so we must protect ourselves.
206     RefPtr<SubresourceLoader> protect(this);
207
208     if (m_client)
209         m_client->didFail(this, error);
210     
211     m_handle = 0;
212     
213     if (cancelled())
214         return;
215     frameLoader()->removeSubresourceLoader(this);
216     ResourceLoader::didFail(error);
217 }
218
219 void SubresourceLoader::didCancel(const ResourceError& error)
220 {
221     ASSERT(!reachedTerminalState());
222
223     // Calling removeSubresourceLoader will likely result in a call to deref, so we must protect ourselves.
224     RefPtr<SubresourceLoader> protect(this);
225
226     if (m_client)
227         m_client->didFail(this, error);
228     
229     if (cancelled())
230         return;
231     frameLoader()->removeSubresourceLoader(this);
232     ResourceLoader::didCancel(error);
233 }
234
235 void SubresourceLoader::stopLoading()
236 {
237     // FIXME: This should stop loading for real and not just clear the client.
238     m_client = 0;
239 }
240     
241 }