• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006, 2007, 2008 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 "DocumentLoader.h"
31 
32 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
33 #include "ApplicationCache.h"
34 #include "ApplicationCacheGroup.h"
35 #include "ApplicationCacheResource.h"
36 #endif
37 #if ENABLE(ARCHIVE) // ANDROID extension: disabled to reduce code size
38 #include "ArchiveFactory.h"
39 #include "ArchiveResourceCollection.h"
40 #else
41 #include "SubstituteResource.h"
42 #endif
43 #include "CachedPage.h"
44 #include "DocLoader.h"
45 #include "Document.h"
46 #include "Event.h"
47 #include "Frame.h"
48 #include "FrameLoader.h"
49 #include "FrameTree.h"
50 #include "HistoryItem.h"
51 #include "Logging.h"
52 #include "MainResourceLoader.h"
53 #include "Page.h"
54 #include "PlatformString.h"
55 #include "Settings.h"
56 #include "SharedBuffer.h"
57 #include "StringBuffer.h"
58 #include "XMLTokenizer.h"
59 
60 #include <wtf/Assertions.h>
61 #include <wtf/unicode/Unicode.h>
62 
63 namespace WebCore {
64 
65 /*
66  * Performs four operations:
67  *  1. Convert backslashes to currency symbols
68  *  2. Convert control characters to spaces
69  *  3. Trim leading and trailing spaces
70  *  4. Collapse internal whitespace.
71  */
canonicalizedTitle(const String & title,Frame * frame)72 static inline String canonicalizedTitle(const String& title, Frame* frame)
73 {
74     ASSERT(!title.isEmpty());
75 
76     const UChar* characters = title.characters();
77     unsigned length = title.length();
78     unsigned i;
79 
80     StringBuffer buffer(length);
81     unsigned builderIndex = 0;
82 
83     // Skip leading spaces and leading characters that would convert to spaces
84     for (i = 0; i < length; ++i) {
85         UChar c = characters[i];
86         if (!(c <= 0x20 || c == 0x7F))
87             break;
88     }
89 
90     if (i == length)
91         return "";
92 
93     // Replace control characters with spaces, and backslashes with currency symbols, and collapse whitespace.
94     bool previousCharWasWS = false;
95     for (; i < length; ++i) {
96         UChar c = characters[i];
97         if (c <= 0x20 || c == 0x7F || (WTF::Unicode::category(c) & (WTF::Unicode::Separator_Line | WTF::Unicode::Separator_Paragraph))) {
98             if (previousCharWasWS)
99                 continue;
100             buffer[builderIndex++] = ' ';
101             previousCharWasWS = true;
102         } else {
103             buffer[builderIndex++] = c;
104             previousCharWasWS = false;
105         }
106     }
107 
108     // Strip trailing spaces
109     while (builderIndex > 0) {
110         --builderIndex;
111         if (buffer[builderIndex] != ' ')
112             break;
113     }
114 
115     if (!builderIndex && buffer[builderIndex] == ' ')
116         return "";
117 
118     buffer.shrink(builderIndex + 1);
119 
120     // Replace the backslashes with currency symbols if the encoding requires it.
121     if (frame->document())
122         frame->document()->displayBufferModifiedByEncoding(buffer.characters(), buffer.length());
123 
124     return String::adopt(buffer);
125 }
126 
cancelAll(const ResourceLoaderSet & loaders)127 static void cancelAll(const ResourceLoaderSet& loaders)
128 {
129     const ResourceLoaderSet copy = loaders;
130     ResourceLoaderSet::const_iterator end = copy.end();
131     for (ResourceLoaderSet::const_iterator it = copy.begin(); it != end; ++it)
132         (*it)->cancel();
133 }
134 
setAllDefersLoading(const ResourceLoaderSet & loaders,bool defers)135 static void setAllDefersLoading(const ResourceLoaderSet& loaders, bool defers)
136 {
137     const ResourceLoaderSet copy = loaders;
138     ResourceLoaderSet::const_iterator end = copy.end();
139     for (ResourceLoaderSet::const_iterator it = copy.begin(); it != end; ++it)
140         (*it)->setDefersLoading(defers);
141 }
142 
DocumentLoader(const ResourceRequest & req,const SubstituteData & substituteData)143 DocumentLoader::DocumentLoader(const ResourceRequest& req, const SubstituteData& substituteData)
144     : m_deferMainResourceDataLoad(true)
145     , m_frame(0)
146     , m_originalRequest(req)
147     , m_substituteData(substituteData)
148     , m_originalRequestCopy(req)
149     , m_request(req)
150     , m_committed(false)
151     , m_isStopping(false)
152     , m_loading(false)
153     , m_gotFirstByte(false)
154     , m_primaryLoadComplete(false)
155     , m_isClientRedirect(false)
156     , m_loadingFromCachedPage(false)
157     , m_stopRecordingResponses(false)
158     , m_substituteResourceDeliveryTimer(this, &DocumentLoader::substituteResourceDeliveryTimerFired)
159     , m_urlForHistoryReflectsClientRedirect(false)
160 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
161     , m_candidateApplicationCacheGroup(0)
162 #endif
163 {
164 }
165 
frameLoader() const166 FrameLoader* DocumentLoader::frameLoader() const
167 {
168     if (!m_frame)
169         return 0;
170     return m_frame->loader();
171 }
172 
~DocumentLoader()173 DocumentLoader::~DocumentLoader()
174 {
175     ASSERT(!m_frame || frameLoader()->activeDocumentLoader() != this || !frameLoader()->isLoading());
176 
177 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
178     if (m_applicationCache)
179         m_applicationCache->group()->disassociateDocumentLoader(this);
180     else if (m_candidateApplicationCacheGroup)
181         m_candidateApplicationCacheGroup->disassociateDocumentLoader(this);
182 #endif
183 }
184 
mainResourceData() const185 PassRefPtr<SharedBuffer> DocumentLoader::mainResourceData() const
186 {
187     if (m_mainResourceData)
188         return m_mainResourceData;
189     if (m_mainResourceLoader)
190         return m_mainResourceLoader->resourceData();
191     return 0;
192 }
193 
originalRequest() const194 const ResourceRequest& DocumentLoader::originalRequest() const
195 {
196     return m_originalRequest;
197 }
198 
originalRequestCopy() const199 const ResourceRequest& DocumentLoader::originalRequestCopy() const
200 {
201     return m_originalRequestCopy;
202 }
203 
request() const204 const ResourceRequest& DocumentLoader::request() const
205 {
206     return m_request;
207 }
208 
request()209 ResourceRequest& DocumentLoader::request()
210 {
211     return m_request;
212 }
213 
url() const214 const KURL& DocumentLoader::url() const
215 {
216     return request().url();
217 }
218 
replaceRequestURLForAnchorScroll(const KURL & url)219 void DocumentLoader::replaceRequestURLForAnchorScroll(const KURL& url)
220 {
221     m_originalRequestCopy.setURL(url);
222     m_request.setURL(url);
223 }
224 
setRequest(const ResourceRequest & req)225 void DocumentLoader::setRequest(const ResourceRequest& req)
226 {
227     // Replacing an unreachable URL with alternate content looks like a server-side
228     // redirect at this point, but we can replace a committed dataSource.
229     bool handlingUnreachableURL = false;
230 
231     handlingUnreachableURL = m_substituteData.isValid() && !m_substituteData.failingURL().isEmpty();
232 
233     if (handlingUnreachableURL)
234         m_committed = false;
235 
236     // We should never be getting a redirect callback after the data
237     // source is committed, except in the unreachable URL case. It
238     // would be a WebFoundation bug if it sent a redirect callback after commit.
239     ASSERT(!m_committed);
240 
241     KURL oldURL = m_request.url();
242     m_request = req;
243 
244     // Only send webView:didReceiveServerRedirectForProvisionalLoadForFrame: if URL changed.
245     // Also, don't send it when replacing unreachable URLs with alternate content.
246     if (!handlingUnreachableURL && oldURL != req.url())
247         frameLoader()->didReceiveServerRedirectForProvisionalLoadForFrame();
248 }
249 
setMainDocumentError(const ResourceError & error)250 void DocumentLoader::setMainDocumentError(const ResourceError& error)
251 {
252     m_mainDocumentError = error;
253     frameLoader()->setMainDocumentError(this, error);
254  }
255 
clearErrors()256 void DocumentLoader::clearErrors()
257 {
258     m_mainDocumentError = ResourceError();
259 }
260 
mainReceivedError(const ResourceError & error,bool isComplete)261 void DocumentLoader::mainReceivedError(const ResourceError& error, bool isComplete)
262 {
263     ASSERT(!error.isNull());
264 
265 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
266     ApplicationCacheGroup* group = m_candidateApplicationCacheGroup;
267     if (!group && m_applicationCache) {
268         ASSERT(!mainResourceApplicationCache()); // If the main resource were loaded from a cache, it wouldn't fail.
269         group = m_applicationCache->group();
270     }
271 
272     if (group)
273         group->failedLoadingMainResource(this);
274 #endif
275 
276     if (!frameLoader())
277         return;
278     setMainDocumentError(error);
279     if (isComplete)
280         frameLoader()->mainReceivedCompleteError(this, error);
281 }
282 
283 // Cancels the data source's pending loads.  Conceptually, a data source only loads
284 // one document at a time, but one document may have many related resources.
285 // stopLoading will stop all loads initiated by the data source,
286 // but not loads initiated by child frames' data sources -- that's the WebFrame's job.
stopLoading()287 void DocumentLoader::stopLoading()
288 {
289     // In some rare cases, calling FrameLoader::stopLoading could set m_loading to false.
290     // (This can happen when there's a single XMLHttpRequest currently loading and stopLoading causes it
291     // to stop loading. Because of this, we need to save it so we don't return early.
292     bool loading = m_loading;
293 
294     if (m_committed) {
295         // Attempt to stop the frame if the document loader is loading, or if it is done loading but
296         // still  parsing. Failure to do so can cause a world leak.
297         Document* doc = m_frame->document();
298 
299         if (loading || (doc && doc->parsing()))
300             m_frame->loader()->stopLoading(false);
301     }
302 
303     // Always cancel multipart loaders
304     cancelAll(m_multipartSubresourceLoaders);
305 
306     if (!loading)
307         return;
308 
309     RefPtr<Frame> protectFrame(m_frame);
310     RefPtr<DocumentLoader> protectLoader(this);
311 
312     m_isStopping = true;
313 
314     FrameLoader* frameLoader = DocumentLoader::frameLoader();
315 
316     if (m_mainResourceLoader)
317         // Stop the main resource loader and let it send the cancelled message.
318         m_mainResourceLoader->cancel();
319     else if (!m_subresourceLoaders.isEmpty())
320         // The main resource loader already finished loading. Set the cancelled error on the
321         // document and let the subresourceLoaders send individual cancelled messages below.
322         setMainDocumentError(frameLoader->cancelledError(m_request));
323     else
324         // If there are no resource loaders, we need to manufacture a cancelled message.
325         // (A back/forward navigation has no resource loaders because its resources are cached.)
326         mainReceivedError(frameLoader->cancelledError(m_request), true);
327 
328     stopLoadingSubresources();
329     stopLoadingPlugIns();
330 
331     m_isStopping = false;
332 }
333 
setupForReplace()334 void DocumentLoader::setupForReplace()
335 {
336     frameLoader()->setupForReplace();
337     m_committed = false;
338 }
339 
commitIfReady()340 void DocumentLoader::commitIfReady()
341 {
342     if (m_gotFirstByte && !m_committed) {
343         m_committed = true;
344         frameLoader()->commitProvisionalLoad(0);
345     }
346 }
347 
finishedLoading()348 void DocumentLoader::finishedLoading()
349 {
350     m_gotFirstByte = true;
351     commitIfReady();
352     if (FrameLoader* loader = frameLoader()) {
353         loader->finishedLoadingDocument(this);
354         loader->end();
355     }
356 }
357 
commitLoad(const char * data,int length)358 void DocumentLoader::commitLoad(const char* data, int length)
359 {
360     // Both unloading the old page and parsing the new page may execute JavaScript which destroys the datasource
361     // by starting a new load, so retain temporarily.
362     RefPtr<DocumentLoader> protect(this);
363 
364     commitIfReady();
365     if (FrameLoader* frameLoader = DocumentLoader::frameLoader())
366         frameLoader->committedLoad(this, data, length);
367 }
368 
doesProgressiveLoad(const String & MIMEType) const369 bool DocumentLoader::doesProgressiveLoad(const String& MIMEType) const
370 {
371     return !frameLoader()->isReplacing() || MIMEType == "text/html";
372 }
373 
receivedData(const char * data,int length)374 void DocumentLoader::receivedData(const char* data, int length)
375 {
376     m_gotFirstByte = true;
377     if (doesProgressiveLoad(m_response.mimeType()))
378         commitLoad(data, length);
379 }
380 
setupForReplaceByMIMEType(const String & newMIMEType)381 void DocumentLoader::setupForReplaceByMIMEType(const String& newMIMEType)
382 {
383     if (!m_gotFirstByte)
384         return;
385 
386     String oldMIMEType = m_response.mimeType();
387 
388     if (!doesProgressiveLoad(oldMIMEType)) {
389         frameLoader()->revertToProvisional(this);
390         setupForReplace();
391         RefPtr<SharedBuffer> resourceData = mainResourceData();
392         commitLoad(resourceData->data(), resourceData->size());
393     }
394 
395     frameLoader()->finishedLoadingDocument(this);
396     m_frame->loader()->end();
397 
398     frameLoader()->setReplacing();
399     m_gotFirstByte = false;
400 
401     if (doesProgressiveLoad(newMIMEType)) {
402         frameLoader()->revertToProvisional(this);
403         setupForReplace();
404     }
405 
406     stopLoadingSubresources();
407     stopLoadingPlugIns();
408 #if ENABLE(ARCHIVE) // ANDROID extension: disabled to reduce code size
409     clearArchiveResources();
410 #endif
411 }
412 
updateLoading()413 void DocumentLoader::updateLoading()
414 {
415     ASSERT(this == frameLoader()->activeDocumentLoader());
416     setLoading(frameLoader()->isLoading());
417 }
418 
setFrame(Frame * frame)419 void DocumentLoader::setFrame(Frame* frame)
420 {
421     if (m_frame == frame)
422         return;
423     ASSERT(frame && !m_frame);
424     m_frame = frame;
425     attachToFrame();
426 }
427 
attachToFrame()428 void DocumentLoader::attachToFrame()
429 {
430     ASSERT(m_frame);
431 }
432 
detachFromFrame()433 void DocumentLoader::detachFromFrame()
434 {
435     ASSERT(m_frame);
436     m_frame = 0;
437 }
438 
prepareForLoadStart()439 void DocumentLoader::prepareForLoadStart()
440 {
441     ASSERT(!m_isStopping);
442     setPrimaryLoadComplete(false);
443     ASSERT(frameLoader());
444     clearErrors();
445 
446     setLoading(true);
447 
448     frameLoader()->prepareForLoadStart();
449 }
450 
setPrimaryLoadComplete(bool flag)451 void DocumentLoader::setPrimaryLoadComplete(bool flag)
452 {
453     m_primaryLoadComplete = flag;
454     if (flag) {
455         if (m_mainResourceLoader) {
456             m_mainResourceData = m_mainResourceLoader->resourceData();
457 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
458             m_mainResourceApplicationCache = m_mainResourceLoader->applicationCache();
459 #endif
460             m_mainResourceLoader = 0;
461         }
462 
463         if (this == frameLoader()->activeDocumentLoader())
464             updateLoading();
465     }
466 }
467 
isLoadingInAPISense() const468 bool DocumentLoader::isLoadingInAPISense() const
469 {
470     // Once a frame has loaded, we no longer need to consider subresources,
471     // but we still need to consider subframes.
472     if (frameLoader()->state() != FrameStateComplete) {
473         if (!m_primaryLoadComplete && isLoading())
474             return true;
475         if (!m_subresourceLoaders.isEmpty())
476             return true;
477         if (Document* doc = m_frame->document()) {
478             if (doc->docLoader()->requestCount())
479                 return true;
480             if (Tokenizer* tok = doc->tokenizer())
481                 if (tok->processingData())
482                     return true;
483         }
484     }
485     return frameLoader()->subframeIsLoading();
486 }
487 
488 #if ENABLE(ARCHIVE) // ANDROID extension: disabled to reduce code size
addAllArchiveResources(Archive * archive)489 void DocumentLoader::addAllArchiveResources(Archive* archive)
490 {
491     if (!m_archiveResourceCollection)
492         m_archiveResourceCollection.set(new ArchiveResourceCollection);
493 
494     ASSERT(archive);
495     if (!archive)
496         return;
497 
498     m_archiveResourceCollection->addAllResources(archive);
499 }
500 
501 // FIXME: Adding a resource directly to a DocumentLoader/ArchiveResourceCollection seems like bad design, but is API some apps rely on.
502 // Can we change the design in a manner that will let us deprecate that API without reducing functionality of those apps?
addArchiveResource(PassRefPtr<ArchiveResource> resource)503 void DocumentLoader::addArchiveResource(PassRefPtr<ArchiveResource> resource)
504 {
505     if (!m_archiveResourceCollection)
506         m_archiveResourceCollection.set(new ArchiveResourceCollection);
507 
508     ASSERT(resource);
509     if (!resource)
510         return;
511 
512     m_archiveResourceCollection->addResource(resource);
513 }
514 
archiveResourceForURL(const KURL & url) const515 ArchiveResource* DocumentLoader::archiveResourceForURL(const KURL& url) const
516 {
517     if (!m_archiveResourceCollection)
518         return 0;
519 
520     ArchiveResource* resource = m_archiveResourceCollection->archiveResourceForURL(url);
521 
522     return resource && !resource->shouldIgnoreWhenUnarchiving() ? resource : 0;
523 }
524 
popArchiveForSubframe(const String & frameName)525 PassRefPtr<Archive> DocumentLoader::popArchiveForSubframe(const String& frameName)
526 {
527     return m_archiveResourceCollection ? m_archiveResourceCollection->popSubframeArchive(frameName) : 0;
528 }
529 
clearArchiveResources()530 void DocumentLoader::clearArchiveResources()
531 {
532     m_archiveResourceCollection.clear();
533     m_substituteResourceDeliveryTimer.stop();
534 }
535 
setParsedArchiveData(PassRefPtr<SharedBuffer> data)536 void DocumentLoader::setParsedArchiveData(PassRefPtr<SharedBuffer> data)
537 {
538     m_parsedArchiveData = data;
539 }
540 
parsedArchiveData() const541 SharedBuffer* DocumentLoader::parsedArchiveData() const
542 {
543     return m_parsedArchiveData.get();
544 }
545 
mainResource() const546 PassRefPtr<ArchiveResource> DocumentLoader::mainResource() const
547 {
548     const ResourceResponse& r = response();
549     RefPtr<SharedBuffer> mainResourceBuffer = mainResourceData();
550     if (!mainResourceBuffer)
551         mainResourceBuffer = SharedBuffer::create();
552 
553     return ArchiveResource::create(mainResourceBuffer, r.url(), r.mimeType(), r.textEncodingName(), frame()->tree()->name());
554 }
555 
subresource(const KURL & url) const556 PassRefPtr<ArchiveResource> DocumentLoader::subresource(const KURL& url) const
557 {
558     if (!isCommitted())
559         return 0;
560 
561     Document* doc = m_frame->document();
562     if (!doc)
563         return archiveResourceForURL(url);
564 
565     CachedResource* resource = doc->docLoader()->cachedResource(url);
566     if (!resource || resource->preloadResult() == CachedResource::PreloadReferenced)
567         return archiveResourceForURL(url);
568 
569     return ArchiveResource::create(resource->data(), url, resource->response());
570 }
571 
getSubresources(Vector<PassRefPtr<ArchiveResource>> & subresources) const572 void DocumentLoader::getSubresources(Vector<PassRefPtr<ArchiveResource> >& subresources) const
573 {
574     if (!isCommitted())
575         return;
576 
577     Document* document = m_frame->document();
578     if (!document)
579         return;
580 
581     const DocLoader::DocumentResourceMap& allResources = document->docLoader()->allCachedResources();
582     DocLoader::DocumentResourceMap::const_iterator end = allResources.end();
583     for (DocLoader::DocumentResourceMap::const_iterator it = allResources.begin(); it != end; ++it) {
584         RefPtr<ArchiveResource> subresource = this->subresource(KURL(it->second->url()));
585         if (subresource)
586             subresources.append(subresource.release());
587     }
588 
589     return;
590 }
591 #endif
592 
deliverSubstituteResourcesAfterDelay()593 void DocumentLoader::deliverSubstituteResourcesAfterDelay()
594 {
595     if (m_pendingSubstituteResources.isEmpty())
596         return;
597     ASSERT(m_frame && m_frame->page());
598     if (m_frame->page()->defersLoading())
599         return;
600     if (!m_substituteResourceDeliveryTimer.isActive())
601         m_substituteResourceDeliveryTimer.startOneShot(0);
602 }
603 
substituteResourceDeliveryTimerFired(Timer<DocumentLoader> *)604 void DocumentLoader::substituteResourceDeliveryTimerFired(Timer<DocumentLoader>*)
605 {
606     if (m_pendingSubstituteResources.isEmpty())
607         return;
608     ASSERT(m_frame && m_frame->page());
609     if (m_frame->page()->defersLoading())
610         return;
611 
612     SubstituteResourceMap copy;
613     copy.swap(m_pendingSubstituteResources);
614 
615     SubstituteResourceMap::const_iterator end = copy.end();
616     for (SubstituteResourceMap::const_iterator it = copy.begin(); it != end; ++it) {
617         RefPtr<ResourceLoader> loader = it->first;
618         SubstituteResource* resource = it->second.get();
619 
620         if (resource) {
621             SharedBuffer* data = resource->data();
622 
623             loader->didReceiveResponse(resource->response());
624             loader->didReceiveData(data->data(), data->size(), data->size(), true);
625             loader->didFinishLoading();
626         } else {
627             // A null resource means that we should fail the load.
628             // FIXME: Maybe we should use another error here - something like "not in cache".
629             loader->didFail(loader->cannotShowURLError());
630         }
631     }
632 }
633 
634 #ifndef NDEBUG
isSubstituteLoadPending(ResourceLoader * loader) const635 bool DocumentLoader::isSubstituteLoadPending(ResourceLoader* loader) const
636 {
637     return m_pendingSubstituteResources.contains(loader);
638 }
639 #endif
640 
cancelPendingSubstituteLoad(ResourceLoader * loader)641 void DocumentLoader::cancelPendingSubstituteLoad(ResourceLoader* loader)
642 {
643     if (m_pendingSubstituteResources.isEmpty())
644         return;
645     m_pendingSubstituteResources.remove(loader);
646     if (m_pendingSubstituteResources.isEmpty())
647         m_substituteResourceDeliveryTimer.stop();
648 }
649 
650 #if ENABLE(ARCHIVE) // ANDROID extension: disabled to reduce code size
scheduleArchiveLoad(ResourceLoader * loader,const ResourceRequest & request,const KURL & originalURL)651 bool DocumentLoader::scheduleArchiveLoad(ResourceLoader* loader, const ResourceRequest& request, const KURL& originalURL)
652 {
653     ArchiveResource* resource = 0;
654 
655     if (request.url() == originalURL)
656         resource = archiveResourceForURL(originalURL);
657 
658     if (!resource) {
659         // WebArchiveDebugMode means we fail loads instead of trying to fetch them from the network if they're not in the archive.
660         bool shouldFailLoad = m_frame->settings()->webArchiveDebugModeEnabled() && ArchiveFactory::isArchiveMimeType(responseMIMEType());
661 
662         if (!shouldFailLoad)
663             return false;
664     }
665 
666     m_pendingSubstituteResources.set(loader, resource);
667     deliverSubstituteResourcesAfterDelay();
668 
669     return true;
670 }
671 #endif
672 
addResponse(const ResourceResponse & r)673 void DocumentLoader::addResponse(const ResourceResponse& r)
674 {
675     if (!m_stopRecordingResponses)
676         m_responses.append(r);
677 }
678 
stopRecordingResponses()679 void DocumentLoader::stopRecordingResponses()
680 {
681     m_stopRecordingResponses = true;
682 }
683 
setTitle(const String & title)684 void DocumentLoader::setTitle(const String& title)
685 {
686     if (title.isEmpty())
687         return;
688 
689     String trimmed = canonicalizedTitle(title, m_frame);
690     if (!trimmed.isEmpty() && m_pageTitle != trimmed) {
691         frameLoader()->willChangeTitle(this);
692         m_pageTitle = trimmed;
693         frameLoader()->didChangeTitle(this);
694     }
695 }
696 
urlForHistory() const697 KURL DocumentLoader::urlForHistory() const
698 {
699     // Return the URL to be used for history and B/F list.
700     // Returns nil for WebDataProtocol URLs that aren't alternates
701     // for unreachable URLs, because these can't be stored in history.
702     if (m_substituteData.isValid())
703         return unreachableURL();
704 
705     return m_originalRequestCopy.url();
706 }
707 
urlForHistoryReflectsFailure() const708 bool DocumentLoader::urlForHistoryReflectsFailure() const
709 {
710     return m_substituteData.isValid() || m_response.httpStatusCode() >= 400;
711 }
712 
loadFromCachedPage(PassRefPtr<CachedPage> cachedPage)713 void DocumentLoader::loadFromCachedPage(PassRefPtr<CachedPage> cachedPage)
714 {
715     LOG(PageCache, "WebCorePageCache: DocumentLoader %p loading from cached page %p", this, cachedPage.get());
716 
717     prepareForLoadStart();
718     setLoadingFromCachedPage(true);
719     setCommitted(true);
720     frameLoader()->commitProvisionalLoad(cachedPage);
721 }
722 
originalURL() const723 const KURL& DocumentLoader::originalURL() const
724 {
725     return m_originalRequestCopy.url();
726 }
727 
requestURL() const728 const KURL& DocumentLoader::requestURL() const
729 {
730     return request().url();
731 }
732 
responseURL() const733 const KURL& DocumentLoader::responseURL() const
734 {
735     return m_response.url();
736 }
737 
responseMIMEType() const738 const String& DocumentLoader::responseMIMEType() const
739 {
740     return m_response.mimeType();
741 }
742 
unreachableURL() const743 const KURL& DocumentLoader::unreachableURL() const
744 {
745     return m_substituteData.failingURL();
746 }
747 
setDefersLoading(bool defers)748 void DocumentLoader::setDefersLoading(bool defers)
749 {
750     if (m_mainResourceLoader)
751         m_mainResourceLoader->setDefersLoading(defers);
752     setAllDefersLoading(m_subresourceLoaders, defers);
753     setAllDefersLoading(m_plugInStreamLoaders, defers);
754     if (!defers)
755         deliverSubstituteResourcesAfterDelay();
756 }
757 
stopLoadingPlugIns()758 void DocumentLoader::stopLoadingPlugIns()
759 {
760     cancelAll(m_plugInStreamLoaders);
761 }
762 
stopLoadingSubresources()763 void DocumentLoader::stopLoadingSubresources()
764 {
765     cancelAll(m_subresourceLoaders);
766 }
767 
addSubresourceLoader(ResourceLoader * loader)768 void DocumentLoader::addSubresourceLoader(ResourceLoader* loader)
769 {
770     m_subresourceLoaders.add(loader);
771     setLoading(true);
772 }
773 
removeSubresourceLoader(ResourceLoader * loader)774 void DocumentLoader::removeSubresourceLoader(ResourceLoader* loader)
775 {
776     m_subresourceLoaders.remove(loader);
777     updateLoading();
778     if (Frame* frame = m_frame)
779         frame->loader()->checkLoadComplete();
780 }
781 
addPlugInStreamLoader(ResourceLoader * loader)782 void DocumentLoader::addPlugInStreamLoader(ResourceLoader* loader)
783 {
784     m_plugInStreamLoaders.add(loader);
785     setLoading(true);
786 }
787 
removePlugInStreamLoader(ResourceLoader * loader)788 void DocumentLoader::removePlugInStreamLoader(ResourceLoader* loader)
789 {
790     m_plugInStreamLoaders.remove(loader);
791     updateLoading();
792 }
793 
isLoadingMainResource() const794 bool DocumentLoader::isLoadingMainResource() const
795 {
796     return !!m_mainResourceLoader;
797 }
798 
isLoadingSubresources() const799 bool DocumentLoader::isLoadingSubresources() const
800 {
801     return !m_subresourceLoaders.isEmpty();
802 }
803 
isLoadingPlugIns() const804 bool DocumentLoader::isLoadingPlugIns() const
805 {
806     return !m_plugInStreamLoaders.isEmpty();
807 }
808 
isLoadingMultipartContent() const809 bool DocumentLoader::isLoadingMultipartContent() const
810 {
811     return m_mainResourceLoader && m_mainResourceLoader->isLoadingMultipartContent();
812 }
813 
startLoadingMainResource(unsigned long identifier)814 bool DocumentLoader::startLoadingMainResource(unsigned long identifier)
815 {
816     ASSERT(!m_mainResourceLoader);
817     m_mainResourceLoader = MainResourceLoader::create(m_frame);
818     m_mainResourceLoader->setIdentifier(identifier);
819 
820     // FIXME: Is there any way the extra fields could have not been added by now?
821     // If not, it would be great to remove this line of code.
822     frameLoader()->addExtraFieldsToMainResourceRequest(m_request);
823 
824     if (!m_mainResourceLoader->load(m_request, m_substituteData)) {
825         // FIXME: If this should really be caught, we should just ASSERT this doesn't happen;
826         // should it be caught by other parts of WebKit or other parts of the app?
827         LOG_ERROR("could not create WebResourceHandle for URL %s -- should be caught by policy handler level", m_request.url().string().ascii().data());
828         m_mainResourceLoader = 0;
829         return false;
830     }
831 
832     return true;
833 }
834 
cancelMainResourceLoad(const ResourceError & error)835 void DocumentLoader::cancelMainResourceLoad(const ResourceError& error)
836 {
837     m_mainResourceLoader->cancel(error);
838 }
839 
subresourceLoaderFinishedLoadingOnePart(ResourceLoader * loader)840 void DocumentLoader::subresourceLoaderFinishedLoadingOnePart(ResourceLoader* loader)
841 {
842     m_multipartSubresourceLoaders.add(loader);
843     m_subresourceLoaders.remove(loader);
844     updateLoading();
845     if (Frame* frame = m_frame)
846         frame->loader()->checkLoadComplete();
847 }
848 
iconLoadDecisionAvailable()849 void DocumentLoader::iconLoadDecisionAvailable()
850 {
851     if (m_frame)
852         m_frame->loader()->iconLoadDecisionAvailable();
853 }
854 
855 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
setCandidateApplicationCacheGroup(ApplicationCacheGroup * group)856 void DocumentLoader::setCandidateApplicationCacheGroup(ApplicationCacheGroup* group)
857 {
858     ASSERT(!m_applicationCache);
859     m_candidateApplicationCacheGroup = group;
860 }
861 
setApplicationCache(PassRefPtr<ApplicationCache> applicationCache)862 void DocumentLoader::setApplicationCache(PassRefPtr<ApplicationCache> applicationCache)
863 {
864     if (m_candidateApplicationCacheGroup) {
865         ASSERT(!m_applicationCache);
866         m_candidateApplicationCacheGroup = 0;
867     }
868 
869     m_applicationCache = applicationCache;
870 }
871 
mainResourceApplicationCache() const872 ApplicationCache* DocumentLoader::mainResourceApplicationCache() const
873 {
874     if (m_mainResourceApplicationCache)
875         return m_mainResourceApplicationCache.get();
876     if (m_mainResourceLoader)
877         return m_mainResourceLoader->applicationCache();
878     return 0;
879 }
880 
shouldLoadResourceFromApplicationCache(const ResourceRequest & request,ApplicationCacheResource * & resource)881 bool DocumentLoader::shouldLoadResourceFromApplicationCache(const ResourceRequest& request, ApplicationCacheResource*& resource)
882 {
883     ApplicationCache* cache = applicationCache();
884     if (!cache || !cache->isComplete())
885         return false;
886 
887     // If the resource is not a HTTP/HTTPS GET, then abort
888     if (!ApplicationCache::requestIsHTTPOrHTTPSGet(request))
889         return false;
890 
891     // If the resource's URL is an master entry, the manifest, an explicit entry, a fallback entry, or a dynamic entry
892     // in the application cache, then get the resource from the cache (instead of fetching it).
893     resource = cache->resourceForURL(request.url());
894 
895     // Resources that match fallback namespaces or online whitelist entries are fetched from the network,
896     // unless they are also cached.
897     if (!resource && (cache->urlMatchesFallbackNamespace(request.url()) || cache->isURLInOnlineWhitelist(request.url())))
898         return false;
899 
900     // Resources that are not present in the manifest will always fail to load (at least, after the
901     // cache has been primed the first time), making the testing of offline applications simpler.
902     return true;
903 }
904 
getApplicationCacheFallbackResource(const ResourceRequest & request,ApplicationCacheResource * & resource,ApplicationCache * cache)905 bool DocumentLoader::getApplicationCacheFallbackResource(const ResourceRequest& request, ApplicationCacheResource*& resource, ApplicationCache* cache)
906 {
907     if (!cache) {
908         cache = applicationCache();
909         if (!cache)
910             return false;
911     }
912     if (!cache->isComplete())
913         return false;
914 
915     // If the resource is not a HTTP/HTTPS GET, then abort
916     if (!ApplicationCache::requestIsHTTPOrHTTPSGet(request))
917         return false;
918 
919     KURL fallbackURL;
920     if (!cache->urlMatchesFallbackNamespace(request.url(), &fallbackURL))
921         return false;
922 
923     resource = cache->resourceForURL(fallbackURL);
924     ASSERT(resource);
925 
926     return true;
927 }
928 
scheduleApplicationCacheLoad(ResourceLoader * loader,const ResourceRequest & request,const KURL & originalURL)929 bool DocumentLoader::scheduleApplicationCacheLoad(ResourceLoader* loader, const ResourceRequest& request, const KURL& originalURL)
930 {
931     if (!frameLoader()->frame()->settings() || !frameLoader()->frame()->settings()->offlineWebApplicationCacheEnabled())
932         return false;
933 
934     if (request.url() != originalURL)
935         return false;
936 
937     ApplicationCacheResource* resource;
938     if (!shouldLoadResourceFromApplicationCache(request, resource))
939         return false;
940 
941     m_pendingSubstituteResources.set(loader, resource);
942     deliverSubstituteResourcesAfterDelay();
943 
944     return true;
945 }
946 
scheduleLoadFallbackResourceFromApplicationCache(ResourceLoader * loader,const ResourceRequest & request,ApplicationCache * cache)947 bool DocumentLoader::scheduleLoadFallbackResourceFromApplicationCache(ResourceLoader* loader, const ResourceRequest& request, ApplicationCache* cache)
948 {
949     if (!frameLoader()->frame()->settings() || !frameLoader()->frame()->settings()->offlineWebApplicationCacheEnabled())
950         return false;
951 
952     ApplicationCacheResource* resource;
953     if (!getApplicationCacheFallbackResource(request, resource, cache))
954         return false;
955 
956     m_pendingSubstituteResources.set(loader, resource);
957     deliverSubstituteResourcesAfterDelay();
958 
959     return true;
960 }
961 
962 #endif // ENABLE(OFFLINE_WEB_APPLICATIONS)
963 
964 }
965