dec248672e7e28ba7b63c432584ab0601d14a22c
[WebKit-https.git] / Source / WebCore / loader / MainResourceLoader.cpp
1 /*
2  * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
3  * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1.  Redistributions of source code must retain the above copyright
10  *     notice, this list of conditions and the following disclaimer. 
11  * 2.  Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution. 
14  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15  *     its contributors may be used to endorse or promote products derived
16  *     from this software without specific prior written permission. 
17  *
18  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include "config.h"
31 #include "MainResourceLoader.h"
32
33 #include "ApplicationCacheHost.h"
34 #include "BackForwardController.h"
35 #include "CachedRawResource.h"
36 #include "CachedResourceLoader.h"
37 #include "CachedResourceRequest.h"
38 #include "Console.h"
39 #include "DOMWindow.h"
40 #include "Document.h"
41 #include "DocumentLoadTiming.h"
42 #include "DocumentLoader.h"
43 #include "FeatureObserver.h"
44 #include "Frame.h"
45 #include "FrameLoader.h"
46 #include "FrameLoaderClient.h"
47 #include "HTMLFormElement.h"
48 #include "HistoryItem.h"
49 #include "InspectorInstrumentation.h"
50 #include "MemoryCache.h"
51 #include "Page.h"
52 #include "ProgressTracker.h"
53 #include "ResourceBuffer.h"
54 #include "ResourceError.h"
55 #include "ResourceHandle.h"
56 #include "SchemeRegistry.h"
57 #include "SecurityOrigin.h"
58 #include "Settings.h"
59 #include "SubresourceLoader.h"
60 #include <wtf/CurrentTime.h>
61
62 #if PLATFORM(QT)
63 #include "PluginDatabase.h"
64 #endif
65
66 namespace WebCore {
67
68 MainResourceLoader::MainResourceLoader(DocumentLoader* documentLoader)
69     : m_dataLoadTimer(this, &MainResourceLoader::handleSubstituteDataLoadNow)
70     , m_documentLoader(documentLoader)
71     , m_identifierForLoadWithoutResourceLoader(0)
72 {
73 }
74
75 MainResourceLoader::~MainResourceLoader()
76 {
77     clearResource();
78 }
79
80 PassRefPtr<MainResourceLoader> MainResourceLoader::create(DocumentLoader* documentLoader)
81 {
82     return adoptRef(new MainResourceLoader(documentLoader));
83 }
84
85 void MainResourceLoader::receivedError(const ResourceError& error)
86 {
87     // Calling receivedMainResourceError will likely result in the last reference to this object to go away.
88     RefPtr<MainResourceLoader> protect(this);
89     RefPtr<Frame> protectFrame(m_documentLoader->frame());
90
91     if (m_identifierForLoadWithoutResourceLoader) {
92         ASSERT(!loader());
93         frameLoader()->client()->dispatchDidFailLoading(documentLoader(), m_identifierForLoadWithoutResourceLoader, error);
94     }
95
96     // It is important that we call DocumentLoader::mainReceivedError before calling 
97     // ResourceLoadNotifier::didFailToLoad because mainReceivedError clears out the relevant
98     // document loaders. Also, mainReceivedError ends up calling a FrameLoadDelegate method
99     // and didFailToLoad calls a ResourceLoadDelegate method and they need to be in the correct order.
100     documentLoader()->mainReceivedError(error);
101 }
102
103 void MainResourceLoader::cancel()
104 {
105     cancel(ResourceError());
106 }
107
108 void MainResourceLoader::cancel(const ResourceError& error)
109 {
110     RefPtr<MainResourceLoader> protect(this);
111     ResourceError resourceError = error.isNull() ? frameLoader()->cancelledError(request()) : error;
112
113     m_dataLoadTimer.stop();
114     if (loader())
115         loader()->cancel(resourceError);
116
117     clearResource();
118     receivedError(resourceError);
119 }
120
121 void MainResourceLoader::clearResource()
122 {
123     if (m_resource) {
124         m_resource->removeClient(this);
125         m_resource = 0;
126     }
127 }
128
129 FrameLoader* MainResourceLoader::frameLoader() const
130 {
131     return m_documentLoader->frameLoader();
132 }
133
134 const ResourceRequest& MainResourceLoader::request() const
135 {
136     return m_resource ? m_resource->resourceRequest() : m_initialRequest;
137 }
138
139 PassRefPtr<ResourceBuffer> MainResourceLoader::resourceData()
140 {
141     if (m_resource)
142         return m_resource->resourceBuffer();
143     return 0;
144 }
145
146 void MainResourceLoader::redirectReceived(CachedResource* resource, ResourceRequest& request, const ResourceResponse& redirectResponse)
147 {
148     ASSERT_UNUSED(resource, resource == m_resource);
149     m_documentLoader->willSendRequest(request, redirectResponse);
150 }
151
152 void MainResourceLoader::responseReceived(CachedResource* resource, const ResourceResponse& r)
153 {
154     ASSERT_UNUSED(resource, m_resource == resource);
155     m_documentLoader->responseReceived(r);
156 }
157
158 void MainResourceLoader::dataReceived(CachedResource* resource, const char* data, int length)
159 {
160     ASSERT_UNUSED(resource, resource == m_resource);
161     documentLoader()->receivedData(data, length);
162 }
163
164 void MainResourceLoader::notifyFinished(CachedResource* resource)
165 {
166     ASSERT_UNUSED(resource, m_resource == resource);
167     ASSERT(m_resource);
168     if (!m_resource->errorOccurred() && !m_resource->wasCanceled()) {
169         documentLoader()->finishedLoading(m_resource->loadFinishTime());
170         return;
171     }
172
173     // FIXME: we should fix the design to eliminate the need for a platform ifdef here
174 #if !PLATFORM(CHROMIUM)
175     if (m_documentLoader->request().cachePolicy() == ReturnCacheDataDontLoad && !m_resource->wasCanceled()) {
176         frameLoader()->retryAfterFailedCacheOnlyMainResourceLoad();
177         return;
178     }
179 #endif
180
181     const ResourceError& error = m_resource->resourceError();
182     if (documentLoader()->applicationCacheHost()->maybeLoadFallbackForMainError(request(), error))
183         return;
184
185     // There is a bug in CFNetwork where callbacks can be dispatched even when loads are deferred.
186     // See <rdar://problem/6304600> for more details.
187 #if !USE(CF)
188     ASSERT(!defersLoading());
189 #endif
190     
191     receivedError(error);
192 }
193
194 void MainResourceLoader::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
195 {
196     MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::Loader);
197     info.addMember(m_resource, "resource");
198     info.addMember(m_initialRequest, "initialRequest");
199     info.addMember(m_dataLoadTimer, "dataLoadTimer");
200     info.addMember(m_documentLoader, "documentLoader");
201 }
202
203 void MainResourceLoader::handleSubstituteDataLoadNow(MainResourceLoaderTimer*)
204 {
205     RefPtr<MainResourceLoader> protect(this);
206
207     KURL url = m_documentLoader->substituteData().responseURL();
208     if (url.isEmpty())
209         url = m_initialRequest.url();
210
211     // Clear the initial request here so that subsequent entries into the
212     // loader will not think there's still a deferred load left to do.
213     m_initialRequest = ResourceRequest();
214         
215     ResourceResponse response(url, m_documentLoader->substituteData().mimeType(), m_documentLoader->substituteData().content()->size(), m_documentLoader->substituteData().textEncoding(), "");
216     responseReceived(0, response);
217 }
218
219 void MainResourceLoader::startDataLoadTimer()
220 {
221     m_dataLoadTimer.startOneShot(0);
222
223 #if HAVE(RUNLOOP_TIMER)
224     if (SchedulePairHashSet* scheduledPairs = m_documentLoader->frame()->page()->scheduledRunLoopPairs())
225         m_dataLoadTimer.schedule(*scheduledPairs);
226 #endif
227 }
228
229 void MainResourceLoader::handleSubstituteDataLoadSoon(const ResourceRequest& r)
230 {
231     m_initialRequest = r;
232     
233     if (m_documentLoader->deferMainResourceDataLoad())
234         startDataLoadTimer();
235     else
236         handleSubstituteDataLoadNow(0);
237 }
238
239 void MainResourceLoader::load(const ResourceRequest& initialRequest)
240 {
241     RefPtr<MainResourceLoader> protect(this);
242     ResourceRequest request(initialRequest);
243
244     if (m_documentLoader->substituteData().isValid()) {
245         m_identifierForLoadWithoutResourceLoader = m_documentLoader->frame()->page()->progress()->createUniqueIdentifier();
246         frameLoader()->notifier()->assignIdentifierToInitialRequest(m_identifierForLoadWithoutResourceLoader, documentLoader(), request);
247         frameLoader()->notifier()->dispatchWillSendRequest(documentLoader(), m_identifierForLoadWithoutResourceLoader, request, ResourceResponse());
248         handleSubstituteDataLoadSoon(request);
249         return;
250     }
251
252     DEFINE_STATIC_LOCAL(ResourceLoaderOptions, mainResourceLoadOptions,
253         (SendCallbacks, SniffContent, BufferData, AllowStoredCredentials, AskClientForCrossOriginCredentials, SkipSecurityCheck));
254     CachedResourceRequest cachedResourceRequest(request, mainResourceLoadOptions);
255     m_resource = documentLoader()->cachedResourceLoader()->requestMainResource(cachedResourceRequest);
256     if (!m_resource) {
257         documentLoader()->setRequest(ResourceRequest());
258         return;
259     }
260     if (!loader()) {
261         m_identifierForLoadWithoutResourceLoader = m_documentLoader->frame()->page()->progress()->createUniqueIdentifier();
262         frameLoader()->notifier()->assignIdentifierToInitialRequest(m_identifierForLoadWithoutResourceLoader, documentLoader(), request);
263         frameLoader()->notifier()->dispatchWillSendRequest(documentLoader(), m_identifierForLoadWithoutResourceLoader, request, ResourceResponse());
264     }
265     m_resource->addClient(this);
266
267     // A bunch of headers are set when the underlying ResourceLoader is created, and DocumentLoader::m_request needs to include those.
268     if (loader())
269         request = loader()->originalRequest();
270     // If there was a fragment identifier on initialRequest, the cache will have stripped it. DocumentLoader::m_request should include
271     // the fragment identifier, so add that back in.
272     if (equalIgnoringFragmentIdentifier(initialRequest.url(), request.url()))
273         request.setURL(initialRequest.url());
274     documentLoader()->setRequest(request);
275 }
276
277 void MainResourceLoader::setDefersLoading(bool defers)
278 {
279     if (loader())
280         loader()->setDefersLoading(defers);
281 }
282
283 bool MainResourceLoader::defersLoading() const
284 {
285     return loader() ? loader()->defersLoading() : false;
286 }
287
288 void MainResourceLoader::setDataBufferingPolicy(DataBufferingPolicy dataBufferingPolicy)
289 {
290     if (m_resource)
291         m_resource->setDataBufferingPolicy(dataBufferingPolicy);
292 }
293
294 ResourceLoader* MainResourceLoader::loader() const
295
296     return m_resource ? m_resource->loader() : 0;
297 }
298
299 unsigned long MainResourceLoader::identifier() const
300 {
301     ASSERT(!m_identifierForLoadWithoutResourceLoader || !loader() || !loader()->identifier());
302     if (m_identifierForLoadWithoutResourceLoader)
303         return m_identifierForLoadWithoutResourceLoader;
304     if (ResourceLoader* resourceLoader = loader())
305         return resourceLoader->identifier();
306     return 0;
307 }
308
309 }