• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
3  * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
4  * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1.  Redistributions of source code must retain the above copyright
11  *     notice, this list of conditions and the following disclaimer.
12  * 2.  Redistributions in binary form must reproduce the above copyright
13  *     notice, this list of conditions and the following disclaimer in the
14  *     documentation and/or other materials provided with the distribution.
15  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
16  *     its contributors may be used to endorse or promote products derived
17  *     from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
20  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
23  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include "config.h"
32 #include "FrameLoader.h"
33 
34 #include "ApplicationCacheHost.h"
35 #if ENABLE(ARCHIVE) // ANDROID extension: disabled to reduce code size
36 #include "Archive.h"
37 #include "ArchiveFactory.h"
38 #endif
39 #include "CString.h"
40 #include "Cache.h"
41 #include "CachedPage.h"
42 #include "Chrome.h"
43 #include "DOMImplementation.h"
44 #include "DOMWindow.h"
45 #include "DocLoader.h"
46 #include "Document.h"
47 #include "DocumentLoader.h"
48 #include "Editor.h"
49 #include "EditorClient.h"
50 #include "Element.h"
51 #include "Event.h"
52 #include "EventNames.h"
53 #include "FloatRect.h"
54 #include "FormState.h"
55 #include "Frame.h"
56 #include "FrameLoadRequest.h"
57 #include "FrameLoaderClient.h"
58 #include "FrameTree.h"
59 #include "FrameView.h"
60 #include "HTMLAppletElement.h"
61 #include "HTMLFormElement.h"
62 #include "HTMLFrameElement.h"
63 #include "HTMLNames.h"
64 #include "HTMLObjectElement.h"
65 #include "HTTPParsers.h"
66 #include "HistoryItem.h"
67 #include "IconDatabase.h"
68 #include "IconLoader.h"
69 #include "InspectorController.h"
70 #include "Logging.h"
71 #include "MIMETypeRegistry.h"
72 #include "MainResourceLoader.h"
73 #include "Page.h"
74 #include "PageCache.h"
75 #include "PageGroup.h"
76 #include "PlaceholderDocument.h"
77 #include "PluginData.h"
78 #include "PluginDocument.h"
79 #include "ProgressTracker.h"
80 #include "RenderPart.h"
81 #include "RenderView.h"
82 #include "RenderWidget.h"
83 #include "ResourceHandle.h"
84 #include "ResourceRequest.h"
85 #include "ScriptController.h"
86 #include "ScriptSourceCode.h"
87 #include "ScriptString.h"
88 #include "ScriptValue.h"
89 #include "SecurityOrigin.h"
90 #include "SegmentedString.h"
91 #include "Settings.h"
92 #include "TextResourceDecoder.h"
93 #include "WindowFeatures.h"
94 #include "XMLHttpRequest.h"
95 #include "XMLTokenizer.h"
96 #include "XSSAuditor.h"
97 #include <wtf/CurrentTime.h>
98 #include <wtf/StdLibExtras.h>
99 
100 
101 #if ENABLE(SVG)
102 #include "SVGDocument.h"
103 #include "SVGLocatable.h"
104 #include "SVGNames.h"
105 #include "SVGPreserveAspectRatio.h"
106 #include "SVGSVGElement.h"
107 #include "SVGViewElement.h"
108 #include "SVGViewSpec.h"
109 #endif
110 
111 #ifdef ANDROID_INSTRUMENT
112 #include "TimeCounter.h"
113 #include "RenderArena.h"
114 #endif
115 
116 #if PLATFORM(ANDROID)
117 #include "WebCoreFrameBridge.h"
118 #endif
119 
120 namespace WebCore {
121 
122 #if ENABLE(SVG)
123 using namespace SVGNames;
124 #endif
125 using namespace HTMLNames;
126 
127 struct ScheduledRedirection {
128     enum Type { redirection, locationChange, historyNavigation, formSubmission };
129 
130     const Type type;
131     const double delay;
132     const String url;
133     const String referrer;
134     const FrameLoadRequest frameRequest;
135     const RefPtr<Event> event;
136     const RefPtr<FormState> formState;
137     const int historySteps;
138     const bool lockHistory;
139     const bool lockBackForwardList;
140     const bool wasUserGesture;
141     const bool wasRefresh;
142     const bool wasDuringLoad;
143 
ScheduledRedirectionWebCore::ScheduledRedirection144     ScheduledRedirection(double delay, const String& url, bool lockHistory, bool lockBackForwardList, bool wasUserGesture, bool refresh)
145         : type(redirection)
146         , delay(delay)
147         , url(url)
148         , historySteps(0)
149         , lockHistory(lockHistory)
150         , lockBackForwardList(lockBackForwardList)
151         , wasUserGesture(wasUserGesture)
152         , wasRefresh(refresh)
153         , wasDuringLoad(false)
154     {
155         ASSERT(!url.isEmpty());
156     }
157 
ScheduledRedirectionWebCore::ScheduledRedirection158     ScheduledRedirection(const String& url, const String& referrer, bool lockHistory, bool lockBackForwardList, bool wasUserGesture, bool refresh, bool duringLoad)
159         : type(locationChange)
160         , delay(0)
161         , url(url)
162         , referrer(referrer)
163         , historySteps(0)
164         , lockHistory(lockHistory)
165         , lockBackForwardList(lockBackForwardList)
166         , wasUserGesture(wasUserGesture)
167         , wasRefresh(refresh)
168         , wasDuringLoad(duringLoad)
169     {
170         ASSERT(!url.isEmpty());
171     }
172 
ScheduledRedirectionWebCore::ScheduledRedirection173     explicit ScheduledRedirection(int historyNavigationSteps)
174         : type(historyNavigation)
175         , delay(0)
176         , historySteps(historyNavigationSteps)
177         , lockHistory(false)
178         , lockBackForwardList(false)
179         , wasUserGesture(false)
180         , wasRefresh(false)
181         , wasDuringLoad(false)
182     {
183     }
184 
ScheduledRedirectionWebCore::ScheduledRedirection185     ScheduledRedirection(const FrameLoadRequest& frameRequest,
186             bool lockHistory, bool lockBackForwardList, PassRefPtr<Event> event, PassRefPtr<FormState> formState,
187             bool duringLoad)
188         : type(formSubmission)
189         , delay(0)
190         , frameRequest(frameRequest)
191         , event(event)
192         , formState(formState)
193         , historySteps(0)
194         , lockHistory(lockHistory)
195         , lockBackForwardList(lockBackForwardList)
196         , wasUserGesture(false)
197         , wasRefresh(false)
198         , wasDuringLoad(duringLoad)
199     {
200         ASSERT(!frameRequest.isEmpty());
201         ASSERT(this->formState);
202     }
203 };
204 
205 #if ENABLE(XHTMLMP)
206 static const char defaultAcceptHeader[] = "application/xml,application/vnd.wap.xhtml+xml,application/xhtml+xml;profile='http://www.wapforum.org/xhtml',text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5";
207 #else
208 static const char defaultAcceptHeader[] = "application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5";
209 #endif
210 static double storedTimeOfLastCompletedLoad;
211 static FrameLoader::LocalLoadPolicy localLoadPolicy = FrameLoader::AllowLocalLoadsForLocalOnly;
212 
isBackForwardLoadType(FrameLoadType type)213 bool isBackForwardLoadType(FrameLoadType type)
214 {
215     switch (type) {
216         case FrameLoadTypeStandard:
217         case FrameLoadTypeReload:
218         case FrameLoadTypeReloadFromOrigin:
219         case FrameLoadTypeSame:
220         case FrameLoadTypeRedirectWithLockedBackForwardList:
221         case FrameLoadTypeReplace:
222             return false;
223         case FrameLoadTypeBack:
224         case FrameLoadTypeBackWMLDeckNotAccessible:
225         case FrameLoadTypeForward:
226         case FrameLoadTypeIndexedBackForward:
227             return true;
228     }
229     ASSERT_NOT_REACHED();
230     return false;
231 }
232 
numRequests(Document * document)233 static int numRequests(Document* document)
234 {
235     if (!document)
236         return 0;
237 
238     return document->docLoader()->requestCount();
239 }
240 
canReferToParentFrameEncoding(const Frame * frame,const Frame * parentFrame)241 static inline bool canReferToParentFrameEncoding(const Frame* frame, const Frame* parentFrame)
242 {
243     return parentFrame && parentFrame->document()->securityOrigin()->canAccess(frame->document()->securityOrigin());
244 }
245 
FrameLoader(Frame * frame,FrameLoaderClient * client)246 FrameLoader::FrameLoader(Frame* frame, FrameLoaderClient* client)
247     : m_frame(frame)
248     , m_client(client)
249     , m_state(FrameStateCommittedPage)
250     , m_loadType(FrameLoadTypeStandard)
251     , m_policyLoadType(FrameLoadTypeStandard)
252     , m_delegateIsHandlingProvisionalLoadError(false)
253     , m_delegateIsDecidingNavigationPolicy(false)
254     , m_delegateIsHandlingUnimplementablePolicy(false)
255     , m_firstLayoutDone(false)
256     , m_quickRedirectComing(false)
257     , m_sentRedirectNotification(false)
258     , m_inStopAllLoaders(false)
259     , m_isExecutingJavaScriptFormAction(false)
260     , m_isRunningScript(false)
261     , m_didCallImplicitClose(false)
262     , m_wasUnloadEventEmitted(false)
263     , m_unloadEventBeingDispatched(false)
264     , m_isComplete(false)
265     , m_isLoadingMainResource(false)
266     , m_cancellingWithLoadInProgress(false)
267     , m_needsClear(false)
268     , m_receivedData(false)
269     , m_encodingWasChosenByUser(false)
270     , m_containsPlugIns(false)
271     , m_redirectionTimer(this, &FrameLoader::redirectionTimerFired)
272     , m_checkCompletedTimer(this, &FrameLoader::checkCompletedTimerFired)
273     , m_checkLoadCompleteTimer(this, &FrameLoader::checkLoadCompleteTimerFired)
274     , m_opener(0)
275     , m_openedByDOM(false)
276     , m_creatingInitialEmptyDocument(false)
277     , m_isDisplayingInitialEmptyDocument(false)
278     , m_committedFirstRealDocumentLoad(false)
279     , m_didPerformFirstNavigation(false)
280 #ifndef NDEBUG
281     , m_didDispatchDidCommitLoad(false)
282 #endif
283 {
284 }
285 
~FrameLoader()286 FrameLoader::~FrameLoader()
287 {
288     setOpener(0);
289 
290     HashSet<Frame*>::iterator end = m_openedFrames.end();
291     for (HashSet<Frame*>::iterator it = m_openedFrames.begin(); it != end; ++it)
292         (*it)->loader()->m_opener = 0;
293 
294     m_client->frameLoaderDestroyed();
295 }
296 
init()297 void FrameLoader::init()
298 {
299     // this somewhat odd set of steps is needed to give the frame an initial empty document
300     m_isDisplayingInitialEmptyDocument = false;
301     m_creatingInitialEmptyDocument = true;
302     setPolicyDocumentLoader(m_client->createDocumentLoader(ResourceRequest(KURL("")), SubstituteData()).get());
303     setProvisionalDocumentLoader(m_policyDocumentLoader.get());
304     setState(FrameStateProvisional);
305     m_provisionalDocumentLoader->setResponse(ResourceResponse(KURL(), "text/html", 0, String(), String()));
306     m_provisionalDocumentLoader->finishedLoading();
307     begin(KURL(), false);
308     end();
309     m_frame->document()->cancelParsing();
310     m_creatingInitialEmptyDocument = false;
311     m_didCallImplicitClose = true;
312 }
313 
setDefersLoading(bool defers)314 void FrameLoader::setDefersLoading(bool defers)
315 {
316     if (m_documentLoader)
317         m_documentLoader->setDefersLoading(defers);
318     if (m_provisionalDocumentLoader)
319         m_provisionalDocumentLoader->setDefersLoading(defers);
320     if (m_policyDocumentLoader)
321         m_policyDocumentLoader->setDefersLoading(defers);
322 }
323 
createWindow(FrameLoader * frameLoaderForFrameLookup,const FrameLoadRequest & request,const WindowFeatures & features,bool & created)324 Frame* FrameLoader::createWindow(FrameLoader* frameLoaderForFrameLookup, const FrameLoadRequest& request, const WindowFeatures& features, bool& created)
325 {
326     ASSERT(!features.dialog || request.frameName().isEmpty());
327 
328     if (!request.frameName().isEmpty() && request.frameName() != "_blank") {
329         Frame* frame = frameLoaderForFrameLookup->frame()->tree()->find(request.frameName());
330         if (frame && shouldAllowNavigation(frame)) {
331             if (!request.resourceRequest().url().isEmpty())
332                 frame->loader()->loadFrameRequest(request, false, false, 0, 0);
333             if (Page* page = frame->page())
334                 page->chrome()->focus();
335             created = false;
336             return frame;
337         }
338     }
339 
340     // FIXME: Setting the referrer should be the caller's responsibility.
341     FrameLoadRequest requestWithReferrer = request;
342     requestWithReferrer.resourceRequest().setHTTPReferrer(m_outgoingReferrer);
343     addHTTPOriginIfNeeded(requestWithReferrer.resourceRequest(), outgoingOrigin());
344 
345     Page* oldPage = m_frame->page();
346     if (!oldPage)
347         return 0;
348 
349     Page* page = oldPage->chrome()->createWindow(m_frame, requestWithReferrer, features);
350     if (!page)
351         return 0;
352 
353     Frame* frame = page->mainFrame();
354     if (request.frameName() != "_blank")
355         frame->tree()->setName(request.frameName());
356 
357     page->chrome()->setToolbarsVisible(features.toolBarVisible || features.locationBarVisible);
358     page->chrome()->setStatusbarVisible(features.statusBarVisible);
359     page->chrome()->setScrollbarsVisible(features.scrollbarsVisible);
360     page->chrome()->setMenubarVisible(features.menuBarVisible);
361     page->chrome()->setResizable(features.resizable);
362 
363     // 'x' and 'y' specify the location of the window, while 'width' and 'height'
364     // specify the size of the page. We can only resize the window, so
365     // adjust for the difference between the window size and the page size.
366 
367     FloatRect windowRect = page->chrome()->windowRect();
368     FloatSize pageSize = page->chrome()->pageRect().size();
369     if (features.xSet)
370         windowRect.setX(features.x);
371     if (features.ySet)
372         windowRect.setY(features.y);
373     if (features.widthSet)
374         windowRect.setWidth(features.width + (windowRect.width() - pageSize.width()));
375     if (features.heightSet)
376         windowRect.setHeight(features.height + (windowRect.height() - pageSize.height()));
377     page->chrome()->setWindowRect(windowRect);
378 
379     page->chrome()->show();
380 
381     created = true;
382     return frame;
383 }
384 
canHandleRequest(const ResourceRequest & request)385 bool FrameLoader::canHandleRequest(const ResourceRequest& request)
386 {
387     return m_client->canHandleRequest(request);
388 }
389 
changeLocation(const KURL & url,const String & referrer,bool lockHistory,bool lockBackForwardList,bool userGesture,bool refresh)390 void FrameLoader::changeLocation(const KURL& url, const String& referrer, bool lockHistory, bool lockBackForwardList, bool userGesture, bool refresh)
391 {
392     RefPtr<Frame> protect(m_frame);
393 
394     ResourceRequest request(url, referrer, refresh ? ReloadIgnoringCacheData : UseProtocolCachePolicy);
395 #ifdef ANDROID_USER_GESTURE
396     request.setUserGesture(userGesture);
397 #endif
398 
399     if (executeIfJavaScriptURL(request.url(), userGesture))
400         return;
401 
402     urlSelected(request, "_self", 0, lockHistory, lockBackForwardList, userGesture);
403 }
404 
urlSelected(const ResourceRequest & request,const String & passedTarget,PassRefPtr<Event> triggeringEvent,bool lockHistory,bool lockBackForwardList,bool userGesture)405 void FrameLoader::urlSelected(const ResourceRequest& request, const String& passedTarget, PassRefPtr<Event> triggeringEvent, bool lockHistory, bool lockBackForwardList, bool userGesture)
406 {
407     if (executeIfJavaScriptURL(request.url(), userGesture, false))
408         return;
409 
410     String target = passedTarget;
411     if (target.isEmpty())
412         target = m_frame->document()->baseTarget();
413 
414     FrameLoadRequest frameRequest(request, target);
415 
416     if (frameRequest.resourceRequest().httpReferrer().isEmpty())
417         frameRequest.resourceRequest().setHTTPReferrer(m_outgoingReferrer);
418     addHTTPOriginIfNeeded(frameRequest.resourceRequest(), outgoingOrigin());
419 
420     loadFrameRequest(frameRequest, lockHistory, lockBackForwardList, triggeringEvent, 0);
421 }
422 
requestFrame(HTMLFrameOwnerElement * ownerElement,const String & urlString,const AtomicString & frameName)423 bool FrameLoader::requestFrame(HTMLFrameOwnerElement* ownerElement, const String& urlString, const AtomicString& frameName)
424 {
425     // Support for <frame src="javascript:string">
426     KURL scriptURL;
427     KURL url;
428     if (protocolIsJavaScript(urlString)) {
429         scriptURL = completeURL(urlString); // completeURL() encodes the URL.
430         url = blankURL();
431     } else
432         url = completeURL(urlString);
433 
434     Frame* frame = ownerElement->contentFrame();
435     if (frame)
436         frame->loader()->scheduleLocationChange(url.string(), m_outgoingReferrer, true, true, isProcessingUserGesture());
437     else
438         frame = loadSubframe(ownerElement, url, frameName, m_outgoingReferrer);
439 
440     if (!frame)
441         return false;
442 
443     if (!scriptURL.isEmpty())
444         frame->loader()->executeIfJavaScriptURL(scriptURL);
445 
446     return true;
447 }
448 
loadSubframe(HTMLFrameOwnerElement * ownerElement,const KURL & url,const String & name,const String & referrer)449 Frame* FrameLoader::loadSubframe(HTMLFrameOwnerElement* ownerElement, const KURL& url, const String& name, const String& referrer)
450 {
451     bool allowsScrolling = true;
452     int marginWidth = -1;
453     int marginHeight = -1;
454     if (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag)) {
455         HTMLFrameElementBase* o = static_cast<HTMLFrameElementBase*>(ownerElement);
456         allowsScrolling = o->scrollingMode() != ScrollbarAlwaysOff;
457         marginWidth = o->getMarginWidth();
458         marginHeight = o->getMarginHeight();
459     }
460 
461     if (!canLoad(url, referrer)) {
462         FrameLoader::reportLocalLoadFailed(m_frame, url.string());
463         return 0;
464     }
465 
466     bool hideReferrer = shouldHideReferrer(url, referrer);
467     RefPtr<Frame> frame = m_client->createFrame(url, name, ownerElement, hideReferrer ? String() : referrer, allowsScrolling, marginWidth, marginHeight);
468 
469     if (!frame)  {
470         checkCallImplicitClose();
471         return 0;
472     }
473 
474     frame->loader()->m_isComplete = false;
475 
476     RenderObject* renderer = ownerElement->renderer();
477     FrameView* view = frame->view();
478     if (renderer && renderer->isWidget() && view)
479         toRenderWidget(renderer)->setWidget(view);
480 
481     checkCallImplicitClose();
482 
483     // In these cases, the synchronous load would have finished
484     // before we could connect the signals, so make sure to send the
485     // completed() signal for the child by hand
486     // FIXME: In this case the Frame will have finished loading before
487     // it's being added to the child list. It would be a good idea to
488     // create the child first, then invoke the loader separately.
489     if (url.isEmpty() || url == blankURL()) {
490         frame->loader()->completed();
491         frame->loader()->checkCompleted();
492     }
493 
494     return frame.get();
495 }
496 
submitForm(const char * action,const String & url,PassRefPtr<FormData> formData,const String & target,const String & contentType,const String & boundary,bool lockHistory,PassRefPtr<Event> event,PassRefPtr<FormState> formState)497 void FrameLoader::submitForm(const char* action, const String& url, PassRefPtr<FormData> formData,
498     const String& target, const String& contentType, const String& boundary,
499     bool lockHistory, PassRefPtr<Event> event, PassRefPtr<FormState> formState)
500 {
501     ASSERT(action);
502     ASSERT(strcmp(action, "GET") == 0 || strcmp(action, "POST") == 0);
503     ASSERT(formData);
504     ASSERT(formState);
505     ASSERT(formState->sourceFrame() == m_frame);
506 
507     if (!m_frame->page())
508         return;
509 
510     KURL u = completeURL(url.isNull() ? "" : url);
511     if (u.isEmpty())
512         return;
513 
514     if (protocolIsJavaScript(u)) {
515         m_isExecutingJavaScriptFormAction = true;
516         executeIfJavaScriptURL(u, false, false);
517         m_isExecutingJavaScriptFormAction = false;
518         return;
519     }
520 
521     FrameLoadRequest frameRequest;
522 #ifdef ANDROID_USER_GESTURE
523     frameRequest.resourceRequest().setUserGesture(isProcessingUserGesture());
524 #endif
525 
526     String targetOrBaseTarget = target.isEmpty() ? m_frame->document()->baseTarget() : target;
527     Frame* targetFrame = findFrameForNavigation(targetOrBaseTarget);
528     if (!targetFrame) {
529         targetFrame = m_frame;
530         frameRequest.setFrameName(targetOrBaseTarget);
531     }
532     if (!targetFrame->page())
533         return;
534 
535     // FIXME: We'd like to remove this altogether and fix the multiple form submission issue another way.
536 
537     // We do not want to submit more than one form from the same page, nor do we want to submit a single
538     // form more than once. This flag prevents these from happening; not sure how other browsers prevent this.
539     // The flag is reset in each time we start handle a new mouse or key down event, and
540     // also in setView since this part may get reused for a page from the back/forward cache.
541     // The form multi-submit logic here is only needed when we are submitting a form that affects this frame.
542 
543     // FIXME: Frame targeting is only one of the ways the submission could end up doing something other
544     // than replacing this frame's content, so this check is flawed. On the other hand, the check is hardly
545     // needed any more now that we reset m_submittedFormURL on each mouse or key down event.
546 
547     if (m_frame->tree()->isDescendantOf(targetFrame)) {
548         if (m_submittedFormURL == u)
549             return;
550         m_submittedFormURL = u;
551     }
552 
553     formData->generateFiles(m_frame->page()->chrome()->client());
554 
555     if (!m_outgoingReferrer.isEmpty())
556         frameRequest.resourceRequest().setHTTPReferrer(m_outgoingReferrer);
557 
558     if (strcmp(action, "GET") == 0)
559         u.setQuery(formData->flattenToString());
560     else {
561         frameRequest.resourceRequest().setHTTPMethod("POST");
562         frameRequest.resourceRequest().setHTTPBody(formData);
563 
564         // construct some user headers if necessary
565         if (contentType.isNull() || contentType == "application/x-www-form-urlencoded")
566             frameRequest.resourceRequest().setHTTPContentType(contentType);
567         else // contentType must be "multipart/form-data"
568             frameRequest.resourceRequest().setHTTPContentType(contentType + "; boundary=" + boundary);
569     }
570 
571     frameRequest.resourceRequest().setURL(u);
572     addHTTPOriginIfNeeded(frameRequest.resourceRequest(), outgoingOrigin());
573 
574     targetFrame->loader()->scheduleFormSubmission(frameRequest, lockHistory, event, formState);
575 }
576 
stopLoading(bool sendUnload,DatabasePolicy databasePolicy)577 void FrameLoader::stopLoading(bool sendUnload, DatabasePolicy databasePolicy)
578 {
579     if (m_frame->document() && m_frame->document()->tokenizer())
580         m_frame->document()->tokenizer()->stopParsing();
581 
582     if (sendUnload) {
583         if (m_frame->document()) {
584             if (m_didCallImplicitClose && !m_wasUnloadEventEmitted) {
585                 Node* currentFocusedNode = m_frame->document()->focusedNode();
586                 if (currentFocusedNode)
587                     currentFocusedNode->aboutToUnload();
588                 m_unloadEventBeingDispatched = true;
589                 if (m_frame->domWindow())
590                     m_frame->domWindow()->dispatchUnloadEvent();
591                 m_unloadEventBeingDispatched = false;
592                 if (m_frame->document())
593                     m_frame->document()->updateStyleIfNeeded();
594                 m_wasUnloadEventEmitted = true;
595             }
596         }
597 
598         // Dispatching the unload event could have made m_frame->document() null.
599         if (m_frame->document() && !m_frame->document()->inPageCache())
600             m_frame->document()->removeAllEventListeners();
601     }
602 
603     m_isComplete = true; // to avoid calling completed() in finishedParsing() (David)
604     m_isLoadingMainResource = false;
605     m_didCallImplicitClose = true; // don't want that one either
606 
607     if (m_frame->document() && m_frame->document()->parsing()) {
608         finishedParsing();
609         m_frame->document()->setParsing(false);
610     }
611 
612     m_workingURL = KURL();
613 
614     if (Document* doc = m_frame->document()) {
615         if (DocLoader* docLoader = doc->docLoader())
616             cache()->loader()->cancelRequests(docLoader);
617 
618 #if ENABLE(DATABASE)
619         if (databasePolicy == DatabasePolicyStop)
620             doc->stopDatabases();
621 #endif
622     }
623 
624     // tell all subframes to stop as well
625     for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
626         child->loader()->stopLoading(sendUnload);
627 
628     cancelRedirection();
629 }
630 
stop()631 void FrameLoader::stop()
632 {
633     // http://bugs.webkit.org/show_bug.cgi?id=10854
634     // The frame's last ref may be removed and it will be deleted by checkCompleted().
635     RefPtr<Frame> protector(m_frame);
636 
637     if (m_frame->document()->tokenizer())
638         m_frame->document()->tokenizer()->stopParsing();
639     m_frame->document()->finishParsing();
640 
641     if (m_iconLoader)
642         m_iconLoader->stopLoading();
643 }
644 
closeURL()645 bool FrameLoader::closeURL()
646 {
647     saveDocumentState();
648     stopLoading(true);
649     m_frame->editor()->clearUndoRedoOperations();
650     return true;
651 }
652 
cancelRedirection(bool cancelWithLoadInProgress)653 void FrameLoader::cancelRedirection(bool cancelWithLoadInProgress)
654 {
655     m_cancellingWithLoadInProgress = cancelWithLoadInProgress;
656 
657     stopRedirectionTimer();
658 
659     m_scheduledRedirection.clear();
660 }
661 
iconURL()662 KURL FrameLoader::iconURL()
663 {
664     // If this isn't a top level frame, return nothing
665     if (m_frame->tree() && m_frame->tree()->parent())
666         return KURL();
667 
668     // If we have an iconURL from a Link element, return that
669     if (!m_frame->document()->iconURL().isEmpty())
670         return KURL(m_frame->document()->iconURL());
671 
672     // Don't return a favicon iconURL unless we're http or https
673     if (!m_URL.protocolInHTTPFamily())
674         return KURL();
675 
676     KURL url;
677     url.setProtocol(m_URL.protocol());
678     url.setHost(m_URL.host());
679     if (int port = m_URL.port())
680         url.setPort(port);
681     url.setPath("/favicon.ico");
682     return url;
683 }
684 
didOpenURL(const KURL & url)685 bool FrameLoader::didOpenURL(const KURL& url)
686 {
687     if (m_scheduledRedirection && m_scheduledRedirection->wasDuringLoad) {
688         // A redirect was scheduled before the document was created.
689         // This can happen when one frame changes another frame's location.
690         return false;
691     }
692 
693     cancelRedirection();
694     m_frame->editor()->clearLastEditCommand();
695     closeURL();
696 
697     m_isComplete = false;
698     m_isLoadingMainResource = true;
699     m_didCallImplicitClose = false;
700 
701     // If we are still in the process of initializing an empty document then
702     // its frame is not in a consistent state for rendering, so avoid setJSStatusBarText
703     // since it may cause clients to attempt to render the frame.
704     if (!m_creatingInitialEmptyDocument) {
705         m_frame->setJSStatusBarText(String());
706         m_frame->setJSDefaultStatusBarText(String());
707     }
708     m_URL = url;
709     if (m_URL.protocolInHTTPFamily() && !m_URL.host().isEmpty() && m_URL.path().isEmpty())
710         m_URL.setPath("/");
711     m_workingURL = m_URL;
712 
713     started();
714 
715     return true;
716 }
717 
didExplicitOpen()718 void FrameLoader::didExplicitOpen()
719 {
720     m_isComplete = false;
721     m_didCallImplicitClose = false;
722 
723     // Calling document.open counts as committing the first real document load.
724     m_committedFirstRealDocumentLoad = true;
725 
726     // Prevent window.open(url) -- eg window.open("about:blank") -- from blowing away results
727     // from a subsequent window.document.open / window.document.write call.
728     // Cancelling redirection here works for all cases because document.open
729     // implicitly precedes document.write.
730     cancelRedirection();
731     if (m_frame->document()->url() != blankURL())
732         m_URL = m_frame->document()->url();
733 }
734 
executeIfJavaScriptURL(const KURL & url,bool userGesture,bool replaceDocument)735 bool FrameLoader::executeIfJavaScriptURL(const KURL& url, bool userGesture, bool replaceDocument)
736 {
737     if (!protocolIsJavaScript(url))
738         return false;
739 
740     if (m_frame->page() && !m_frame->page()->javaScriptURLsAreAllowed())
741         return true;
742 
743     const int javascriptSchemeLength = sizeof("javascript:") - 1;
744 
745     String script = decodeURLEscapeSequences(url.string().substring(javascriptSchemeLength));
746     ScriptValue result = executeScript(script, userGesture);
747 
748     String scriptResult;
749     if (!result.getString(scriptResult))
750         return true;
751 
752     SecurityOrigin* currentSecurityOrigin = m_frame->document()->securityOrigin();
753 
754     // FIXME: We should always replace the document, but doing so
755     //        synchronously can cause crashes:
756     //        http://bugs.webkit.org/show_bug.cgi?id=16782
757     if (replaceDocument) {
758         stopAllLoaders();
759         begin(m_URL, true, currentSecurityOrigin);
760         write(scriptResult);
761         end();
762     }
763 
764     return true;
765 }
766 
executeScript(const String & script,bool forceUserGesture)767 ScriptValue FrameLoader::executeScript(const String& script, bool forceUserGesture)
768 {
769     return executeScript(ScriptSourceCode(script, forceUserGesture ? KURL() : m_URL));
770 }
771 
executeScript(const ScriptSourceCode & sourceCode)772 ScriptValue FrameLoader::executeScript(const ScriptSourceCode& sourceCode)
773 {
774     if (!m_frame->script()->isEnabled() || m_frame->script()->isPaused())
775         return ScriptValue();
776 
777     bool wasRunningScript = m_isRunningScript;
778     m_isRunningScript = true;
779 
780     ScriptValue result = m_frame->script()->evaluate(sourceCode);
781 
782     if (!wasRunningScript) {
783         m_isRunningScript = false;
784         Document::updateStyleForAllDocuments();
785     }
786 
787     return result;
788 }
789 
cancelAndClear()790 void FrameLoader::cancelAndClear()
791 {
792     cancelRedirection();
793 
794     if (!m_isComplete)
795         closeURL();
796 
797     clear(false);
798     m_frame->script()->updatePlatformScriptObjects();
799 }
800 
clear(bool clearWindowProperties,bool clearScriptObjects)801 void FrameLoader::clear(bool clearWindowProperties, bool clearScriptObjects)
802 {
803     m_frame->editor()->clear();
804 
805     if (!m_needsClear)
806         return;
807     m_needsClear = false;
808 
809     if (!m_frame->document()->inPageCache()) {
810         m_frame->document()->cancelParsing();
811         m_frame->document()->stopActiveDOMObjects();
812         if (m_frame->document()->attached()) {
813             m_frame->document()->willRemove();
814             m_frame->document()->detach();
815 
816             m_frame->document()->removeFocusedNodeOfSubtree(m_frame->document());
817         }
818     }
819 
820     // Do this after detaching the document so that the unload event works.
821     if (clearWindowProperties) {
822         m_frame->clearDOMWindow();
823         m_frame->script()->clearWindowShell();
824     }
825 
826     m_frame->selection()->clear();
827     m_frame->eventHandler()->clear();
828     if (m_frame->view())
829         m_frame->view()->clear();
830 
831     m_frame->setSelectionGranularity(CharacterGranularity);
832 
833     // Do not drop the document before the ScriptController and view are cleared
834     // as some destructors might still try to access the document.
835     m_frame->setDocument(0);
836     m_decoder = 0;
837 
838     m_containsPlugIns = false;
839 
840     if (clearScriptObjects)
841         m_frame->script()->clearScriptObjects();
842 
843     m_redirectionTimer.stop();
844     m_scheduledRedirection.clear();
845 
846     m_checkCompletedTimer.stop();
847     m_checkLoadCompleteTimer.stop();
848 
849     m_receivedData = false;
850     m_isDisplayingInitialEmptyDocument = false;
851 
852     if (!m_encodingWasChosenByUser)
853         m_encoding = String();
854 }
855 
receivedFirstData()856 void FrameLoader::receivedFirstData()
857 {
858     begin(m_workingURL, false);
859 
860     dispatchDidCommitLoad();
861     dispatchWindowObjectAvailable();
862 
863     if (m_documentLoader) {
864         String ptitle = m_documentLoader->title();
865         // If we have a title let the WebView know about it.
866         if (!ptitle.isNull())
867             m_client->dispatchDidReceiveTitle(ptitle);
868     }
869 
870     m_workingURL = KURL();
871 
872     double delay;
873     String url;
874     if (!m_documentLoader)
875         return;
876     if (!parseHTTPRefresh(m_documentLoader->response().httpHeaderField("Refresh"), false, delay, url))
877         return;
878 
879     if (url.isEmpty())
880         url = m_URL.string();
881     else
882         url = m_frame->document()->completeURL(url).string();
883 
884     scheduleHTTPRedirection(delay, url);
885 }
886 
responseMIMEType() const887 const String& FrameLoader::responseMIMEType() const
888 {
889     return m_responseMIMEType;
890 }
891 
setResponseMIMEType(const String & type)892 void FrameLoader::setResponseMIMEType(const String& type)
893 {
894     m_responseMIMEType = type;
895 }
896 
begin()897 void FrameLoader::begin()
898 {
899     begin(KURL());
900 }
901 
begin(const KURL & url,bool dispatch,SecurityOrigin * origin)902 void FrameLoader::begin(const KURL& url, bool dispatch, SecurityOrigin* origin)
903 {
904     // We need to take a reference to the security origin because |clear|
905     // might destroy the document that owns it.
906     RefPtr<SecurityOrigin> forcedSecurityOrigin = origin;
907 
908     RefPtr<Document> document;
909 
910     // Create a new document before clearing the frame, because it may need to inherit an aliased security context.
911     if (!m_isDisplayingInitialEmptyDocument && m_client->shouldUsePluginDocument(m_responseMIMEType))
912         document = PluginDocument::create(m_frame);
913     else if (!m_client->hasHTMLView())
914         document = PlaceholderDocument::create(m_frame);
915     else
916         document = DOMImplementation::createDocument(m_responseMIMEType, m_frame, m_frame->inViewSourceMode());
917 
918     bool resetScripting = !(m_isDisplayingInitialEmptyDocument && m_frame->document()->securityOrigin()->isSecureTransitionTo(url));
919     clear(resetScripting, resetScripting);
920     if (resetScripting)
921         m_frame->script()->updatePlatformScriptObjects();
922 
923     m_needsClear = true;
924     m_isComplete = false;
925     m_didCallImplicitClose = false;
926     m_isLoadingMainResource = true;
927     m_isDisplayingInitialEmptyDocument = m_creatingInitialEmptyDocument;
928 
929     KURL ref(url);
930     ref.setUser(String());
931     ref.setPass(String());
932     ref.removeFragmentIdentifier();
933     m_outgoingReferrer = ref.string();
934     m_URL = url;
935 
936     m_frame->setDocument(document);
937 
938     if (dispatch)
939         dispatchWindowObjectAvailable();
940 
941     document->setURL(m_URL);
942     if (m_decoder)
943         document->setDecoder(m_decoder.get());
944     if (forcedSecurityOrigin)
945         document->setSecurityOrigin(forcedSecurityOrigin.get());
946 
947     m_frame->domWindow()->setURL(document->url());
948     m_frame->domWindow()->setSecurityOrigin(document->securityOrigin());
949 
950     updateFirstPartyForCookies();
951 
952     Settings* settings = document->settings();
953     document->docLoader()->setAutoLoadImages(settings && settings->loadsImagesAutomatically());
954 #ifdef ANDROID_BLOCK_NETWORK_IMAGE
955     document->docLoader()->setBlockNetworkImage(settings && settings->blockNetworkImage());
956 #endif
957 
958     if (m_documentLoader) {
959         String dnsPrefetchControl = m_documentLoader->response().httpHeaderField("X-DNS-Prefetch-Control");
960         if (!dnsPrefetchControl.isEmpty())
961             document->parseDNSPrefetchControlHeader(dnsPrefetchControl);
962     }
963 
964 #if FRAME_LOADS_USER_STYLESHEET
965     KURL userStyleSheet = settings ? settings->userStyleSheetLocation() : KURL();
966     if (!userStyleSheet.isEmpty())
967         m_frame->setUserStyleSheetLocation(userStyleSheet);
968 #endif
969 
970     restoreDocumentState();
971 
972     document->implicitOpen();
973 
974     if (m_frame->view() && m_client->hasHTMLView())
975         m_frame->view()->setContentsSize(IntSize());
976 }
977 
write(const char * str,int len,bool flush)978 void FrameLoader::write(const char* str, int len, bool flush)
979 {
980     if (len == 0 && !flush)
981         return;
982 
983     if (len == -1)
984         len = strlen(str);
985 
986     Tokenizer* tokenizer = m_frame->document()->tokenizer();
987     if (tokenizer && tokenizer->wantsRawData()) {
988         if (len > 0)
989             tokenizer->writeRawData(str, len);
990         return;
991     }
992 
993     if (!m_decoder) {
994         if (Settings* settings = m_frame->settings()) {
995             m_decoder = TextResourceDecoder::create(m_responseMIMEType,
996                 settings->defaultTextEncodingName(),
997                 settings->usesEncodingDetector());
998             Frame* parentFrame = m_frame->tree()->parent();
999             // Set the hint encoding to the parent frame encoding only if
1000             // the parent and the current frames share the security origin.
1001             // We impose this condition because somebody can make a child frame
1002             // containing a carefully crafted html/javascript in one encoding
1003             // that can be mistaken for hintEncoding (or related encoding) by
1004             // an auto detector. When interpreted in the latter, it could be
1005             // an attack vector.
1006             // FIXME: This might be too cautious for non-7bit-encodings and
1007             // we may consider relaxing this later after testing.
1008             if (canReferToParentFrameEncoding(m_frame, parentFrame))
1009                 m_decoder->setHintEncoding(parentFrame->document()->decoder());
1010         } else
1011             m_decoder = TextResourceDecoder::create(m_responseMIMEType, String());
1012         Frame* parentFrame = m_frame->tree()->parent();
1013         if (m_encoding.isEmpty()) {
1014             if (canReferToParentFrameEncoding(m_frame, parentFrame))
1015                 m_decoder->setEncoding(parentFrame->document()->inputEncoding(), TextResourceDecoder::EncodingFromParentFrame);
1016         } else {
1017             m_decoder->setEncoding(m_encoding,
1018                 m_encodingWasChosenByUser ? TextResourceDecoder::UserChosenEncoding : TextResourceDecoder::EncodingFromHTTPHeader);
1019         }
1020         m_frame->document()->setDecoder(m_decoder.get());
1021     }
1022 
1023     String decoded = m_decoder->decode(str, len);
1024     if (flush)
1025         decoded += m_decoder->flush();
1026     if (decoded.isEmpty())
1027         return;
1028 
1029     if (!m_receivedData) {
1030         m_receivedData = true;
1031         if (m_decoder->encoding().usesVisualOrdering())
1032             m_frame->document()->setVisuallyOrdered();
1033         m_frame->document()->recalcStyle(Node::Force);
1034     }
1035 
1036     if (tokenizer) {
1037         ASSERT(!tokenizer->wantsRawData());
1038         tokenizer->write(decoded, true);
1039     }
1040 }
1041 
write(const String & str)1042 void FrameLoader::write(const String& str)
1043 {
1044     if (str.isNull())
1045         return;
1046 
1047     if (!m_receivedData) {
1048         m_receivedData = true;
1049         m_frame->document()->setParseMode(Document::Strict);
1050     }
1051 
1052     if (Tokenizer* tokenizer = m_frame->document()->tokenizer())
1053         tokenizer->write(str, true);
1054 }
1055 
end()1056 void FrameLoader::end()
1057 {
1058     m_isLoadingMainResource = false;
1059     endIfNotLoadingMainResource();
1060 }
1061 
endIfNotLoadingMainResource()1062 void FrameLoader::endIfNotLoadingMainResource()
1063 {
1064     if (m_isLoadingMainResource || !m_frame->page() || !m_frame->document())
1065         return;
1066 
1067     // http://bugs.webkit.org/show_bug.cgi?id=10854
1068     // The frame's last ref may be removed and it can be deleted by checkCompleted(),
1069     // so we'll add a protective refcount
1070     RefPtr<Frame> protector(m_frame);
1071 
1072     // make sure nothing's left in there
1073     write(0, 0, true);
1074     m_frame->document()->finishParsing();
1075 }
1076 
iconLoadDecisionAvailable()1077 void FrameLoader::iconLoadDecisionAvailable()
1078 {
1079     if (!m_mayLoadIconLater)
1080         return;
1081     LOG(IconDatabase, "FrameLoader %p was told a load decision is available for its icon", this);
1082     startIconLoader();
1083     m_mayLoadIconLater = false;
1084 }
1085 
startIconLoader()1086 void FrameLoader::startIconLoader()
1087 {
1088     // FIXME: We kick off the icon loader when the frame is done receiving its main resource.
1089     // But we should instead do it when we're done parsing the head element.
1090     if (!isLoadingMainFrame())
1091         return;
1092 
1093     if (!iconDatabase() || !iconDatabase()->isEnabled())
1094         return;
1095 
1096     KURL url(iconURL());
1097     String urlString(url.string());
1098     if (urlString.isEmpty())
1099         return;
1100 
1101     // If we're not reloading and the icon database doesn't say to load now then bail before we actually start the load
1102     if (loadType() != FrameLoadTypeReload && loadType() != FrameLoadTypeReloadFromOrigin) {
1103         IconLoadDecision decision = iconDatabase()->loadDecisionForIconURL(urlString, m_documentLoader.get());
1104         if (decision == IconLoadNo) {
1105             LOG(IconDatabase, "FrameLoader::startIconLoader() - Told not to load this icon, committing iconURL %s to database for pageURL mapping", urlString.ascii().data());
1106             commitIconURLToIconDatabase(url);
1107 
1108             // We were told not to load this icon - that means this icon is already known by the database
1109             // If the icon data hasn't been read in from disk yet, kick off the read of the icon from the database to make sure someone
1110             // has done it.  This is after registering for the notification so the WebView can call the appropriate delegate method.
1111             // Otherwise if the icon data *is* available, notify the delegate
1112             if (!iconDatabase()->iconDataKnownForIconURL(urlString)) {
1113                 LOG(IconDatabase, "Told not to load icon %s but icon data is not yet available - registering for notification and requesting load from disk", urlString.ascii().data());
1114                 m_client->registerForIconNotification();
1115                 iconDatabase()->iconForPageURL(m_URL.string(), IntSize(0, 0));
1116                 iconDatabase()->iconForPageURL(originalRequestURL().string(), IntSize(0, 0));
1117             } else
1118                 m_client->dispatchDidReceiveIcon();
1119 
1120             return;
1121         }
1122 
1123         if (decision == IconLoadUnknown) {
1124             // In this case, we may end up loading the icon later, but we still want to commit the icon url mapping to the database
1125             // just in case we don't end up loading later - if we commit the mapping a second time after the load, that's no big deal
1126             // We also tell the client to register for the notification that the icon is received now so it isn't missed in case the
1127             // icon is later read in from disk
1128             LOG(IconDatabase, "FrameLoader %p might load icon %s later", this, urlString.ascii().data());
1129             m_mayLoadIconLater = true;
1130             m_client->registerForIconNotification();
1131             commitIconURLToIconDatabase(url);
1132             return;
1133         }
1134     }
1135 
1136     // People who want to avoid loading images generally want to avoid loading all images.
1137     // Now that we've accounted for URL mapping, avoid starting the network load if images aren't set to display automatically.
1138     Settings* settings = m_frame->settings();
1139     if (settings && !settings->loadsImagesAutomatically())
1140         return;
1141 
1142     // This is either a reload or the icon database said "yes, load the icon", so kick off the load!
1143     if (!m_iconLoader)
1144         m_iconLoader.set(IconLoader::create(m_frame).release());
1145 
1146     m_iconLoader->startLoading();
1147 }
1148 
setLocalLoadPolicy(LocalLoadPolicy policy)1149 void FrameLoader::setLocalLoadPolicy(LocalLoadPolicy policy)
1150 {
1151     localLoadPolicy = policy;
1152 }
1153 
restrictAccessToLocal()1154 bool FrameLoader::restrictAccessToLocal()
1155 {
1156     return localLoadPolicy != FrameLoader::AllowLocalLoadsForAll;
1157 }
1158 
allowSubstituteDataAccessToLocal()1159 bool FrameLoader::allowSubstituteDataAccessToLocal()
1160 {
1161     return localLoadPolicy != FrameLoader::AllowLocalLoadsForLocalOnly;
1162 }
1163 
commitIconURLToIconDatabase(const KURL & icon)1164 void FrameLoader::commitIconURLToIconDatabase(const KURL& icon)
1165 {
1166     ASSERT(iconDatabase());
1167     LOG(IconDatabase, "Committing iconURL %s to database for pageURLs %s and %s", icon.string().ascii().data(), m_URL.string().ascii().data(), originalRequestURL().string().ascii().data());
1168     iconDatabase()->setIconURLForPageURL(icon.string(), m_URL.string());
1169     iconDatabase()->setIconURLForPageURL(icon.string(), originalRequestURL().string());
1170 }
1171 
restoreDocumentState()1172 void FrameLoader::restoreDocumentState()
1173 {
1174     Document* doc = m_frame->document();
1175 
1176     HistoryItem* itemToRestore = 0;
1177 
1178     switch (loadType()) {
1179         case FrameLoadTypeReload:
1180         case FrameLoadTypeReloadFromOrigin:
1181         case FrameLoadTypeSame:
1182         case FrameLoadTypeReplace:
1183             break;
1184         case FrameLoadTypeBack:
1185         case FrameLoadTypeBackWMLDeckNotAccessible:
1186         case FrameLoadTypeForward:
1187         case FrameLoadTypeIndexedBackForward:
1188         case FrameLoadTypeRedirectWithLockedBackForwardList:
1189         case FrameLoadTypeStandard:
1190             itemToRestore = m_currentHistoryItem.get();
1191     }
1192 
1193     if (!itemToRestore)
1194         return;
1195 
1196     LOG(Loading, "WebCoreLoading %s: restoring form state from %p", m_frame->tree()->name().string().utf8().data(), itemToRestore);
1197     doc->setStateForNewFormElements(itemToRestore->documentState());
1198 }
1199 
gotoAnchor()1200 void FrameLoader::gotoAnchor()
1201 {
1202     // If our URL has no ref, then we have no place we need to jump to.
1203     // OTOH If CSS target was set previously, we want to set it to 0, recalc
1204     // and possibly repaint because :target pseudo class may have been
1205     // set (see bug 11321).
1206     if (!m_URL.hasFragmentIdentifier() && !m_frame->document()->cssTarget())
1207         return;
1208 
1209     String fragmentIdentifier = m_URL.fragmentIdentifier();
1210     if (gotoAnchor(fragmentIdentifier))
1211         return;
1212 
1213     // Try again after decoding the ref, based on the document's encoding.
1214     if (m_decoder)
1215         gotoAnchor(decodeURLEscapeSequences(fragmentIdentifier, m_decoder->encoding()));
1216 }
1217 
finishedParsing()1218 void FrameLoader::finishedParsing()
1219 {
1220     if (m_creatingInitialEmptyDocument)
1221         return;
1222 
1223     // This can be called from the Frame's destructor, in which case we shouldn't protect ourselves
1224     // because doing so will cause us to re-enter the destructor when protector goes out of scope.
1225     // Null-checking the FrameView indicates whether or not we're in the destructor.
1226     RefPtr<Frame> protector = m_frame->view() ? m_frame : 0;
1227 
1228     m_client->dispatchDidFinishDocumentLoad();
1229 
1230     checkCompleted();
1231 
1232     if (!m_frame->view())
1233         return; // We are being destroyed by something checkCompleted called.
1234 
1235     // Check if the scrollbars are really needed for the content.
1236     // If not, remove them, relayout, and repaint.
1237     m_frame->view()->restoreScrollbar();
1238 
1239     gotoAnchor();
1240 }
1241 
loadDone()1242 void FrameLoader::loadDone()
1243 {
1244     checkCompleted();
1245 }
1246 
checkCompleted()1247 void FrameLoader::checkCompleted()
1248 {
1249     if (m_frame->view())
1250         m_frame->view()->checkStopDelayingDeferredRepaints();
1251 
1252     // Any frame that hasn't completed yet?
1253     for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
1254         if (!child->loader()->m_isComplete)
1255             return;
1256 
1257     // Have we completed before?
1258     if (m_isComplete)
1259         return;
1260 
1261     // Are we still parsing?
1262     if (m_frame->document()->parsing())
1263         return;
1264 
1265     // Still waiting for images/scripts?
1266     if (numRequests(m_frame->document()))
1267         return;
1268 
1269     // OK, completed.
1270     m_isComplete = true;
1271 
1272     RefPtr<Frame> protect(m_frame);
1273     checkCallImplicitClose(); // if we didn't do it before
1274 
1275     // Do not start a redirection timer for subframes here.
1276     // That is deferred until the parent is completed.
1277     if (m_scheduledRedirection && !m_frame->tree()->parent())
1278         startRedirectionTimer();
1279 
1280     completed();
1281     if (m_frame->page())
1282         checkLoadComplete();
1283 }
1284 
checkCompletedTimerFired(Timer<FrameLoader> *)1285 void FrameLoader::checkCompletedTimerFired(Timer<FrameLoader>*)
1286 {
1287     checkCompleted();
1288 }
1289 
scheduleCheckCompleted()1290 void FrameLoader::scheduleCheckCompleted()
1291 {
1292     if (!m_checkCompletedTimer.isActive())
1293         m_checkCompletedTimer.startOneShot(0);
1294 }
1295 
checkLoadCompleteTimerFired(Timer<FrameLoader> *)1296 void FrameLoader::checkLoadCompleteTimerFired(Timer<FrameLoader>*)
1297 {
1298     if (!m_frame->page())
1299         return;
1300     checkLoadComplete();
1301 }
1302 
scheduleCheckLoadComplete()1303 void FrameLoader::scheduleCheckLoadComplete()
1304 {
1305     if (!m_checkLoadCompleteTimer.isActive())
1306         m_checkLoadCompleteTimer.startOneShot(0);
1307 }
1308 
checkCallImplicitClose()1309 void FrameLoader::checkCallImplicitClose()
1310 {
1311     if (m_didCallImplicitClose || m_frame->document()->parsing())
1312         return;
1313 
1314     for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
1315         if (!child->loader()->m_isComplete) // still got a frame running -> too early
1316             return;
1317 
1318     m_didCallImplicitClose = true;
1319     m_wasUnloadEventEmitted = false;
1320     m_frame->document()->implicitClose();
1321 }
1322 
baseURL() const1323 KURL FrameLoader::baseURL() const
1324 {
1325     ASSERT(m_frame->document());
1326     return m_frame->document()->baseURL();
1327 }
1328 
completeURL(const String & url)1329 KURL FrameLoader::completeURL(const String& url)
1330 {
1331     ASSERT(m_frame->document());
1332     return m_frame->document()->completeURL(url);
1333 }
1334 
scheduleHTTPRedirection(double delay,const String & url)1335 void FrameLoader::scheduleHTTPRedirection(double delay, const String& url)
1336 {
1337     if (delay < 0 || delay > INT_MAX / 1000)
1338         return;
1339 
1340     if (!m_frame->page())
1341         return;
1342 
1343     if (url.isEmpty())
1344         return;
1345 
1346     // We want a new history item if the refresh timeout is > 1 second.
1347     if (!m_scheduledRedirection || delay <= m_scheduledRedirection->delay)
1348         scheduleRedirection(new ScheduledRedirection(delay, url, true, delay <= 1, false, false));
1349 }
1350 
mustLockBackForwardList(Frame * targetFrame)1351 static bool mustLockBackForwardList(Frame* targetFrame)
1352 {
1353     // Navigation of a subframe during loading of an ancestor frame does not create a new back/forward item.
1354     // The definition of "during load" is any time before all handlers for the load event have been run.
1355     // See https://bugs.webkit.org/show_bug.cgi?id=14957 for the original motivation for this.
1356 
1357     for (Frame* ancestor = targetFrame->tree()->parent(); ancestor; ancestor = ancestor->tree()->parent()) {
1358         Document* document = ancestor->document();
1359         if (!ancestor->loader()->isComplete() || document && document->processingLoadEvent())
1360             return true;
1361     }
1362     return false;
1363 }
1364 
scheduleLocationChange(const String & url,const String & referrer,bool lockHistory,bool lockBackForwardList,bool wasUserGesture)1365 void FrameLoader::scheduleLocationChange(const String& url, const String& referrer, bool lockHistory, bool lockBackForwardList, bool wasUserGesture)
1366 {
1367     if (!m_frame->page())
1368         return;
1369 
1370     if (url.isEmpty())
1371         return;
1372 
1373     lockBackForwardList = lockBackForwardList || mustLockBackForwardList(m_frame);
1374 
1375     // If the URL we're going to navigate to is the same as the current one, except for the
1376     // fragment part, we don't need to schedule the location change.
1377     KURL parsedURL(url);
1378     if (parsedURL.hasFragmentIdentifier() && equalIgnoringFragmentIdentifier(m_URL, parsedURL)) {
1379         changeLocation(completeURL(url), referrer, lockHistory, lockBackForwardList, wasUserGesture);
1380         return;
1381     }
1382 
1383     // Handle a location change of a page with no document as a special case.
1384     // This may happen when a frame changes the location of another frame.
1385     bool duringLoad = !m_committedFirstRealDocumentLoad;
1386 
1387     scheduleRedirection(new ScheduledRedirection(url, referrer, lockHistory, lockBackForwardList, wasUserGesture, false, duringLoad));
1388 }
1389 
scheduleFormSubmission(const FrameLoadRequest & frameRequest,bool lockHistory,PassRefPtr<Event> event,PassRefPtr<FormState> formState)1390 void FrameLoader::scheduleFormSubmission(const FrameLoadRequest& frameRequest,
1391     bool lockHistory, PassRefPtr<Event> event, PassRefPtr<FormState> formState)
1392 {
1393     ASSERT(m_frame->page());
1394     ASSERT(!frameRequest.isEmpty());
1395 
1396     // FIXME: Do we need special handling for form submissions where the URL is the same
1397     // as the current one except for the fragment part? See scheduleLocationChange above.
1398 
1399     // Handle a location change of a page with no document as a special case.
1400     // This may happen when a frame changes the location of another frame.
1401     bool duringLoad = !m_committedFirstRealDocumentLoad;
1402 
1403     scheduleRedirection(new ScheduledRedirection(frameRequest, lockHistory, mustLockBackForwardList(m_frame), event, formState, duringLoad));
1404 }
1405 
scheduleRefresh(bool wasUserGesture)1406 void FrameLoader::scheduleRefresh(bool wasUserGesture)
1407 {
1408     if (!m_frame->page())
1409         return;
1410 
1411     if (m_URL.isEmpty())
1412         return;
1413 
1414     scheduleRedirection(new ScheduledRedirection(m_URL.string(), m_outgoingReferrer, true, true, wasUserGesture, true, false));
1415 }
1416 
isLocationChange(const ScheduledRedirection & redirection)1417 bool FrameLoader::isLocationChange(const ScheduledRedirection& redirection)
1418 {
1419     switch (redirection.type) {
1420         case ScheduledRedirection::redirection:
1421             return false;
1422         case ScheduledRedirection::historyNavigation:
1423         case ScheduledRedirection::locationChange:
1424         case ScheduledRedirection::formSubmission:
1425             return true;
1426     }
1427     ASSERT_NOT_REACHED();
1428     return false;
1429 }
1430 
scheduleHistoryNavigation(int steps)1431 void FrameLoader::scheduleHistoryNavigation(int steps)
1432 {
1433     if (!m_frame->page())
1434         return;
1435 
1436     // navigation will always be allowed in the 0 steps case, which is OK because that's supposed to force a reload.
1437     if (!canGoBackOrForward(steps)) {
1438         cancelRedirection();
1439         return;
1440     }
1441 
1442     scheduleRedirection(new ScheduledRedirection(steps));
1443 }
1444 
goBackOrForward(int distance)1445 void FrameLoader::goBackOrForward(int distance)
1446 {
1447     if (distance == 0)
1448         return;
1449 
1450     Page* page = m_frame->page();
1451     if (!page)
1452         return;
1453     BackForwardList* list = page->backForwardList();
1454     if (!list)
1455         return;
1456 
1457     HistoryItem* item = list->itemAtIndex(distance);
1458     if (!item) {
1459         if (distance > 0) {
1460             int forwardListCount = list->forwardListCount();
1461             if (forwardListCount > 0)
1462                 item = list->itemAtIndex(forwardListCount);
1463         } else {
1464             int backListCount = list->backListCount();
1465             if (backListCount > 0)
1466                 item = list->itemAtIndex(-backListCount);
1467         }
1468     }
1469 
1470     ASSERT(item); // we should not reach this line with an empty back/forward list
1471     if (item)
1472         page->goToItem(item, FrameLoadTypeIndexedBackForward);
1473 }
1474 
redirectionTimerFired(Timer<FrameLoader> *)1475 void FrameLoader::redirectionTimerFired(Timer<FrameLoader>*)
1476 {
1477     ASSERT(m_frame->page());
1478 
1479     OwnPtr<ScheduledRedirection> redirection(m_scheduledRedirection.release());
1480 
1481     switch (redirection->type) {
1482         case ScheduledRedirection::redirection:
1483         case ScheduledRedirection::locationChange:
1484             changeLocation(KURL(redirection->url), redirection->referrer,
1485                 redirection->lockHistory, redirection->lockBackForwardList, redirection->wasUserGesture, redirection->wasRefresh);
1486             return;
1487         case ScheduledRedirection::historyNavigation:
1488             if (redirection->historySteps == 0) {
1489                 // Special case for go(0) from a frame -> reload only the frame
1490                 urlSelected(m_URL, "", 0, redirection->lockHistory, redirection->lockBackForwardList, redirection->wasUserGesture);
1491                 return;
1492             }
1493             // go(i!=0) from a frame navigates into the history of the frame only,
1494             // in both IE and NS (but not in Mozilla). We can't easily do that.
1495             goBackOrForward(redirection->historySteps);
1496             return;
1497         case ScheduledRedirection::formSubmission:
1498             // The submitForm function will find a target frame before using the redirection timer.
1499             // Now that the timer has fired, we need to repeat the security check which normally is done when
1500             // selecting a target, in case conditions have changed. Other code paths avoid this by targeting
1501             // without leaving a time window. If we fail the check just silently drop the form submission.
1502             if (!redirection->formState->sourceFrame()->loader()->shouldAllowNavigation(m_frame))
1503                 return;
1504             loadFrameRequest(redirection->frameRequest, redirection->lockHistory, redirection->lockBackForwardList,
1505                 redirection->event, redirection->formState);
1506             return;
1507     }
1508 
1509     ASSERT_NOT_REACHED();
1510 }
1511 
loadURLIntoChildFrame(const KURL & url,const String & referer,Frame * childFrame)1512 void FrameLoader::loadURLIntoChildFrame(const KURL& url, const String& referer, Frame* childFrame)
1513 {
1514     ASSERT(childFrame);
1515 
1516     HistoryItem* parentItem = currentHistoryItem();
1517     FrameLoadType loadType = this->loadType();
1518     FrameLoadType childLoadType = FrameLoadTypeRedirectWithLockedBackForwardList;
1519 
1520     KURL workingURL = url;
1521 
1522     // If we're moving in the back/forward list, we might want to replace the content
1523     // of this child frame with whatever was there at that point.
1524     if (parentItem && parentItem->children().size() && isBackForwardLoadType(loadType)) {
1525         HistoryItem* childItem = parentItem->childItemWithTarget(childFrame->tree()->name());
1526         if (childItem) {
1527             // Use the original URL to ensure we get all the side-effects, such as
1528             // onLoad handlers, of any redirects that happened. An example of where
1529             // this is needed is Radar 3213556.
1530             workingURL = KURL(childItem->originalURLString());
1531             childLoadType = loadType;
1532             childFrame->loader()->m_provisionalHistoryItem = childItem;
1533         }
1534     }
1535 
1536 #if ENABLE(ARCHIVE) // ANDROID extension: disabled to reduce code size
1537     RefPtr<Archive> subframeArchive = activeDocumentLoader()->popArchiveForSubframe(childFrame->tree()->name());
1538 
1539     if (subframeArchive)
1540         childFrame->loader()->loadArchive(subframeArchive.release());
1541     else
1542 #endif
1543 #ifdef ANDROID_USER_GESTURE
1544         childFrame->loader()->loadURL(workingURL, referer, String(), false, childLoadType, 0, 0, false);
1545 #else
1546         childFrame->loader()->loadURL(workingURL, referer, String(), false, childLoadType, 0, 0);
1547 #endif
1548 }
1549 
1550 #if ENABLE(ARCHIVE) // ANDROID extension: disabled to reduce code size
loadArchive(PassRefPtr<Archive> prpArchive)1551 void FrameLoader::loadArchive(PassRefPtr<Archive> prpArchive)
1552 {
1553     RefPtr<Archive> archive = prpArchive;
1554 
1555     ArchiveResource* mainResource = archive->mainResource();
1556     ASSERT(mainResource);
1557     if (!mainResource)
1558         return;
1559 
1560     SubstituteData substituteData(mainResource->data(), mainResource->mimeType(), mainResource->textEncoding(), KURL());
1561 
1562     ResourceRequest request(mainResource->url());
1563 #if PLATFORM(MAC)
1564     request.applyWebArchiveHackForMail();
1565 #endif
1566 
1567     RefPtr<DocumentLoader> documentLoader = m_client->createDocumentLoader(request, substituteData);
1568     documentLoader->addAllArchiveResources(archive.get());
1569     load(documentLoader.get());
1570 }
1571 #endif
1572 
encoding() const1573 String FrameLoader::encoding() const
1574 {
1575     if (m_encodingWasChosenByUser && !m_encoding.isEmpty())
1576         return m_encoding;
1577     if (m_decoder && m_decoder->encoding().isValid())
1578         return m_decoder->encoding().name();
1579     Settings* settings = m_frame->settings();
1580     return settings ? settings->defaultTextEncodingName() : String();
1581 }
1582 
gotoAnchor(const String & name)1583 bool FrameLoader::gotoAnchor(const String& name)
1584 {
1585     ASSERT(m_frame->document());
1586 
1587     if (!m_frame->document()->haveStylesheetsLoaded()) {
1588         m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(true);
1589         return false;
1590     }
1591 
1592     m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(false);
1593 
1594     Element* anchorNode = m_frame->document()->findAnchor(name);
1595 
1596 #if ENABLE(SVG)
1597     if (m_frame->document()->isSVGDocument()) {
1598         if (name.startsWith("xpointer(")) {
1599             // We need to parse the xpointer reference here
1600         } else if (name.startsWith("svgView(")) {
1601             RefPtr<SVGSVGElement> svg = static_cast<SVGDocument*>(m_frame->document())->rootElement();
1602             if (!svg->currentView()->parseViewSpec(name))
1603                 return false;
1604             svg->setUseCurrentView(true);
1605         } else {
1606             if (anchorNode && anchorNode->hasTagName(SVGNames::viewTag)) {
1607                 RefPtr<SVGViewElement> viewElement = anchorNode->hasTagName(SVGNames::viewTag) ? static_cast<SVGViewElement*>(anchorNode) : 0;
1608                 if (viewElement.get()) {
1609                     RefPtr<SVGSVGElement> svg = static_cast<SVGSVGElement*>(SVGLocatable::nearestViewportElement(viewElement.get()));
1610                     svg->inheritViewAttributes(viewElement.get());
1611                 }
1612             }
1613         }
1614         // FIXME: need to decide which <svg> to focus on, and zoom to that one
1615         // FIXME: need to actually "highlight" the viewTarget(s)
1616     }
1617 #endif
1618 
1619     m_frame->document()->setCSSTarget(anchorNode); // Setting to null will clear the current target.
1620 
1621     // Implement the rule that "" and "top" both mean top of page as in other browsers.
1622     if (!anchorNode && !(name.isEmpty() || equalIgnoringCase(name, "top")))
1623         return false;
1624 
1625     if (FrameView* view = m_frame->view())
1626 #ifdef ANDROID_SCROLL_ON_GOTO_ANCHOR
1627     {
1628         // TODO(andreip): check with Grace if this is correct.
1629         android::WebFrame::getWebFrame(m_frame)->setUserInitiatedClick(true);
1630 #endif
1631         view->maintainScrollPositionAtAnchor(anchorNode ? static_cast<Node*>(anchorNode) : m_frame->document());
1632 #ifdef ANDROID_SCROLL_ON_GOTO_ANCHOR
1633         android::WebFrame::getWebFrame(m_frame)->setUserInitiatedClick(false);
1634     }
1635 #endif
1636 
1637     return true;
1638 }
1639 
requestObject(RenderPart * renderer,const String & url,const AtomicString & frameName,const String & mimeType,const Vector<String> & paramNames,const Vector<String> & paramValues)1640 bool FrameLoader::requestObject(RenderPart* renderer, const String& url, const AtomicString& frameName,
1641     const String& mimeType, const Vector<String>& paramNames, const Vector<String>& paramValues)
1642 {
1643     if (url.isEmpty() && mimeType.isEmpty())
1644         return false;
1645 
1646     if (!m_frame->script()->xssAuditor()->canLoadObject(url)) {
1647         // It is unsafe to honor the request for this object.
1648         return false;
1649     }
1650 
1651     KURL completedURL;
1652     if (!url.isEmpty())
1653         completedURL = completeURL(url);
1654 
1655     bool useFallback;
1656     if (shouldUsePlugin(completedURL, mimeType, renderer->hasFallbackContent(), useFallback)) {
1657         Settings* settings = m_frame->settings();
1658         if (!settings || !settings->arePluginsEnabled() ||
1659             (!settings->isJavaEnabled() && MIMETypeRegistry::isJavaAppletMIMEType(mimeType)))
1660             return false;
1661         return loadPlugin(renderer, completedURL, mimeType, paramNames, paramValues, useFallback);
1662     }
1663 
1664     ASSERT(renderer->node()->hasTagName(objectTag) || renderer->node()->hasTagName(embedTag));
1665     HTMLPlugInElement* element = static_cast<HTMLPlugInElement*>(renderer->node());
1666 
1667     // FIXME: OK to always make a new frame? When does the old frame get removed?
1668     return loadSubframe(element, completedURL, frameName, m_outgoingReferrer);
1669 }
1670 
shouldUsePlugin(const KURL & url,const String & mimeType,bool hasFallback,bool & useFallback)1671 bool FrameLoader::shouldUsePlugin(const KURL& url, const String& mimeType, bool hasFallback, bool& useFallback)
1672 {
1673     if (m_client->shouldUsePluginDocument(mimeType)) {
1674         useFallback = false;
1675         return true;
1676     }
1677 
1678     // Allow other plug-ins to win over QuickTime because if the user has installed a plug-in that
1679     // can handle TIFF (which QuickTime can also handle) they probably intended to override QT.
1680     if (m_frame->page() && (mimeType == "image/tiff" || mimeType == "image/tif" || mimeType == "image/x-tiff")) {
1681         const PluginData* pluginData = m_frame->page()->pluginData();
1682         String pluginName = pluginData ? pluginData->pluginNameForMimeType(mimeType) : String();
1683         if (!pluginName.isEmpty() && !pluginName.contains("QuickTime", false))
1684             return true;
1685     }
1686 
1687     ObjectContentType objectType = m_client->objectContentType(url, mimeType);
1688     // If an object's content can't be handled and it has no fallback, let
1689     // it be handled as a plugin to show the broken plugin icon.
1690     useFallback = objectType == ObjectContentNone && hasFallback;
1691     return objectType == ObjectContentNone || objectType == ObjectContentNetscapePlugin || objectType == ObjectContentOtherPlugin;
1692 }
1693 
toPlugInElement(Node * node)1694 static HTMLPlugInElement* toPlugInElement(Node* node)
1695 {
1696     if (!node)
1697         return 0;
1698 
1699 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
1700     ASSERT(node->hasTagName(objectTag) || node->hasTagName(embedTag)
1701         || node->hasTagName(videoTag) || node->hasTagName(audioTag)
1702         || node->hasTagName(appletTag));
1703 #else
1704     ASSERT(node->hasTagName(objectTag) || node->hasTagName(embedTag)
1705         || node->hasTagName(appletTag));
1706 #endif
1707 
1708     return static_cast<HTMLPlugInElement*>(node);
1709 }
1710 
loadPlugin(RenderPart * renderer,const KURL & url,const String & mimeType,const Vector<String> & paramNames,const Vector<String> & paramValues,bool useFallback)1711 bool FrameLoader::loadPlugin(RenderPart* renderer, const KURL& url, const String& mimeType,
1712     const Vector<String>& paramNames, const Vector<String>& paramValues, bool useFallback)
1713 {
1714     RefPtr<Widget> widget;
1715 
1716     if (renderer && !useFallback) {
1717         HTMLPlugInElement* element = toPlugInElement(renderer->node());
1718 
1719         if (!canLoad(url, String(), frame()->document())) {
1720             FrameLoader::reportLocalLoadFailed(m_frame, url.string());
1721             return false;
1722         }
1723 
1724         widget = m_client->createPlugin(IntSize(renderer->contentWidth(), renderer->contentHeight()),
1725                                         element, url, paramNames, paramValues, mimeType,
1726                                         m_frame->document()->isPluginDocument() && !m_containsPlugIns);
1727         if (widget) {
1728             renderer->setWidget(widget);
1729             m_containsPlugIns = true;
1730         }
1731     }
1732 
1733     return widget != 0;
1734 }
1735 
parentCompleted()1736 void FrameLoader::parentCompleted()
1737 {
1738     if (m_scheduledRedirection && !m_redirectionTimer.isActive())
1739         startRedirectionTimer();
1740 }
1741 
outgoingReferrer() const1742 String FrameLoader::outgoingReferrer() const
1743 {
1744     return m_outgoingReferrer;
1745 }
1746 
outgoingOrigin() const1747 String FrameLoader::outgoingOrigin() const
1748 {
1749     return m_frame->document()->securityOrigin()->toString();
1750 }
1751 
opener()1752 Frame* FrameLoader::opener()
1753 {
1754     return m_opener;
1755 }
1756 
setOpener(Frame * opener)1757 void FrameLoader::setOpener(Frame* opener)
1758 {
1759     if (m_opener)
1760         m_opener->loader()->m_openedFrames.remove(m_frame);
1761     if (opener)
1762         opener->loader()->m_openedFrames.add(m_frame);
1763     m_opener = opener;
1764 
1765     if (m_frame->document()) {
1766         m_frame->document()->initSecurityContext();
1767         m_frame->domWindow()->setSecurityOrigin(m_frame->document()->securityOrigin());
1768     }
1769 }
1770 
openedByDOM() const1771 bool FrameLoader::openedByDOM() const
1772 {
1773     return m_openedByDOM;
1774 }
1775 
setOpenedByDOM()1776 void FrameLoader::setOpenedByDOM()
1777 {
1778     m_openedByDOM = true;
1779 }
1780 
handleFallbackContent()1781 void FrameLoader::handleFallbackContent()
1782 {
1783     HTMLFrameOwnerElement* owner = m_frame->ownerElement();
1784     if (!owner || !owner->hasTagName(objectTag))
1785         return;
1786     static_cast<HTMLObjectElement*>(owner)->renderFallbackContent();
1787 }
1788 
provisionalLoadStarted()1789 void FrameLoader::provisionalLoadStarted()
1790 {
1791 #ifdef ANDROID_INSTRUMENT
1792     if (!m_frame->tree()->parent())
1793         android::TimeCounter::reset();
1794 #endif
1795     m_firstLayoutDone = false;
1796     cancelRedirection(true);
1797     m_client->provisionalLoadStarted();
1798 }
1799 
isProcessingUserGesture()1800 bool FrameLoader::isProcessingUserGesture()
1801 {
1802     Frame* frame = m_frame->tree()->top();
1803     if (!frame->script()->isEnabled())
1804         return true; // If JavaScript is disabled, a user gesture must have initiated the navigation.
1805     return frame->script()->processingUserGesture(); // FIXME: Use pageIsProcessingUserGesture.
1806 }
1807 
resetMultipleFormSubmissionProtection()1808 void FrameLoader::resetMultipleFormSubmissionProtection()
1809 {
1810     m_submittedFormURL = KURL();
1811 }
1812 
setEncoding(const String & name,bool userChosen)1813 void FrameLoader::setEncoding(const String& name, bool userChosen)
1814 {
1815     if (!m_workingURL.isEmpty())
1816         receivedFirstData();
1817     m_encoding = name;
1818     m_encodingWasChosenByUser = userChosen;
1819 }
1820 
addData(const char * bytes,int length)1821 void FrameLoader::addData(const char* bytes, int length)
1822 {
1823     ASSERT(m_workingURL.isEmpty());
1824     ASSERT(m_frame->document());
1825     ASSERT(m_frame->document()->parsing());
1826     write(bytes, length);
1827 }
1828 
1829 #if ENABLE(WML)
frameContainsWMLContent(Frame * frame)1830 static inline bool frameContainsWMLContent(Frame* frame)
1831 {
1832     Document* document = frame ? frame->document() : 0;
1833     if (!document)
1834         return false;
1835 
1836     return document->containsWMLContent() || document->isWMLDocument();
1837 }
1838 #endif
1839 
canCachePageContainingThisFrame()1840 bool FrameLoader::canCachePageContainingThisFrame()
1841 {
1842     return m_documentLoader
1843         && m_documentLoader->mainDocumentError().isNull()
1844         && !m_frame->tree()->childCount()
1845         // FIXME: If we ever change this so that frames with plug-ins will be cached,
1846         // we need to make sure that we don't cache frames that have outstanding NPObjects
1847         // (objects created by the plug-in). Since there is no way to pause/resume a Netscape plug-in,
1848         // they would need to be destroyed and then recreated, and there is no way that we can recreate
1849         // the right NPObjects. See <rdar://problem/5197041> for more information.
1850         && !m_containsPlugIns
1851         && !m_URL.protocolIs("https")
1852         && (!m_frame->domWindow() || !m_frame->domWindow()->hasEventListener(eventNames().unloadEvent))
1853 #if ENABLE(DATABASE)
1854         && !m_frame->document()->hasOpenDatabases()
1855 #endif
1856         && !m_frame->document()->usingGeolocation()
1857         && m_currentHistoryItem
1858         && !m_quickRedirectComing
1859         && !m_documentLoader->isLoadingInAPISense()
1860         && !m_documentLoader->isStopping()
1861         && m_frame->document()->canSuspendActiveDOMObjects()
1862 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
1863         // FIXME: We should investigating caching frames that have an associated
1864         // application cache. <rdar://problem/5917899> tracks that work.
1865         && m_documentLoader->applicationCacheHost()->canCacheInPageCache()
1866 #endif
1867 #if ENABLE(WML)
1868         && !frameContainsWMLContent(m_frame)
1869 #endif
1870         && m_client->canCachePage()
1871         ;
1872 }
1873 
canCachePage()1874 bool FrameLoader::canCachePage()
1875 {
1876 #ifndef NDEBUG
1877     logCanCachePageDecision();
1878 #endif
1879 
1880     // Cache the page, if possible.
1881     // Don't write to the cache if in the middle of a redirect, since we will want to
1882     // store the final page we end up on.
1883     // No point writing to the cache on a reload or loadSame, since we will just write
1884     // over it again when we leave that page.
1885     // FIXME: <rdar://problem/4886592> - We should work out the complexities of caching pages with frames as they
1886     // are the most interesting pages on the web, and often those that would benefit the most from caching!
1887     FrameLoadType loadType = this->loadType();
1888 
1889     return !m_frame->tree()->parent()
1890         && canCachePageContainingThisFrame()
1891         && m_frame->page()
1892         && m_frame->page()->backForwardList()->enabled()
1893         && m_frame->page()->backForwardList()->capacity() > 0
1894         && m_frame->page()->settings()->usesPageCache()
1895         && loadType != FrameLoadTypeReload
1896         && loadType != FrameLoadTypeReloadFromOrigin
1897         && loadType != FrameLoadTypeSame
1898         ;
1899 }
1900 
1901 #ifndef NDEBUG
pageCacheLogPrefix(int indentLevel)1902 static String& pageCacheLogPrefix(int indentLevel)
1903 {
1904     static int previousIndent = -1;
1905     DEFINE_STATIC_LOCAL(String, prefix, ());
1906 
1907     if (indentLevel != previousIndent) {
1908         previousIndent = indentLevel;
1909         prefix.truncate(0);
1910         for (int i = 0; i < previousIndent; ++i)
1911             prefix += "    ";
1912     }
1913 
1914     return prefix;
1915 }
1916 
pageCacheLog(const String & prefix,const String & message)1917 static void pageCacheLog(const String& prefix, const String& message)
1918 {
1919     LOG(PageCache, "%s%s", prefix.utf8().data(), message.utf8().data());
1920 }
1921 
1922 #define PCLOG(...) pageCacheLog(pageCacheLogPrefix(indentLevel), String::format(__VA_ARGS__))
1923 
logCanCachePageDecision()1924 void FrameLoader::logCanCachePageDecision()
1925 {
1926     // Only bother logging for main frames that have actually loaded and have content.
1927     if (m_creatingInitialEmptyDocument)
1928         return;
1929     KURL currentURL = m_documentLoader ? m_documentLoader->url() : KURL();
1930     if (currentURL.isEmpty())
1931         return;
1932 
1933     int indentLevel = 0;
1934     PCLOG("--------\n Determining if page can be cached:");
1935 
1936     bool cannotCache = !logCanCacheFrameDecision(1);
1937 
1938     FrameLoadType loadType = this->loadType();
1939     do {
1940         if (m_frame->tree()->parent())
1941             { PCLOG("   -Frame has a parent frame"); cannotCache = true; }
1942         if (!m_frame->page()) {
1943             PCLOG("   -There is no Page object");
1944             cannotCache = true;
1945             break;
1946         }
1947         if (!m_frame->page()->backForwardList()->enabled())
1948             { PCLOG("   -The back/forward list is disabled"); cannotCache = true; }
1949         if (!(m_frame->page()->backForwardList()->capacity() > 0))
1950             { PCLOG("   -The back/forward list has a 0 capacity"); cannotCache = true; }
1951         if (!m_frame->page()->settings()->usesPageCache())
1952             { PCLOG("   -Page settings says b/f cache disabled"); cannotCache = true; }
1953         if (loadType == FrameLoadTypeReload)
1954             { PCLOG("   -Load type is: Reload"); cannotCache = true; }
1955         if (loadType == FrameLoadTypeReloadFromOrigin)
1956             { PCLOG("   -Load type is: Reload from origin"); cannotCache = true; }
1957         if (loadType == FrameLoadTypeSame)
1958             { PCLOG("   -Load type is: Same"); cannotCache = true; }
1959     } while (false);
1960 
1961     PCLOG(cannotCache ? " Page CANNOT be cached\n--------" : " Page CAN be cached\n--------");
1962 }
1963 
logCanCacheFrameDecision(int indentLevel)1964 bool FrameLoader::logCanCacheFrameDecision(int indentLevel)
1965 {
1966     // Only bother logging for frames that have actually loaded and have content.
1967     if (m_creatingInitialEmptyDocument)
1968         return false;
1969     KURL currentURL = m_documentLoader ? m_documentLoader->url() : KURL();
1970     if (currentURL.isEmpty())
1971         return false;
1972 
1973     PCLOG("+---");
1974     KURL newURL = m_provisionalDocumentLoader ? m_provisionalDocumentLoader->url() : KURL();
1975     if (!newURL.isEmpty())
1976         PCLOG(" Determining if frame can be cached navigating from (%s) to (%s):", currentURL.string().utf8().data(), newURL.string().utf8().data());
1977     else
1978         PCLOG(" Determining if subframe with URL (%s) can be cached:", currentURL.string().utf8().data());
1979 
1980     bool cannotCache = false;
1981 
1982     do {
1983         if (!m_documentLoader) {
1984             PCLOG("   -There is no DocumentLoader object");
1985             cannotCache = true;
1986             break;
1987         }
1988         if (!m_documentLoader->mainDocumentError().isNull())
1989             { PCLOG("   -Main document has an error"); cannotCache = true; }
1990         if (m_frame->tree()->childCount())
1991             { PCLOG("   -Frame has child frames"); cannotCache = true; }
1992         if (m_containsPlugIns)
1993             { PCLOG("   -Frame contains plugins"); cannotCache = true; }
1994         if (m_URL.protocolIs("https"))
1995             { PCLOG("   -Frame is HTTPS"); cannotCache = true; }
1996         if (m_frame->domWindow() && m_frame->domWindow()->hasEventListener(eventNames().unloadEvent))
1997             { PCLOG("   -Frame has an unload event listener"); cannotCache = true; }
1998 #if ENABLE(DATABASE)
1999         if (m_frame->document()->hasOpenDatabases())
2000             { PCLOG("   -Frame has open database handles"); cannotCache = true; }
2001 #endif
2002         if (m_frame->document()->usingGeolocation())
2003             { PCLOG("   -Frame uses Geolocation"); cannotCache = true; }
2004         if (!m_currentHistoryItem)
2005             { PCLOG("   -No current history item"); cannotCache = true; }
2006         if (m_quickRedirectComing)
2007             { PCLOG("   -Quick redirect is coming"); cannotCache = true; }
2008         if (m_documentLoader->isLoadingInAPISense())
2009             { PCLOG("   -DocumentLoader is still loading in API sense"); cannotCache = true; }
2010         if (m_documentLoader->isStopping())
2011             { PCLOG("   -DocumentLoader is in the middle of stopping"); cannotCache = true; }
2012         if (!m_frame->document()->canSuspendActiveDOMObjects())
2013             { PCLOG("   -The document cannot suspect its active DOM Objects"); cannotCache = true; }
2014 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
2015         if (!m_documentLoader->applicationCacheHost()->canCacheInPageCache())
2016             { PCLOG("   -The DocumentLoader uses an application cache"); cannotCache = true; }
2017 #endif
2018         if (!m_client->canCachePage())
2019             { PCLOG("   -The client says this frame cannot be cached"); cannotCache = true; }
2020     } while (false);
2021 
2022     for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
2023         if (!child->loader()->logCanCacheFrameDecision(indentLevel + 1))
2024             cannotCache = true;
2025 
2026     PCLOG(cannotCache ? " Frame CANNOT be cached" : " Frame CAN be cached");
2027     PCLOG("+---");
2028 
2029     return !cannotCache;
2030 }
2031 #endif
2032 
updateFirstPartyForCookies()2033 void FrameLoader::updateFirstPartyForCookies()
2034 {
2035     if (m_frame->tree()->parent())
2036         setFirstPartyForCookies(m_frame->tree()->parent()->document()->firstPartyForCookies());
2037     else
2038         setFirstPartyForCookies(m_URL);
2039 }
2040 
setFirstPartyForCookies(const KURL & url)2041 void FrameLoader::setFirstPartyForCookies(const KURL& url)
2042 {
2043     m_frame->document()->setFirstPartyForCookies(url);
2044     for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
2045         child->loader()->setFirstPartyForCookies(url);
2046 }
2047 
2048 class HashChangeEventTask : public ScriptExecutionContext::Task {
2049 public:
create(PassRefPtr<Document> document)2050     static PassRefPtr<HashChangeEventTask> create(PassRefPtr<Document> document)
2051     {
2052         return adoptRef(new HashChangeEventTask(document));
2053     }
2054 
performTask(ScriptExecutionContext * context)2055     virtual void performTask(ScriptExecutionContext* context)
2056     {
2057         ASSERT_UNUSED(context, context->isDocument());
2058         m_document->dispatchWindowEvent(eventNames().hashchangeEvent, false, false);
2059     }
2060 
2061 private:
HashChangeEventTask(PassRefPtr<Document> document)2062     HashChangeEventTask(PassRefPtr<Document> document)
2063         : m_document(document)
2064     {
2065         ASSERT(m_document);
2066     }
2067 
2068     RefPtr<Document> m_document;
2069 };
2070 
2071 // This does the same kind of work that didOpenURL does, except it relies on the fact
2072 // that a higher level already checked that the URLs match and the scrolling is the right thing to do.
scrollToAnchor(const KURL & url)2073 void FrameLoader::scrollToAnchor(const KURL& url)
2074 {
2075     ASSERT(equalIgnoringFragmentIdentifier(url, m_URL));
2076     if (equalIgnoringFragmentIdentifier(url, m_URL) && !equalIgnoringNullity(url.fragmentIdentifier(), m_URL.fragmentIdentifier())) {
2077         Document* currentDocument = frame()->document();
2078         currentDocument->postTask(HashChangeEventTask::create(currentDocument));
2079     }
2080 
2081     m_URL = url;
2082     updateHistoryForAnchorScroll();
2083 
2084     // If we were in the autoscroll/panScroll mode we want to stop it before following the link to the anchor
2085     m_frame->eventHandler()->stopAutoscrollTimer();
2086     started();
2087     gotoAnchor();
2088 
2089     // It's important to model this as a load that starts and immediately finishes.
2090     // Otherwise, the parent frame may think we never finished loading.
2091     m_isComplete = false;
2092     checkCompleted();
2093 }
2094 
isComplete() const2095 bool FrameLoader::isComplete() const
2096 {
2097     return m_isComplete;
2098 }
2099 
scheduleRedirection(ScheduledRedirection * redirection)2100 void FrameLoader::scheduleRedirection(ScheduledRedirection* redirection)
2101 {
2102     ASSERT(m_frame->page());
2103 
2104     // If a redirect was scheduled during a load, then stop the current load.
2105     // Otherwise when the current load transitions from a provisional to a
2106     // committed state, pending redirects may be cancelled.
2107     if (redirection->wasDuringLoad) {
2108         if (m_provisionalDocumentLoader)
2109             m_provisionalDocumentLoader->stopLoading();
2110         stopLoading(true);
2111     }
2112 
2113     stopRedirectionTimer();
2114     m_scheduledRedirection.set(redirection);
2115     if (!m_isComplete && redirection->type != ScheduledRedirection::redirection)
2116         completed();
2117     if (m_isComplete || redirection->type != ScheduledRedirection::redirection)
2118         startRedirectionTimer();
2119 }
2120 
startRedirectionTimer()2121 void FrameLoader::startRedirectionTimer()
2122 {
2123     ASSERT(m_frame->page());
2124     ASSERT(m_scheduledRedirection);
2125 
2126     m_redirectionTimer.stop();
2127     m_redirectionTimer.startOneShot(m_scheduledRedirection->delay);
2128 
2129     switch (m_scheduledRedirection->type) {
2130         case ScheduledRedirection::locationChange:
2131         case ScheduledRedirection::redirection:
2132             clientRedirected(KURL(m_scheduledRedirection->url),
2133                 m_scheduledRedirection->delay,
2134                 currentTime() + m_redirectionTimer.nextFireInterval(),
2135                 m_scheduledRedirection->lockBackForwardList);
2136             return;
2137         case ScheduledRedirection::formSubmission:
2138             // FIXME: It would make sense to report form submissions as client redirects too.
2139             // But we didn't do that in the past when form submission used a separate delay
2140             // mechanism, so doing it will be a behavior change.
2141             return;
2142         case ScheduledRedirection::historyNavigation:
2143             // Don't report history navigations.
2144             return;
2145     }
2146     ASSERT_NOT_REACHED();
2147 }
2148 
stopRedirectionTimer()2149 void FrameLoader::stopRedirectionTimer()
2150 {
2151     if (!m_redirectionTimer.isActive())
2152         return;
2153 
2154     m_redirectionTimer.stop();
2155 
2156     if (m_scheduledRedirection) {
2157         switch (m_scheduledRedirection->type) {
2158             case ScheduledRedirection::locationChange:
2159             case ScheduledRedirection::redirection:
2160                 clientRedirectCancelledOrFinished(m_cancellingWithLoadInProgress);
2161                 return;
2162             case ScheduledRedirection::formSubmission:
2163                 // FIXME: It would make sense to report form submissions as client redirects too.
2164                 // But we didn't do that in the past when form submission used a separate delay
2165                 // mechanism, so doing it will be a behavior change.
2166                 return;
2167             case ScheduledRedirection::historyNavigation:
2168                 // Don't report history navigations.
2169                 return;
2170         }
2171         ASSERT_NOT_REACHED();
2172     }
2173 }
2174 
completed()2175 void FrameLoader::completed()
2176 {
2177     RefPtr<Frame> protect(m_frame);
2178     for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
2179         child->loader()->parentCompleted();
2180     if (Frame* parent = m_frame->tree()->parent())
2181         parent->loader()->checkCompleted();
2182     if (m_frame->view())
2183         m_frame->view()->maintainScrollPositionAtAnchor(0);
2184 }
2185 
started()2186 void FrameLoader::started()
2187 {
2188     for (Frame* frame = m_frame; frame; frame = frame->tree()->parent())
2189         frame->loader()->m_isComplete = false;
2190 }
2191 
containsPlugins() const2192 bool FrameLoader::containsPlugins() const
2193 {
2194     return m_containsPlugIns;
2195 }
2196 
prepareForLoadStart()2197 void FrameLoader::prepareForLoadStart()
2198 {
2199     if (Page* page = m_frame->page())
2200         page->progress()->progressStarted(m_frame);
2201     m_client->dispatchDidStartProvisionalLoad();
2202 }
2203 
setupForReplace()2204 void FrameLoader::setupForReplace()
2205 {
2206     setState(FrameStateProvisional);
2207     m_provisionalDocumentLoader = m_documentLoader;
2208     m_documentLoader = 0;
2209     detachChildren();
2210 }
2211 
setupForReplaceByMIMEType(const String & newMIMEType)2212 void FrameLoader::setupForReplaceByMIMEType(const String& newMIMEType)
2213 {
2214     activeDocumentLoader()->setupForReplaceByMIMEType(newMIMEType);
2215 }
2216 
2217 // This is a hack to allow keep navigation to http/https feeds working. To remove this
2218 // we need to introduce new API akin to registerURLSchemeAsLocal, that registers a
2219 // protocols navigation policy.
isFeedWithNestedProtocolInHTTPFamily(const KURL & url)2220 static bool isFeedWithNestedProtocolInHTTPFamily(const KURL& url)
2221 {
2222     const String& urlString = url.string();
2223     if (!urlString.startsWith("feed", false))
2224         return false;
2225 
2226     return urlString.startsWith("feed://", false)
2227         || urlString.startsWith("feed:http:", false) || urlString.startsWith("feed:https:", false)
2228         || urlString.startsWith("feeds:http:", false) || urlString.startsWith("feeds:https:", false)
2229         || urlString.startsWith("feedsearch:http:", false) || urlString.startsWith("feedsearch:https:", false);
2230 }
2231 
loadFrameRequest(const FrameLoadRequest & request,bool lockHistory,bool lockBackForwardList,PassRefPtr<Event> event,PassRefPtr<FormState> formState)2232 void FrameLoader::loadFrameRequest(const FrameLoadRequest& request, bool lockHistory, bool lockBackForwardList,
2233     PassRefPtr<Event> event, PassRefPtr<FormState> formState)
2234 {
2235     KURL url = request.resourceRequest().url();
2236 
2237     String referrer;
2238     String argsReferrer = request.resourceRequest().httpReferrer();
2239     if (!argsReferrer.isEmpty())
2240         referrer = argsReferrer;
2241     else
2242         referrer = m_outgoingReferrer;
2243 
2244     ASSERT(frame()->document());
2245     if (SecurityOrigin::shouldTreatURLAsLocal(url.string()) && !isFeedWithNestedProtocolInHTTPFamily(url)) {
2246         if (!canLoad(url, String(), frame()->document()) && !canLoad(url, referrer)) {
2247             FrameLoader::reportLocalLoadFailed(m_frame, url.string());
2248             return;
2249         }
2250     }
2251 
2252     if (shouldHideReferrer(url, referrer))
2253         referrer = String();
2254 
2255     FrameLoadType loadType;
2256     if (request.resourceRequest().cachePolicy() == ReloadIgnoringCacheData)
2257         loadType = FrameLoadTypeReload;
2258     else if (lockBackForwardList)
2259         loadType = FrameLoadTypeRedirectWithLockedBackForwardList;
2260     else
2261         loadType = FrameLoadTypeStandard;
2262 
2263 #ifdef ANDROID_USER_GESTURE
2264     if (request.resourceRequest().httpMethod() == "POST")
2265         loadPostRequest(request.resourceRequest(), referrer, request.frameName(), lockHistory, loadType, event, formState.get(), request.resourceRequest().getUserGesture());
2266     else
2267         loadURL(request.resourceRequest().url(), referrer, request.frameName(), lockHistory, loadType, event, formState.get(), request.resourceRequest().getUserGesture());
2268 #else
2269     if (request.resourceRequest().httpMethod() == "POST")
2270         loadPostRequest(request.resourceRequest(), referrer, request.frameName(), lockHistory, loadType, event, formState.get());
2271     else
2272         loadURL(request.resourceRequest().url(), referrer, request.frameName(), lockHistory, loadType, event, formState.get());
2273 #endif
2274 
2275     // FIXME: It's possible this targetFrame will not be the same frame that was targeted by the actual
2276     // load if frame names have changed.
2277     Frame* sourceFrame = formState ? formState->sourceFrame() : m_frame;
2278     Frame* targetFrame = sourceFrame->loader()->findFrameForNavigation(request.frameName());
2279     if (targetFrame && targetFrame != sourceFrame) {
2280         if (Page* page = targetFrame->page())
2281             page->chrome()->focus();
2282     }
2283 }
2284 
2285 #ifdef ANDROID_USER_GESTURE
loadURL(const KURL & newURL,const String & referrer,const String & frameName,bool lockHistory,FrameLoadType newLoadType,PassRefPtr<Event> event,PassRefPtr<FormState> prpFormState,bool userGesture)2286 void FrameLoader::loadURL(const KURL& newURL, const String& referrer, const String& frameName, bool lockHistory, FrameLoadType newLoadType,
2287     PassRefPtr<Event> event, PassRefPtr<FormState> prpFormState, bool userGesture)
2288 #else
2289 void FrameLoader::loadURL(const KURL& newURL, const String& referrer, const String& frameName, bool lockHistory, FrameLoadType newLoadType,
2290     PassRefPtr<Event> event, PassRefPtr<FormState> prpFormState)
2291 #endif
2292 {
2293     RefPtr<FormState> formState = prpFormState;
2294     bool isFormSubmission = formState;
2295 
2296     ResourceRequest request(newURL);
2297 #ifdef ANDROID_USER_GESTURE
2298     request.setUserGesture(userGesture);
2299 #endif
2300     if (!referrer.isEmpty()) {
2301         request.setHTTPReferrer(referrer);
2302         RefPtr<SecurityOrigin> referrerOrigin = SecurityOrigin::createFromString(referrer);
2303         addHTTPOriginIfNeeded(request, referrerOrigin->toString());
2304     }
2305     addExtraFieldsToRequest(request, newLoadType, true, event || isFormSubmission);
2306     if (newLoadType == FrameLoadTypeReload || newLoadType == FrameLoadTypeReloadFromOrigin)
2307         request.setCachePolicy(ReloadIgnoringCacheData);
2308 
2309     ASSERT(newLoadType != FrameLoadTypeSame);
2310 
2311     // The search for a target frame is done earlier in the case of form submission.
2312     Frame* targetFrame = isFormSubmission ? 0 : findFrameForNavigation(frameName);
2313     if (targetFrame && targetFrame != m_frame) {
2314 #ifdef ANDROID_USER_GESTURE
2315         targetFrame->loader()->loadURL(newURL, referrer, String(), lockHistory, newLoadType, event, formState.release(), userGesture);
2316 #else
2317         targetFrame->loader()->loadURL(newURL, referrer, String(), lockHistory, newLoadType, event, formState.release());
2318 #endif
2319         return;
2320     }
2321 
2322     NavigationAction action(newURL, newLoadType, isFormSubmission, event);
2323 
2324     if (!targetFrame && !frameName.isEmpty()) {
2325         checkNewWindowPolicy(action, request, formState.release(), frameName);
2326         return;
2327     }
2328 
2329     RefPtr<DocumentLoader> oldDocumentLoader = m_documentLoader;
2330 
2331     bool sameURL = shouldTreatURLAsSameAsCurrent(newURL);
2332 
2333     // Make sure to do scroll to anchor processing even if the URL is
2334     // exactly the same so pages with '#' links and DHTML side effects
2335     // work properly.
2336     if (shouldScrollToAnchor(isFormSubmission, newLoadType, newURL)) {
2337         oldDocumentLoader->setTriggeringAction(action);
2338         stopPolicyCheck();
2339         checkNavigationPolicy(request, oldDocumentLoader.get(), formState.release(),
2340             callContinueFragmentScrollAfterNavigationPolicy, this);
2341     } else {
2342         // must grab this now, since this load may stop the previous load and clear this flag
2343         bool isRedirect = m_quickRedirectComing;
2344         loadWithNavigationAction(request, action, lockHistory, newLoadType, formState.release());
2345         if (isRedirect) {
2346             m_quickRedirectComing = false;
2347             if (m_provisionalDocumentLoader)
2348                 m_provisionalDocumentLoader->setIsClientRedirect(true);
2349         } else if (sameURL)
2350             // Example of this case are sites that reload the same URL with a different cookie
2351             // driving the generated content, or a master frame with links that drive a target
2352             // frame, where the user has clicked on the same link repeatedly.
2353             m_loadType = FrameLoadTypeSame;
2354     }
2355 }
2356 
load(const ResourceRequest & request,bool lockHistory)2357 void FrameLoader::load(const ResourceRequest& request, bool lockHistory)
2358 {
2359     load(request, SubstituteData(), lockHistory);
2360 }
2361 
load(const ResourceRequest & request,const SubstituteData & substituteData,bool lockHistory)2362 void FrameLoader::load(const ResourceRequest& request, const SubstituteData& substituteData, bool lockHistory)
2363 {
2364     if (m_inStopAllLoaders)
2365         return;
2366 
2367     // FIXME: is this the right place to reset loadType? Perhaps this should be done after loading is finished or aborted.
2368     m_loadType = FrameLoadTypeStandard;
2369     RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request, substituteData);
2370     if (lockHistory && m_documentLoader)
2371         loader->setClientRedirectSourceForHistory(m_documentLoader->didCreateGlobalHistoryEntry() ? m_documentLoader->urlForHistory() : m_documentLoader->clientRedirectSourceForHistory());
2372     load(loader.get());
2373 }
2374 
load(const ResourceRequest & request,const String & frameName,bool lockHistory)2375 void FrameLoader::load(const ResourceRequest& request, const String& frameName, bool lockHistory)
2376 {
2377     if (frameName.isEmpty()) {
2378         load(request, lockHistory);
2379         return;
2380     }
2381 
2382     Frame* frame = findFrameForNavigation(frameName);
2383     if (frame) {
2384         frame->loader()->load(request, lockHistory);
2385         return;
2386     }
2387 
2388     checkNewWindowPolicy(NavigationAction(request.url(), NavigationTypeOther), request, 0, frameName);
2389 }
2390 
loadWithNavigationAction(const ResourceRequest & request,const NavigationAction & action,bool lockHistory,FrameLoadType type,PassRefPtr<FormState> formState)2391 void FrameLoader::loadWithNavigationAction(const ResourceRequest& request, const NavigationAction& action, bool lockHistory, FrameLoadType type, PassRefPtr<FormState> formState)
2392 {
2393     RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request, SubstituteData());
2394     if (lockHistory && m_documentLoader)
2395         loader->setClientRedirectSourceForHistory(m_documentLoader->didCreateGlobalHistoryEntry() ? m_documentLoader->urlForHistory() : m_documentLoader->clientRedirectSourceForHistory());
2396 
2397     loader->setTriggeringAction(action);
2398     if (m_documentLoader)
2399         loader->setOverrideEncoding(m_documentLoader->overrideEncoding());
2400 
2401     loadWithDocumentLoader(loader.get(), type, formState);
2402 }
2403 
load(DocumentLoader * newDocumentLoader)2404 void FrameLoader::load(DocumentLoader* newDocumentLoader)
2405 {
2406     ResourceRequest& r = newDocumentLoader->request();
2407     addExtraFieldsToMainResourceRequest(r);
2408     FrameLoadType type;
2409 
2410     if (shouldTreatURLAsSameAsCurrent(newDocumentLoader->originalRequest().url())) {
2411         r.setCachePolicy(ReloadIgnoringCacheData);
2412         type = FrameLoadTypeSame;
2413     } else
2414         type = FrameLoadTypeStandard;
2415 
2416     if (m_documentLoader)
2417         newDocumentLoader->setOverrideEncoding(m_documentLoader->overrideEncoding());
2418 
2419     // When we loading alternate content for an unreachable URL that we're
2420     // visiting in the history list, we treat it as a reload so the history list
2421     // is appropriately maintained.
2422     //
2423     // FIXME: This seems like a dangerous overloading of the meaning of "FrameLoadTypeReload" ...
2424     // shouldn't a more explicit type of reload be defined, that means roughly
2425     // "load without affecting history" ?
2426     if (shouldReloadToHandleUnreachableURL(newDocumentLoader)) {
2427         ASSERT(type == FrameLoadTypeStandard);
2428         type = FrameLoadTypeReload;
2429     }
2430 
2431     loadWithDocumentLoader(newDocumentLoader, type, 0);
2432 }
2433 
loadWithDocumentLoader(DocumentLoader * loader,FrameLoadType type,PassRefPtr<FormState> prpFormState)2434 void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType type, PassRefPtr<FormState> prpFormState)
2435 {
2436     ASSERT(m_client->hasWebView());
2437 
2438     // Unfortunately the view must be non-nil, this is ultimately due
2439     // to parser requiring a FrameView.  We should fix this dependency.
2440 
2441     ASSERT(m_frame->view());
2442 
2443     m_policyLoadType = type;
2444     RefPtr<FormState> formState = prpFormState;
2445     bool isFormSubmission = formState;
2446 
2447     const KURL& newURL = loader->request().url();
2448 
2449     if (shouldScrollToAnchor(isFormSubmission, m_policyLoadType, newURL)) {
2450         RefPtr<DocumentLoader> oldDocumentLoader = m_documentLoader;
2451         NavigationAction action(newURL, m_policyLoadType, isFormSubmission);
2452 
2453         oldDocumentLoader->setTriggeringAction(action);
2454         stopPolicyCheck();
2455         checkNavigationPolicy(loader->request(), oldDocumentLoader.get(), formState,
2456             callContinueFragmentScrollAfterNavigationPolicy, this);
2457     } else {
2458         if (Frame* parent = m_frame->tree()->parent())
2459             loader->setOverrideEncoding(parent->loader()->documentLoader()->overrideEncoding());
2460 
2461         stopPolicyCheck();
2462         setPolicyDocumentLoader(loader);
2463         if (loader->triggeringAction().isEmpty())
2464             loader->setTriggeringAction(NavigationAction(newURL, m_policyLoadType, isFormSubmission));
2465 
2466         checkNavigationPolicy(loader->request(), loader, formState,
2467             callContinueLoadAfterNavigationPolicy, this);
2468     }
2469 }
2470 
canLoad(const KURL & url,const String & referrer,const Document * doc)2471 bool FrameLoader::canLoad(const KURL& url, const String& referrer, const Document* doc)
2472 {
2473     return canLoad(url, referrer, doc ? doc->securityOrigin() : 0);
2474 }
2475 
canLoad(const KURL & url,const String & referrer,const SecurityOrigin * securityOrigin)2476 bool FrameLoader::canLoad(const KURL& url, const String& referrer, const SecurityOrigin* securityOrigin)
2477 {
2478     // We can always load any URL that isn't considered local (e.g. http URLs).
2479     if (!SecurityOrigin::shouldTreatURLAsLocal(url.string()))
2480         return true;
2481 
2482     // If we were provided a document, we let its local file policy dictate the result,
2483     // otherwise we allow local loads only if the supplied referrer is also local.
2484     if (securityOrigin)
2485         return securityOrigin->canLoadLocalResources();
2486     if (!referrer.isEmpty())
2487         return SecurityOrigin::shouldTreatURLAsLocal(referrer);
2488     return false;
2489 }
2490 
reportLocalLoadFailed(Frame * frame,const String & url)2491 void FrameLoader::reportLocalLoadFailed(Frame* frame, const String& url)
2492 {
2493     ASSERT(!url.isEmpty());
2494     if (!frame)
2495         return;
2496 
2497     frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "Not allowed to load local resource: " + url, 0, String());
2498 }
2499 
shouldHideReferrer(const KURL & url,const String & referrer)2500 bool FrameLoader::shouldHideReferrer(const KURL& url, const String& referrer)
2501 {
2502     bool referrerIsSecureURL = protocolIs(referrer, "https");
2503     bool referrerIsWebURL = referrerIsSecureURL || protocolIs(referrer, "http");
2504 
2505     if (!referrerIsWebURL)
2506         return true;
2507 
2508     if (!referrerIsSecureURL)
2509         return false;
2510 
2511     bool URLIsSecureURL = url.protocolIs("https");
2512 
2513     return !URLIsSecureURL;
2514 }
2515 
initialRequest() const2516 const ResourceRequest& FrameLoader::initialRequest() const
2517 {
2518     return activeDocumentLoader()->originalRequest();
2519 }
2520 
receivedData(const char * data,int length)2521 void FrameLoader::receivedData(const char* data, int length)
2522 {
2523     activeDocumentLoader()->receivedData(data, length);
2524 }
2525 
handleUnimplementablePolicy(const ResourceError & error)2526 void FrameLoader::handleUnimplementablePolicy(const ResourceError& error)
2527 {
2528     m_delegateIsHandlingUnimplementablePolicy = true;
2529     m_client->dispatchUnableToImplementPolicy(error);
2530     m_delegateIsHandlingUnimplementablePolicy = false;
2531 }
2532 
cannotShowMIMEType(const ResourceResponse & response)2533 void FrameLoader::cannotShowMIMEType(const ResourceResponse& response)
2534 {
2535     handleUnimplementablePolicy(m_client->cannotShowMIMETypeError(response));
2536 }
2537 
interruptionForPolicyChangeError(const ResourceRequest & request)2538 ResourceError FrameLoader::interruptionForPolicyChangeError(const ResourceRequest& request)
2539 {
2540     return m_client->interruptForPolicyChangeError(request);
2541 }
2542 
checkNavigationPolicy(const ResourceRequest & newRequest,NavigationPolicyDecisionFunction function,void * argument)2543 void FrameLoader::checkNavigationPolicy(const ResourceRequest& newRequest, NavigationPolicyDecisionFunction function, void* argument)
2544 {
2545     checkNavigationPolicy(newRequest, activeDocumentLoader(), 0, function, argument);
2546 }
2547 
checkContentPolicy(const String & MIMEType,ContentPolicyDecisionFunction function,void * argument)2548 void FrameLoader::checkContentPolicy(const String& MIMEType, ContentPolicyDecisionFunction function, void* argument)
2549 {
2550     ASSERT(activeDocumentLoader());
2551 
2552     // Always show content with valid substitute data.
2553     if (activeDocumentLoader()->substituteData().isValid()) {
2554         function(argument, PolicyUse);
2555         return;
2556     }
2557 
2558 #if ENABLE(FTPDIR)
2559     // Respect the hidden FTP Directory Listing pref so it can be tested even if the policy delegate might otherwise disallow it
2560     Settings* settings = m_frame->settings();
2561     if (settings && settings->forceFTPDirectoryListings() && MIMEType == "application/x-ftp-directory") {
2562         function(argument, PolicyUse);
2563         return;
2564     }
2565 #endif
2566 
2567     m_policyCheck.set(function, argument);
2568     m_client->dispatchDecidePolicyForMIMEType(&FrameLoader::continueAfterContentPolicy,
2569         MIMEType, activeDocumentLoader()->request());
2570 }
2571 
shouldReloadToHandleUnreachableURL(DocumentLoader * docLoader)2572 bool FrameLoader::shouldReloadToHandleUnreachableURL(DocumentLoader* docLoader)
2573 {
2574     KURL unreachableURL = docLoader->unreachableURL();
2575 
2576     if (unreachableURL.isEmpty())
2577         return false;
2578 
2579     if (!isBackForwardLoadType(m_policyLoadType))
2580         return false;
2581 
2582     // We only treat unreachableURLs specially during the delegate callbacks
2583     // for provisional load errors and navigation policy decisions. The former
2584     // case handles well-formed URLs that can't be loaded, and the latter
2585     // case handles malformed URLs and unknown schemes. Loading alternate content
2586     // at other times behaves like a standard load.
2587     DocumentLoader* compareDocumentLoader = 0;
2588     if (m_delegateIsDecidingNavigationPolicy || m_delegateIsHandlingUnimplementablePolicy)
2589         compareDocumentLoader = m_policyDocumentLoader.get();
2590     else if (m_delegateIsHandlingProvisionalLoadError)
2591         compareDocumentLoader = m_provisionalDocumentLoader.get();
2592 
2593     return compareDocumentLoader && unreachableURL == compareDocumentLoader->request().url();
2594 }
2595 
reloadWithOverrideEncoding(const String & encoding)2596 void FrameLoader::reloadWithOverrideEncoding(const String& encoding)
2597 {
2598     if (!m_documentLoader)
2599         return;
2600 
2601     ResourceRequest request = m_documentLoader->request();
2602     KURL unreachableURL = m_documentLoader->unreachableURL();
2603     if (!unreachableURL.isEmpty())
2604         request.setURL(unreachableURL);
2605 
2606     request.setCachePolicy(ReturnCacheDataElseLoad);
2607 
2608     RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request, SubstituteData());
2609     setPolicyDocumentLoader(loader.get());
2610 
2611     loader->setOverrideEncoding(encoding);
2612 
2613     loadWithDocumentLoader(loader.get(), FrameLoadTypeReload, 0);
2614 }
2615 
reload(bool endToEndReload)2616 void FrameLoader::reload(bool endToEndReload)
2617 {
2618     if (!m_documentLoader)
2619         return;
2620 
2621     // If a window is created by javascript, its main frame can have an empty but non-nil URL.
2622     // Reloading in this case will lose the current contents (see 4151001).
2623     if (m_documentLoader->request().url().isEmpty())
2624         return;
2625 
2626     ResourceRequest initialRequest = m_documentLoader->request();
2627 
2628     // Replace error-page URL with the URL we were trying to reach.
2629     KURL unreachableURL = m_documentLoader->unreachableURL();
2630     if (!unreachableURL.isEmpty())
2631         initialRequest.setURL(unreachableURL);
2632 
2633     // Create a new document loader for the reload, this will become m_documentLoader eventually,
2634     // but first it has to be the "policy" document loader, and then the "provisional" document loader.
2635     RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(initialRequest, SubstituteData());
2636 
2637     ResourceRequest& request = loader->request();
2638 
2639     // FIXME: We don't have a mechanism to revalidate the main resource without reloading at the moment.
2640     request.setCachePolicy(ReloadIgnoringCacheData);
2641 
2642     // If we're about to re-post, set up action so the application can warn the user.
2643     if (request.httpMethod() == "POST")
2644         loader->setTriggeringAction(NavigationAction(request.url(), NavigationTypeFormResubmitted));
2645 
2646     loader->setOverrideEncoding(m_documentLoader->overrideEncoding());
2647 
2648     loadWithDocumentLoader(loader.get(), endToEndReload ? FrameLoadTypeReloadFromOrigin : FrameLoadTypeReload, 0);
2649 }
2650 
canAccessAncestor(const SecurityOrigin * activeSecurityOrigin,Frame * targetFrame)2651 static bool canAccessAncestor(const SecurityOrigin* activeSecurityOrigin, Frame* targetFrame)
2652 {
2653     // targetFrame can be NULL when we're trying to navigate a top-level frame
2654     // that has a NULL opener.
2655     if (!targetFrame)
2656         return false;
2657 
2658     for (Frame* ancestorFrame = targetFrame; ancestorFrame; ancestorFrame = ancestorFrame->tree()->parent()) {
2659         Document* ancestorDocument = ancestorFrame->document();
2660         if (!ancestorDocument)
2661             return true;
2662 
2663         const SecurityOrigin* ancestorSecurityOrigin = ancestorDocument->securityOrigin();
2664         if (activeSecurityOrigin->canAccess(ancestorSecurityOrigin))
2665             return true;
2666     }
2667 
2668     return false;
2669 }
2670 
shouldAllowNavigation(Frame * targetFrame) const2671 bool FrameLoader::shouldAllowNavigation(Frame* targetFrame) const
2672 {
2673     // The navigation change is safe if the active frame is:
2674     //   - in the same security origin as the target or one of the target's
2675     //     ancestors.
2676     //
2677     // Or the target frame is:
2678     //   - a top-level frame in the frame hierarchy and the active frame can
2679     //     navigate the target frame's opener per above.
2680 
2681     if (!targetFrame)
2682         return true;
2683 
2684     // Performance optimization.
2685     if (m_frame == targetFrame)
2686         return true;
2687 
2688     // Let a frame navigate the top-level window that contains it.  This is
2689     // important to allow because it lets a site "frame-bust" (escape from a
2690     // frame created by another web site).
2691     if (targetFrame == m_frame->tree()->top())
2692         return true;
2693 
2694     Document* activeDocument = m_frame->document();
2695     ASSERT(activeDocument);
2696     const SecurityOrigin* activeSecurityOrigin = activeDocument->securityOrigin();
2697 
2698     // For top-level windows, check the opener.
2699     if (!targetFrame->tree()->parent() && canAccessAncestor(activeSecurityOrigin, targetFrame->loader()->opener()))
2700         return true;
2701 
2702     // In general, check the frame's ancestors.
2703     if (canAccessAncestor(activeSecurityOrigin, targetFrame))
2704         return true;
2705 
2706     Settings* settings = targetFrame->settings();
2707     if (settings && !settings->privateBrowsingEnabled()) {
2708         Document* targetDocument = targetFrame->document();
2709         // FIXME: this error message should contain more specifics of why the navigation change is not allowed.
2710         String message = String::format("Unsafe JavaScript attempt to initiate a navigation change for frame with URL %s from frame with URL %s.\n",
2711             targetDocument->url().string().utf8().data(), activeDocument->url().string().utf8().data());
2712 
2713         // FIXME: should we print to the console of the activeFrame as well?
2714         targetFrame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, message, 1, String());
2715     }
2716 
2717     return false;
2718 }
2719 
stopLoadingSubframes()2720 void FrameLoader::stopLoadingSubframes()
2721 {
2722     for (RefPtr<Frame> child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
2723         child->loader()->stopAllLoaders();
2724 }
2725 
stopAllLoaders(DatabasePolicy databasePolicy)2726 void FrameLoader::stopAllLoaders(DatabasePolicy databasePolicy)
2727 {
2728     if (m_unloadEventBeingDispatched)
2729         return;
2730 
2731     // If this method is called from within this method, infinite recursion can occur (3442218). Avoid this.
2732     if (m_inStopAllLoaders)
2733         return;
2734 
2735     m_inStopAllLoaders = true;
2736 
2737     stopPolicyCheck();
2738 
2739     stopLoadingSubframes();
2740     if (m_provisionalDocumentLoader)
2741         m_provisionalDocumentLoader->stopLoading(databasePolicy);
2742     if (m_documentLoader)
2743         m_documentLoader->stopLoading(databasePolicy);
2744 
2745     setProvisionalDocumentLoader(0);
2746 
2747 #if ENABLE(ARCHIVE) // ANDROID extension: disabled to reduce code size
2748     if (m_documentLoader)
2749         m_documentLoader->clearArchiveResources();
2750 #endif
2751 
2752     m_inStopAllLoaders = false;
2753 }
2754 
stopForUserCancel(bool deferCheckLoadComplete)2755 void FrameLoader::stopForUserCancel(bool deferCheckLoadComplete)
2756 {
2757     stopAllLoaders();
2758 
2759     if (deferCheckLoadComplete)
2760         scheduleCheckLoadComplete();
2761     else if (m_frame->page())
2762         checkLoadComplete();
2763 }
2764 
activeDocumentLoader() const2765 DocumentLoader* FrameLoader::activeDocumentLoader() const
2766 {
2767     if (m_state == FrameStateProvisional)
2768         return m_provisionalDocumentLoader.get();
2769     return m_documentLoader.get();
2770 }
2771 
isLoading() const2772 bool FrameLoader::isLoading() const
2773 {
2774     DocumentLoader* docLoader = activeDocumentLoader();
2775     if (!docLoader)
2776         return false;
2777     return docLoader->isLoadingMainResource() || docLoader->isLoadingSubresources() || docLoader->isLoadingPlugIns();
2778 }
2779 
frameHasLoaded() const2780 bool FrameLoader::frameHasLoaded() const
2781 {
2782     return m_committedFirstRealDocumentLoad || (m_provisionalDocumentLoader && !m_creatingInitialEmptyDocument);
2783 }
2784 
setDocumentLoader(DocumentLoader * loader)2785 void FrameLoader::setDocumentLoader(DocumentLoader* loader)
2786 {
2787     if (!loader && !m_documentLoader)
2788         return;
2789 
2790     ASSERT(loader != m_documentLoader);
2791     ASSERT(!loader || loader->frameLoader() == this);
2792 
2793     m_client->prepareForDataSourceReplacement();
2794     detachChildren();
2795     if (m_documentLoader)
2796         m_documentLoader->detachFromFrame();
2797 
2798     m_documentLoader = loader;
2799 }
2800 
setPolicyDocumentLoader(DocumentLoader * loader)2801 void FrameLoader::setPolicyDocumentLoader(DocumentLoader* loader)
2802 {
2803     if (m_policyDocumentLoader == loader)
2804         return;
2805 
2806     ASSERT(m_frame);
2807     if (loader)
2808         loader->setFrame(m_frame);
2809     if (m_policyDocumentLoader
2810             && m_policyDocumentLoader != m_provisionalDocumentLoader
2811             && m_policyDocumentLoader != m_documentLoader)
2812         m_policyDocumentLoader->detachFromFrame();
2813 
2814     m_policyDocumentLoader = loader;
2815 }
2816 
setProvisionalDocumentLoader(DocumentLoader * loader)2817 void FrameLoader::setProvisionalDocumentLoader(DocumentLoader* loader)
2818 {
2819     ASSERT(!loader || !m_provisionalDocumentLoader);
2820     ASSERT(!loader || loader->frameLoader() == this);
2821 
2822     if (m_provisionalDocumentLoader && m_provisionalDocumentLoader != m_documentLoader)
2823         m_provisionalDocumentLoader->detachFromFrame();
2824 
2825     m_provisionalDocumentLoader = loader;
2826 }
2827 
timeOfLastCompletedLoad()2828 double FrameLoader::timeOfLastCompletedLoad()
2829 {
2830     return storedTimeOfLastCompletedLoad;
2831 }
2832 
setState(FrameState newState)2833 void FrameLoader::setState(FrameState newState)
2834 {
2835     m_state = newState;
2836 
2837     if (newState == FrameStateProvisional)
2838         provisionalLoadStarted();
2839     else if (newState == FrameStateComplete) {
2840         frameLoadCompleted();
2841         storedTimeOfLastCompletedLoad = currentTime();
2842         if (m_documentLoader)
2843             m_documentLoader->stopRecordingResponses();
2844     }
2845 }
2846 
clearProvisionalLoad()2847 void FrameLoader::clearProvisionalLoad()
2848 {
2849     setProvisionalDocumentLoader(0);
2850     if (Page* page = m_frame->page())
2851         page->progress()->progressCompleted(m_frame);
2852     setState(FrameStateComplete);
2853 }
2854 
markLoadComplete()2855 void FrameLoader::markLoadComplete()
2856 {
2857     setState(FrameStateComplete);
2858 }
2859 
commitProvisionalLoad(PassRefPtr<CachedPage> prpCachedPage)2860 void FrameLoader::commitProvisionalLoad(PassRefPtr<CachedPage> prpCachedPage)
2861 {
2862     RefPtr<CachedPage> cachedPage = prpCachedPage;
2863     RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader;
2864 
2865     LOG(Loading, "WebCoreLoading %s: About to commit provisional load from previous URL %s", m_frame->tree()->name().string().utf8().data(), m_URL.string().utf8().data());
2866 
2867     // Check to see if we need to cache the page we are navigating away from into the back/forward cache.
2868     // We are doing this here because we know for sure that a new page is about to be loaded.
2869     cachePageForHistoryItem(m_currentHistoryItem.get());
2870 
2871     if (m_loadType != FrameLoadTypeReplace)
2872         closeOldDataSources();
2873 
2874     if (!cachedPage && !m_creatingInitialEmptyDocument)
2875         m_client->makeRepresentation(pdl.get());
2876 
2877     transitionToCommitted(cachedPage);
2878 
2879     // Call clientRedirectCancelledOrFinished() here so that the frame load delegate is notified that the redirect's
2880     // status has changed, if there was a redirect.  The frame load delegate may have saved some state about
2881     // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:.  Since we are
2882     // just about to commit a new page, there cannot possibly be a pending redirect at this point.
2883     if (m_sentRedirectNotification)
2884         clientRedirectCancelledOrFinished(false);
2885 
2886     if (cachedPage && cachedPage->document()) {
2887         open(*cachedPage);
2888         cachedPage->clear();
2889     } else {
2890         KURL url = pdl->substituteData().responseURL();
2891         if (url.isEmpty())
2892             url = pdl->url();
2893         if (url.isEmpty())
2894             url = pdl->responseURL();
2895         if (url.isEmpty())
2896             url = blankURL();
2897 
2898         didOpenURL(url);
2899     }
2900 
2901     LOG(Loading, "WebCoreLoading %s: Finished committing provisional load to URL %s", m_frame->tree()->name().string().utf8().data(), m_URL.string().utf8().data());
2902 
2903     if (m_loadType == FrameLoadTypeStandard && m_documentLoader->isClientRedirect())
2904         updateHistoryForClientRedirect();
2905 
2906     if (m_documentLoader->isLoadingFromCachedPage()) {
2907         m_frame->document()->documentDidBecomeActive();
2908 
2909         // Force a layout to update view size and thereby update scrollbars.
2910         m_client->forceLayout();
2911 
2912         const ResponseVector& responses = m_documentLoader->responses();
2913         size_t count = responses.size();
2914         for (size_t i = 0; i < count; i++) {
2915             const ResourceResponse& response = responses[i];
2916             // FIXME: If the WebKit client changes or cancels the request, this is not respected.
2917             ResourceError error;
2918             unsigned long identifier;
2919             ResourceRequest request(response.url());
2920             requestFromDelegate(request, identifier, error);
2921             // FIXME: If we get a resource with more than 2B bytes, this code won't do the right thing.
2922             // However, with today's computers and networking speeds, this won't happen in practice.
2923             // Could be an issue with a giant local file.
2924             sendRemainingDelegateMessages(identifier, response, static_cast<int>(response.expectedContentLength()), error);
2925         }
2926 
2927         pageCache()->remove(m_currentHistoryItem.get());
2928 
2929         m_documentLoader->setPrimaryLoadComplete(true);
2930 
2931         // FIXME: Why only this frame and not parent frames?
2932         checkLoadCompleteForThisFrame();
2933     }
2934 }
2935 
transitionToCommitted(PassRefPtr<CachedPage> cachedPage)2936 void FrameLoader::transitionToCommitted(PassRefPtr<CachedPage> cachedPage)
2937 {
2938     ASSERT(m_client->hasWebView());
2939     ASSERT(m_state == FrameStateProvisional);
2940 
2941     if (m_state != FrameStateProvisional)
2942         return;
2943 
2944     m_client->setCopiesOnScroll();
2945     updateHistoryForCommit();
2946 
2947     // The call to closeURL() invokes the unload event handler, which can execute arbitrary
2948     // JavaScript. If the script initiates a new load, we need to abandon the current load,
2949     // or the two will stomp each other.
2950     DocumentLoader* pdl = m_provisionalDocumentLoader.get();
2951     if (m_documentLoader)
2952         closeURL();
2953     if (pdl != m_provisionalDocumentLoader)
2954         return;
2955 
2956     // Nothing else can interupt this commit - set the Provisional->Committed transition in stone
2957     if (m_documentLoader)
2958         m_documentLoader->stopLoadingSubresources();
2959     if (m_documentLoader)
2960         m_documentLoader->stopLoadingPlugIns();
2961 
2962     setDocumentLoader(m_provisionalDocumentLoader.get());
2963     setProvisionalDocumentLoader(0);
2964     setState(FrameStateCommittedPage);
2965 
2966     // Handle adding the URL to the back/forward list.
2967     DocumentLoader* dl = m_documentLoader.get();
2968     String ptitle = dl->title();
2969 
2970     switch (m_loadType) {
2971         case FrameLoadTypeForward:
2972         case FrameLoadTypeBack:
2973         case FrameLoadTypeBackWMLDeckNotAccessible:
2974         case FrameLoadTypeIndexedBackForward:
2975             if (Page* page = m_frame->page())
2976                 if (page->backForwardList()) {
2977                     updateHistoryForBackForwardNavigation();
2978 
2979                     // Create a document view for this document, or used the cached view.
2980                     if (cachedPage) {
2981                         DocumentLoader* cachedDocumentLoader = cachedPage->documentLoader();
2982                         ASSERT(cachedDocumentLoader);
2983                         cachedDocumentLoader->setFrame(m_frame);
2984                         m_client->transitionToCommittedFromCachedFrame(cachedPage->cachedMainFrame());
2985 
2986                     } else
2987                         m_client->transitionToCommittedForNewPage();
2988                 }
2989             break;
2990 
2991         case FrameLoadTypeReload:
2992         case FrameLoadTypeReloadFromOrigin:
2993         case FrameLoadTypeSame:
2994         case FrameLoadTypeReplace:
2995             updateHistoryForReload();
2996             m_client->transitionToCommittedForNewPage();
2997             break;
2998 
2999         case FrameLoadTypeStandard:
3000             updateHistoryForStandardLoad();
3001 #ifndef BUILDING_ON_TIGER
3002             // This code was originally added for a Leopard performance imporvement. We decided to
3003             // ifdef it to fix correctness issues on Tiger documented in <rdar://problem/5441823>.
3004             if (m_frame->view())
3005                 m_frame->view()->setScrollbarsSuppressed(true);
3006 #endif
3007             m_client->transitionToCommittedForNewPage();
3008             break;
3009 
3010         case FrameLoadTypeRedirectWithLockedBackForwardList:
3011             updateHistoryForRedirectWithLockedBackForwardList();
3012             m_client->transitionToCommittedForNewPage();
3013             break;
3014 
3015         // FIXME Remove this check when dummy ds is removed (whatever "dummy ds" is).
3016         // An exception should be thrown if we're in the FrameLoadTypeUninitialized state.
3017         default:
3018             ASSERT_NOT_REACHED();
3019     }
3020 
3021     m_responseMIMEType = dl->responseMIMEType();
3022 
3023     // Tell the client we've committed this URL.
3024     ASSERT(m_frame->view());
3025 
3026     if (m_creatingInitialEmptyDocument)
3027         return;
3028 
3029     m_committedFirstRealDocumentLoad = true;
3030 
3031     if (!m_client->hasHTMLView())
3032         receivedFirstData();
3033     else if (cachedPage) {
3034         // For non-cached HTML pages, these methods are called in receivedFirstData().
3035         dispatchDidCommitLoad();
3036 
3037         // If we have a title let the WebView know about it.
3038         if (!ptitle.isNull())
3039             m_client->dispatchDidReceiveTitle(ptitle);
3040     }
3041 }
3042 
clientRedirectCancelledOrFinished(bool cancelWithLoadInProgress)3043 void FrameLoader::clientRedirectCancelledOrFinished(bool cancelWithLoadInProgress)
3044 {
3045     // Note that -webView:didCancelClientRedirectForFrame: is called on the frame load delegate even if
3046     // the redirect succeeded.  We should either rename this API, or add a new method, like
3047     // -webView:didFinishClientRedirectForFrame:
3048     m_client->dispatchDidCancelClientRedirect();
3049 
3050     if (!cancelWithLoadInProgress)
3051         m_quickRedirectComing = false;
3052 
3053     m_sentRedirectNotification = false;
3054 }
3055 
clientRedirected(const KURL & url,double seconds,double fireDate,bool lockBackForwardList)3056 void FrameLoader::clientRedirected(const KURL& url, double seconds, double fireDate, bool lockBackForwardList)
3057 {
3058     m_client->dispatchWillPerformClientRedirect(url, seconds, fireDate);
3059 
3060     // Remember that we sent a redirect notification to the frame load delegate so that when we commit
3061     // the next provisional load, we can send a corresponding -webView:didCancelClientRedirectForFrame:
3062     m_sentRedirectNotification = true;
3063 
3064     // If a "quick" redirect comes in, we set a special mode so we treat the next
3065     // load as part of the original navigation. If we don't have a document loader, we have
3066     // no "original" load on which to base a redirect, so we treat the redirect as a normal load.
3067     // Loads triggered by JavaScript form submissions never count as quick redirects.
3068     m_quickRedirectComing = lockBackForwardList && m_documentLoader && !m_isExecutingJavaScriptFormAction;
3069 }
3070 
shouldReload(const KURL & currentURL,const KURL & destinationURL)3071 bool FrameLoader::shouldReload(const KURL& currentURL, const KURL& destinationURL)
3072 {
3073 #if ENABLE(WML)
3074     // All WML decks are supposed to be reloaded, even within the same URL fragment
3075     if (frameContainsWMLContent(m_frame))
3076         return true;
3077 #endif
3078 
3079     // This function implements the rule: "Don't reload if navigating by fragment within
3080     // the same URL, but do reload if going to a new URL or to the same URL with no
3081     // fragment identifier at all."
3082     if (!destinationURL.hasFragmentIdentifier())
3083         return true;
3084     return !equalIgnoringFragmentIdentifier(currentURL, destinationURL);
3085 }
3086 
closeOldDataSources()3087 void FrameLoader::closeOldDataSources()
3088 {
3089     // FIXME: Is it important for this traversal to be postorder instead of preorder?
3090     // If so, add helpers for postorder traversal, and use them. If not, then lets not
3091     // use a recursive algorithm here.
3092     for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
3093         child->loader()->closeOldDataSources();
3094 
3095     if (m_documentLoader)
3096         m_client->dispatchWillClose();
3097 
3098     m_client->setMainFrameDocumentReady(false); // stop giving out the actual DOMDocument to observers
3099 }
3100 
open(CachedPage & cachedPage)3101 void FrameLoader::open(CachedPage& cachedPage)
3102 {
3103     ASSERT(!m_frame->tree()->parent());
3104     ASSERT(m_frame->page());
3105     ASSERT(m_frame->page()->mainFrame() == m_frame);
3106 
3107     cancelRedirection();
3108 
3109     // We still have to close the previous part page.
3110     closeURL();
3111 
3112     // Delete old status bar messages (if it _was_ activated on last URL).
3113     if (m_frame->script()->isEnabled()) {
3114         m_frame->setJSStatusBarText(String());
3115         m_frame->setJSDefaultStatusBarText(String());
3116     }
3117 
3118     open(*cachedPage.cachedMainFrame());
3119     cachedPage.restore(m_frame->page());
3120 
3121     checkCompleted();
3122 }
3123 
open(CachedFrame & cachedFrame)3124 void FrameLoader::open(CachedFrame& cachedFrame)
3125 {
3126     m_isComplete = false;
3127 
3128     // Don't re-emit the load event.
3129     m_didCallImplicitClose = true;
3130 
3131     KURL url = cachedFrame.url();
3132 
3133     if (url.protocolInHTTPFamily() && !url.host().isEmpty() && url.path().isEmpty())
3134         url.setPath("/");
3135 
3136     m_URL = url;
3137     m_workingURL = url;
3138 
3139     started();
3140 
3141     clear();
3142 
3143     Document* document = cachedFrame.document();
3144     ASSERT(document);
3145     document->setInPageCache(false);
3146 
3147     m_needsClear = true;
3148     m_isComplete = false;
3149     m_didCallImplicitClose = false;
3150     m_outgoingReferrer = url.string();
3151 
3152     FrameView* view = cachedFrame.view();
3153 
3154     // When navigating to a CachedFrame its FrameView should never be null.  If it is we'll crash in creative ways downstream.
3155     ASSERT(view);
3156     if (view)
3157         view->setWasScrolledByUser(false);
3158     m_frame->setView(view);
3159 
3160     m_frame->setDocument(document);
3161     m_frame->setDOMWindow(cachedFrame.domWindow());
3162     m_frame->domWindow()->setURL(document->url());
3163     m_frame->domWindow()->setSecurityOrigin(document->securityOrigin());
3164 
3165     m_decoder = document->decoder();
3166 
3167     updateFirstPartyForCookies();
3168 
3169     cachedFrame.restore();
3170 }
3171 
isStopping() const3172 bool FrameLoader::isStopping() const
3173 {
3174     return activeDocumentLoader()->isStopping();
3175 }
3176 
finishedLoading()3177 void FrameLoader::finishedLoading()
3178 {
3179     // Retain because the stop may release the last reference to it.
3180     RefPtr<Frame> protect(m_frame);
3181 
3182     RefPtr<DocumentLoader> dl = activeDocumentLoader();
3183     dl->finishedLoading();
3184     if (!dl->mainDocumentError().isNull() || !dl->frameLoader())
3185         return;
3186     dl->setPrimaryLoadComplete(true);
3187     m_client->dispatchDidLoadMainResource(dl.get());
3188     checkLoadComplete();
3189 }
3190 
isHostedByObjectElement() const3191 bool FrameLoader::isHostedByObjectElement() const
3192 {
3193     HTMLFrameOwnerElement* owner = m_frame->ownerElement();
3194     return owner && owner->hasTagName(objectTag);
3195 }
3196 
isLoadingMainFrame() const3197 bool FrameLoader::isLoadingMainFrame() const
3198 {
3199     Page* page = m_frame->page();
3200     return page && m_frame == page->mainFrame();
3201 }
3202 
canShowMIMEType(const String & MIMEType) const3203 bool FrameLoader::canShowMIMEType(const String& MIMEType) const
3204 {
3205     return m_client->canShowMIMEType(MIMEType);
3206 }
3207 
representationExistsForURLScheme(const String & URLScheme)3208 bool FrameLoader::representationExistsForURLScheme(const String& URLScheme)
3209 {
3210     return m_client->representationExistsForURLScheme(URLScheme);
3211 }
3212 
generatedMIMETypeForURLScheme(const String & URLScheme)3213 String FrameLoader::generatedMIMETypeForURLScheme(const String& URLScheme)
3214 {
3215     return m_client->generatedMIMETypeForURLScheme(URLScheme);
3216 }
3217 
cancelContentPolicyCheck()3218 void FrameLoader::cancelContentPolicyCheck()
3219 {
3220     m_client->cancelPolicyCheck();
3221     m_policyCheck.clear();
3222 }
3223 
didReceiveServerRedirectForProvisionalLoadForFrame()3224 void FrameLoader::didReceiveServerRedirectForProvisionalLoadForFrame()
3225 {
3226     m_client->dispatchDidReceiveServerRedirectForProvisionalLoad();
3227 }
3228 
finishedLoadingDocument(DocumentLoader * loader)3229 void FrameLoader::finishedLoadingDocument(DocumentLoader* loader)
3230 {
3231     // FIXME: Platforms shouldn't differ here!
3232 #if PLATFORM(WIN) || PLATFORM(CHROMIUM) || defined(ANDROID)
3233     if (m_creatingInitialEmptyDocument)
3234         return;
3235 #endif
3236 
3237 #if ENABLE(ARCHIVE) // ANDROID extension: disabled to reduce code size
3238     // If loading a webarchive, run through webarchive machinery
3239     const String& responseMIMEType = loader->responseMIMEType();
3240 
3241     // FIXME: Mac's FrameLoaderClient::finishedLoading() method does work that is required even with Archive loads
3242     // so we still need to call it.  Other platforms should only call finishLoading for non-archive loads
3243     // That work should be factored out so this #ifdef can be removed
3244 #if PLATFORM(MAC)
3245     m_client->finishedLoading(loader);
3246     if (!ArchiveFactory::isArchiveMimeType(responseMIMEType))
3247         return;
3248 #else
3249     if (!ArchiveFactory::isArchiveMimeType(responseMIMEType)) {
3250         m_client->finishedLoading(loader);
3251         return;
3252     }
3253 #endif
3254 
3255     RefPtr<Archive> archive(ArchiveFactory::create(loader->mainResourceData().get(), responseMIMEType));
3256     if (!archive)
3257         return;
3258 
3259     loader->addAllArchiveResources(archive.get());
3260 
3261     ArchiveResource* mainResource = archive->mainResource();
3262     loader->setParsedArchiveData(mainResource->data());
3263 
3264     m_responseMIMEType = mainResource->mimeType();
3265     didOpenURL(mainResource->url());
3266 
3267     String userChosenEncoding = documentLoader()->overrideEncoding();
3268     bool encodingIsUserChosen = !userChosenEncoding.isNull();
3269     setEncoding(encodingIsUserChosen ? userChosenEncoding : mainResource->textEncoding(), encodingIsUserChosen);
3270 
3271     ASSERT(m_frame->document());
3272 
3273     addData(mainResource->data()->data(), mainResource->data()->size());
3274 #else
3275     m_client->finishedLoading(loader);
3276 #endif // ARCHIVE
3277 }
3278 
isReplacing() const3279 bool FrameLoader::isReplacing() const
3280 {
3281     return m_loadType == FrameLoadTypeReplace;
3282 }
3283 
setReplacing()3284 void FrameLoader::setReplacing()
3285 {
3286     m_loadType = FrameLoadTypeReplace;
3287 }
3288 
revertToProvisional(DocumentLoader * loader)3289 void FrameLoader::revertToProvisional(DocumentLoader* loader)
3290 {
3291     m_client->revertToProvisionalState(loader);
3292 }
3293 
subframeIsLoading() const3294 bool FrameLoader::subframeIsLoading() const
3295 {
3296     // It's most likely that the last added frame is the last to load so we walk backwards.
3297     for (Frame* child = m_frame->tree()->lastChild(); child; child = child->tree()->previousSibling()) {
3298         FrameLoader* childLoader = child->loader();
3299         DocumentLoader* documentLoader = childLoader->documentLoader();
3300         if (documentLoader && documentLoader->isLoadingInAPISense())
3301             return true;
3302         documentLoader = childLoader->provisionalDocumentLoader();
3303         if (documentLoader && documentLoader->isLoadingInAPISense())
3304             return true;
3305     }
3306     return false;
3307 }
3308 
willChangeTitle(DocumentLoader * loader)3309 void FrameLoader::willChangeTitle(DocumentLoader* loader)
3310 {
3311     m_client->willChangeTitle(loader);
3312 }
3313 
loadType() const3314 FrameLoadType FrameLoader::loadType() const
3315 {
3316     return m_loadType;
3317 }
3318 
subresourceCachePolicy() const3319 CachePolicy FrameLoader::subresourceCachePolicy() const
3320 {
3321     if (m_isComplete)
3322         return CachePolicyVerify;
3323 
3324     if (m_loadType == FrameLoadTypeReloadFromOrigin)
3325         return CachePolicyReload;
3326 
3327     if (Frame* parentFrame = m_frame->tree()->parent()) {
3328         CachePolicy parentCachePolicy = parentFrame->loader()->subresourceCachePolicy();
3329         if (parentCachePolicy != CachePolicyVerify)
3330             return parentCachePolicy;
3331     }
3332 
3333     // FIXME: POST documents are always Reloads, but their subresources should still be Revalidate.
3334     // If we bring the CachePolicy.h and ResourceRequest cache policy enums in sync with each other and
3335     // remember "Revalidate" in ResourceRequests, we can remove this "POST" check and return either "Reload"
3336     // or "Revalidate" if the DocumentLoader was requested with either.
3337     const ResourceRequest& request(documentLoader()->request());
3338     if (request.cachePolicy() == ReloadIgnoringCacheData && !equalIgnoringCase(request.httpMethod(), "post"))
3339         return CachePolicyRevalidate;
3340 
3341     if (m_loadType == FrameLoadTypeReload)
3342         return CachePolicyRevalidate;
3343 
3344     return CachePolicyVerify;
3345 }
3346 
stopPolicyCheck()3347 void FrameLoader::stopPolicyCheck()
3348 {
3349     m_client->cancelPolicyCheck();
3350     PolicyCheck check = m_policyCheck;
3351     m_policyCheck.clear();
3352     check.cancel();
3353 }
3354 
checkLoadCompleteForThisFrame()3355 void FrameLoader::checkLoadCompleteForThisFrame()
3356 {
3357     ASSERT(m_client->hasWebView());
3358 
3359     switch (m_state) {
3360         case FrameStateProvisional: {
3361             if (m_delegateIsHandlingProvisionalLoadError)
3362                 return;
3363 
3364             RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader;
3365             if (!pdl)
3366                 return;
3367 
3368             // If we've received any errors we may be stuck in the provisional state and actually complete.
3369             const ResourceError& error = pdl->mainDocumentError();
3370             if (error.isNull())
3371                 return;
3372 
3373             // Check all children first.
3374             RefPtr<HistoryItem> item;
3375             if (Page* page = m_frame->page())
3376                 if (isBackForwardLoadType(loadType()) && m_frame == page->mainFrame())
3377                     item = m_currentHistoryItem;
3378 
3379             bool shouldReset = true;
3380             if (!(pdl->isLoadingInAPISense() && !pdl->isStopping())) {
3381                 m_delegateIsHandlingProvisionalLoadError = true;
3382                 m_client->dispatchDidFailProvisionalLoad(error);
3383                 m_delegateIsHandlingProvisionalLoadError = false;
3384 
3385                 // FIXME: can stopping loading here possibly have any effect, if isLoading is false,
3386                 // which it must be to be in this branch of the if? And is it OK to just do a full-on
3387                 // stopAllLoaders instead of stopLoadingSubframes?
3388                 stopLoadingSubframes();
3389                 pdl->stopLoading();
3390 
3391                 // Finish resetting the load state, but only if another load hasn't been started by the
3392                 // delegate callback.
3393                 if (pdl == m_provisionalDocumentLoader)
3394                     clearProvisionalLoad();
3395                 else if (m_provisionalDocumentLoader) {
3396                     KURL unreachableURL = m_provisionalDocumentLoader->unreachableURL();
3397                     if (!unreachableURL.isEmpty() && unreachableURL == pdl->request().url())
3398                         shouldReset = false;
3399                 }
3400             }
3401             if (shouldReset && item)
3402                 if (Page* page = m_frame->page()) {
3403                     page->backForwardList()->goToItem(item.get());
3404                     Settings* settings = m_frame->settings();
3405                     page->setGlobalHistoryItem((!settings || settings->privateBrowsingEnabled()) ? 0 : item.get());
3406                 }
3407             return;
3408         }
3409 
3410         case FrameStateCommittedPage: {
3411             DocumentLoader* dl = m_documentLoader.get();
3412             if (!dl || (dl->isLoadingInAPISense() && !dl->isStopping()))
3413                 return;
3414 
3415             markLoadComplete();
3416 
3417             // FIXME: Is this subsequent work important if we already navigated away?
3418             // Maybe there are bugs because of that, or extra work we can skip because
3419             // the new page is ready.
3420 
3421             m_client->forceLayoutForNonHTML();
3422 
3423             // If the user had a scroll point, scroll to it, overriding the anchor point if any.
3424             if (Page* page = m_frame->page())
3425                 if ((isBackForwardLoadType(m_loadType) || m_loadType == FrameLoadTypeReload || m_loadType == FrameLoadTypeReloadFromOrigin) && page->backForwardList())
3426                     restoreScrollPositionAndViewState();
3427 
3428             if (m_creatingInitialEmptyDocument || !m_committedFirstRealDocumentLoad)
3429                 return;
3430 
3431             const ResourceError& error = dl->mainDocumentError();
3432 #ifndef NDEBUG
3433             m_didDispatchDidCommitLoad = false;
3434 #endif
3435             if (!error.isNull())
3436                 m_client->dispatchDidFailLoad(error);
3437             else
3438                 m_client->dispatchDidFinishLoad();
3439 
3440             if (Page* page = m_frame->page())
3441                 page->progress()->progressCompleted(m_frame);
3442 
3443 #ifdef ANDROID_INSTRUMENT
3444             if (!m_frame->tree()->parent() && m_frame->document()->renderArena())
3445                 android::TimeCounter::report(m_URL, cache()->getLiveSize(), cache()->getDeadSize(),
3446                         m_frame->document()->renderArena()->reportPoolSize());
3447 #endif
3448             return;
3449         }
3450 
3451         case FrameStateComplete:
3452             frameLoadCompleted();
3453             return;
3454     }
3455 
3456     ASSERT_NOT_REACHED();
3457 }
3458 
continueAfterContentPolicy(PolicyAction policy)3459 void FrameLoader::continueAfterContentPolicy(PolicyAction policy)
3460 {
3461     PolicyCheck check = m_policyCheck;
3462     m_policyCheck.clear();
3463     check.call(policy);
3464 }
3465 
continueLoadAfterWillSubmitForm(PolicyAction)3466 void FrameLoader::continueLoadAfterWillSubmitForm(PolicyAction)
3467 {
3468     if (!m_provisionalDocumentLoader)
3469         return;
3470 
3471     // DocumentLoader calls back to our prepareForLoadStart
3472     m_provisionalDocumentLoader->prepareForLoadStart();
3473 
3474     // The load might be cancelled inside of prepareForLoadStart(), nulling out the m_provisionalDocumentLoader,
3475     // so we need to null check it again.
3476     if (!m_provisionalDocumentLoader)
3477         return;
3478 
3479     DocumentLoader* activeDocLoader = activeDocumentLoader();
3480     if (activeDocLoader && activeDocLoader->isLoadingMainResource())
3481         return;
3482 
3483     m_provisionalDocumentLoader->setLoadingFromCachedPage(false);
3484 
3485     unsigned long identifier = 0;
3486 
3487     if (Page* page = m_frame->page()) {
3488         identifier = page->progress()->createUniqueIdentifier();
3489         dispatchAssignIdentifierToInitialRequest(identifier, m_provisionalDocumentLoader.get(), m_provisionalDocumentLoader->originalRequest());
3490     }
3491 
3492     if (!m_provisionalDocumentLoader->startLoadingMainResource(identifier))
3493         m_provisionalDocumentLoader->updateLoading();
3494 }
3495 
didFirstLayout()3496 void FrameLoader::didFirstLayout()
3497 {
3498     if (Page* page = m_frame->page())
3499         if (isBackForwardLoadType(m_loadType) && page->backForwardList())
3500             restoreScrollPositionAndViewState();
3501 
3502     m_firstLayoutDone = true;
3503     m_client->dispatchDidFirstLayout();
3504 }
3505 
didFirstVisuallyNonEmptyLayout()3506 void FrameLoader::didFirstVisuallyNonEmptyLayout()
3507 {
3508     m_client->dispatchDidFirstVisuallyNonEmptyLayout();
3509 }
3510 
frameLoadCompleted()3511 void FrameLoader::frameLoadCompleted()
3512 {
3513     // Note: Can be called multiple times.
3514 
3515     m_client->frameLoadCompleted();
3516 
3517     // Even if already complete, we might have set a previous item on a frame that
3518     // didn't do any data loading on the past transaction. Make sure to clear these out.
3519     m_previousHistoryItem = 0;
3520 
3521     // After a canceled provisional load, firstLayoutDone is false.
3522     // Reset it to true if we're displaying a page.
3523     if (m_documentLoader)
3524         m_firstLayoutDone = true;
3525 }
3526 
firstLayoutDone() const3527 bool FrameLoader::firstLayoutDone() const
3528 {
3529     return m_firstLayoutDone;
3530 }
3531 
detachChildren()3532 void FrameLoader::detachChildren()
3533 {
3534     // FIXME: Is it really necessary to do this in reverse order?
3535     Frame* previous;
3536     for (Frame* child = m_frame->tree()->lastChild(); child; child = previous) {
3537         previous = child->tree()->previousSibling();
3538         child->loader()->detachFromParent();
3539     }
3540 }
3541 
closeAndRemoveChild(Frame * child)3542 void FrameLoader::closeAndRemoveChild(Frame* child)
3543 {
3544     child->tree()->detachFromParent();
3545 
3546     child->setView(0);
3547     if (child->ownerElement())
3548         child->page()->decrementFrameCount();
3549     child->pageDestroyed();
3550 
3551     m_frame->tree()->removeChild(child);
3552 }
3553 
recursiveCheckLoadComplete()3554 void FrameLoader::recursiveCheckLoadComplete()
3555 {
3556     Vector<RefPtr<Frame>, 10> frames;
3557 
3558     for (RefPtr<Frame> frame = m_frame->tree()->firstChild(); frame; frame = frame->tree()->nextSibling())
3559         frames.append(frame);
3560 
3561     unsigned size = frames.size();
3562     for (unsigned i = 0; i < size; i++)
3563         frames[i]->loader()->recursiveCheckLoadComplete();
3564 
3565     checkLoadCompleteForThisFrame();
3566 }
3567 
3568 // Called every time a resource is completely loaded, or an error is received.
checkLoadComplete()3569 void FrameLoader::checkLoadComplete()
3570 {
3571     ASSERT(m_client->hasWebView());
3572 
3573     // FIXME: Always traversing the entire frame tree is a bit inefficient, but
3574     // is currently needed in order to null out the previous history item for all frames.
3575     if (Page* page = m_frame->page())
3576         page->mainFrame()->loader()->recursiveCheckLoadComplete();
3577 }
3578 
numPendingOrLoadingRequests(bool recurse) const3579 int FrameLoader::numPendingOrLoadingRequests(bool recurse) const
3580 {
3581     if (!recurse)
3582         return numRequests(m_frame->document());
3583 
3584     int count = 0;
3585     for (Frame* frame = m_frame; frame; frame = frame->tree()->traverseNext(m_frame))
3586         count += numRequests(frame->document());
3587     return count;
3588 }
3589 
userAgent(const KURL & url) const3590 String FrameLoader::userAgent(const KURL& url) const
3591 {
3592     return m_client->userAgent(url);
3593 }
3594 
tokenizerProcessedData()3595 void FrameLoader::tokenizerProcessedData()
3596 {
3597     checkCompleted();
3598 }
3599 
handledOnloadEvents()3600 void FrameLoader::handledOnloadEvents()
3601 {
3602     m_client->dispatchDidHandleOnloadEvents();
3603 }
3604 
frameDetached()3605 void FrameLoader::frameDetached()
3606 {
3607     stopAllLoaders();
3608     m_frame->document()->stopActiveDOMObjects();
3609     detachFromParent();
3610 }
3611 
detachFromParent()3612 void FrameLoader::detachFromParent()
3613 {
3614     RefPtr<Frame> protect(m_frame);
3615 
3616     closeURL();
3617     stopAllLoaders();
3618     saveScrollPositionAndViewStateToItem(currentHistoryItem());
3619     detachChildren();
3620 
3621     if (Page* page = m_frame->page())
3622         page->inspectorController()->frameDetachedFromParent(m_frame);
3623 
3624     m_client->detachedFromParent2();
3625     setDocumentLoader(0);
3626     m_client->detachedFromParent3();
3627     if (Frame* parent = m_frame->tree()->parent()) {
3628         parent->loader()->closeAndRemoveChild(m_frame);
3629         parent->loader()->scheduleCheckCompleted();
3630     } else {
3631         m_frame->setView(0);
3632         m_frame->pageDestroyed();
3633     }
3634 }
3635 
addExtraFieldsToSubresourceRequest(ResourceRequest & request)3636 void FrameLoader::addExtraFieldsToSubresourceRequest(ResourceRequest& request)
3637 {
3638     addExtraFieldsToRequest(request, m_loadType, false, false);
3639 }
3640 
addExtraFieldsToMainResourceRequest(ResourceRequest & request)3641 void FrameLoader::addExtraFieldsToMainResourceRequest(ResourceRequest& request)
3642 {
3643     addExtraFieldsToRequest(request, m_loadType, true, false);
3644 }
3645 
addExtraFieldsToRequest(ResourceRequest & request,FrameLoadType loadType,bool mainResource,bool cookiePolicyURLFromRequest)3646 void FrameLoader::addExtraFieldsToRequest(ResourceRequest& request, FrameLoadType loadType, bool mainResource, bool cookiePolicyURLFromRequest)
3647 {
3648     // Don't set the cookie policy URL if it's already been set.
3649     // But make sure to set it on all requests, as it has significance beyond the cookie policy for all protocols (<rdar://problem/6616664>).
3650     if (request.firstPartyForCookies().isEmpty()) {
3651         if (mainResource && (isLoadingMainFrame() || cookiePolicyURLFromRequest))
3652             request.setFirstPartyForCookies(request.url());
3653         else if (Document* document = m_frame->document())
3654             request.setFirstPartyForCookies(document->firstPartyForCookies());
3655     }
3656 
3657     // The remaining modifications are only necessary for HTTP and HTTPS.
3658     if (!request.url().isEmpty() && !request.url().protocolInHTTPFamily())
3659         return;
3660 
3661     applyUserAgent(request);
3662 
3663     if (loadType == FrameLoadTypeReload) {
3664         request.setCachePolicy(ReloadIgnoringCacheData);
3665         request.setHTTPHeaderField("Cache-Control", "max-age=0");
3666     } else if (loadType == FrameLoadTypeReloadFromOrigin) {
3667         request.setCachePolicy(ReloadIgnoringCacheData);
3668         request.setHTTPHeaderField("Cache-Control", "no-cache");
3669         request.setHTTPHeaderField("Pragma", "no-cache");
3670     }
3671 
3672     if (mainResource)
3673         request.setHTTPAccept(defaultAcceptHeader);
3674 
3675     // Make sure we send the Origin header.
3676     addHTTPOriginIfNeeded(request, String());
3677 
3678     // Always try UTF-8. If that fails, try frame encoding (if any) and then the default.
3679     // For a newly opened frame with an empty URL, encoding() should not be used, because this methods asks decoder, which uses ISO-8859-1.
3680     Settings* settings = m_frame->settings();
3681     request.setResponseContentDispositionEncodingFallbackArray("UTF-8", m_URL.isEmpty() ? m_encoding : encoding(), settings ? settings->defaultTextEncodingName() : String());
3682 }
3683 
addHTTPOriginIfNeeded(ResourceRequest & request,String origin)3684 void FrameLoader::addHTTPOriginIfNeeded(ResourceRequest& request, String origin)
3685 {
3686     if (!request.httpOrigin().isEmpty())
3687         return;  // Request already has an Origin header.
3688 
3689     // Don't send an Origin header for GET or HEAD to avoid privacy issues.
3690     // For example, if an intranet page has a hyperlink to an external web
3691     // site, we don't want to include the Origin of the request because it
3692     // will leak the internal host name. Similar privacy concerns have lead
3693     // to the widespread suppression of the Referer header at the network
3694     // layer.
3695     if (request.httpMethod() == "GET" || request.httpMethod() == "HEAD")
3696         return;
3697 
3698     // For non-GET and non-HEAD methods, always send an Origin header so the
3699     // server knows we support this feature.
3700 
3701     if (origin.isEmpty()) {
3702         // If we don't know what origin header to attach, we attach the value
3703         // for an empty origin.
3704         origin = SecurityOrigin::createEmpty()->toString();
3705     }
3706 
3707     request.setHTTPOrigin(origin);
3708 }
3709 
committedLoad(DocumentLoader * loader,const char * data,int length)3710 void FrameLoader::committedLoad(DocumentLoader* loader, const char* data, int length)
3711 {
3712 #if ENABLE(ARCHIVE) // ANDROID extension: disabled to reduce code size
3713     if (ArchiveFactory::isArchiveMimeType(loader->response().mimeType()))
3714         return;
3715 #endif
3716     m_client->committedLoad(loader, data, length);
3717 }
3718 
3719 #ifdef ANDROID_USER_GESTURE
loadPostRequest(const ResourceRequest & inRequest,const String & referrer,const String & frameName,bool lockHistory,FrameLoadType loadType,PassRefPtr<Event> event,PassRefPtr<FormState> prpFormState,bool userGesture)3720 void FrameLoader::loadPostRequest(const ResourceRequest& inRequest, const String& referrer, const String& frameName, bool lockHistory, FrameLoadType loadType, PassRefPtr<Event> event, PassRefPtr<FormState> prpFormState, bool userGesture)
3721 #else
3722 void FrameLoader::loadPostRequest(const ResourceRequest& inRequest, const String& referrer, const String& frameName, bool lockHistory, FrameLoadType loadType, PassRefPtr<Event> event, PassRefPtr<FormState> prpFormState)
3723 #endif
3724 {
3725     RefPtr<FormState> formState = prpFormState;
3726 
3727     // When posting, use the NSURLRequestReloadIgnoringCacheData load flag.
3728     // This prevents a potential bug which may cause a page with a form that uses itself
3729     // as an action to be returned from the cache without submitting.
3730 
3731     // FIXME: Where's the code that implements what the comment above says?
3732 
3733     // Previously when this method was reached, the original FrameLoadRequest had been deconstructed to build a
3734     // bunch of parameters that would come in here and then be built back up to a ResourceRequest.  In case
3735     // any caller depends on the immutability of the original ResourceRequest, I'm rebuilding a ResourceRequest
3736     // from scratch as it did all along.
3737     const KURL& url = inRequest.url();
3738     RefPtr<FormData> formData = inRequest.httpBody();
3739     const String& contentType = inRequest.httpContentType();
3740     String origin = inRequest.httpOrigin();
3741 
3742     ResourceRequest workingResourceRequest(url);
3743 #ifdef ANDROID_USER_GESTURE
3744     workingResourceRequest.setUserGesture(userGesture);
3745 #endif
3746 
3747     if (!referrer.isEmpty())
3748         workingResourceRequest.setHTTPReferrer(referrer);
3749     workingResourceRequest.setHTTPOrigin(origin);
3750     workingResourceRequest.setHTTPMethod("POST");
3751     workingResourceRequest.setHTTPBody(formData);
3752     workingResourceRequest.setHTTPContentType(contentType);
3753     addExtraFieldsToRequest(workingResourceRequest, loadType, true, true);
3754 
3755     NavigationAction action(url, loadType, true, event);
3756 
3757     if (!frameName.isEmpty()) {
3758         // The search for a target frame is done earlier in the case of form submission.
3759         if (Frame* targetFrame = formState ? 0 : findFrameForNavigation(frameName))
3760             targetFrame->loader()->loadWithNavigationAction(workingResourceRequest, action, lockHistory, loadType, formState.release());
3761         else
3762             checkNewWindowPolicy(action, workingResourceRequest, formState.release(), frameName);
3763     } else
3764         loadWithNavigationAction(workingResourceRequest, action, lockHistory, loadType, formState.release());
3765 }
3766 
loadResourceSynchronously(const ResourceRequest & request,StoredCredentials storedCredentials,ResourceError & error,ResourceResponse & response,Vector<char> & data)3767 unsigned long FrameLoader::loadResourceSynchronously(const ResourceRequest& request, StoredCredentials storedCredentials, ResourceError& error, ResourceResponse& response, Vector<char>& data)
3768 {
3769     String referrer = m_outgoingReferrer;
3770     if (shouldHideReferrer(request.url(), referrer))
3771         referrer = String();
3772 
3773     ResourceRequest initialRequest = request;
3774     initialRequest.setTimeoutInterval(10);
3775 
3776     if (initialRequest.isConditional())
3777         initialRequest.setCachePolicy(ReloadIgnoringCacheData);
3778     else
3779         initialRequest.setCachePolicy(documentLoader()->request().cachePolicy());
3780 
3781     if (!referrer.isEmpty())
3782         initialRequest.setHTTPReferrer(referrer);
3783     addHTTPOriginIfNeeded(initialRequest, outgoingOrigin());
3784 
3785     if (Page* page = m_frame->page())
3786         initialRequest.setFirstPartyForCookies(page->mainFrame()->loader()->documentLoader()->request().url());
3787     initialRequest.setHTTPUserAgent(client()->userAgent(request.url()));
3788 
3789     unsigned long identifier = 0;
3790     ResourceRequest newRequest(initialRequest);
3791     requestFromDelegate(newRequest, identifier, error);
3792 
3793     if (error.isNull()) {
3794         ASSERT(!newRequest.isNull());
3795 
3796 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
3797         if (!documentLoader()->applicationCacheHost()->maybeLoadSynchronously(newRequest, error, response, data)) {
3798 #endif
3799             ResourceHandle::loadResourceSynchronously(newRequest, storedCredentials, error, response, data, m_frame);
3800 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
3801             documentLoader()->applicationCacheHost()->maybeLoadFallbackSynchronously(newRequest, error, response, data);
3802         }
3803 #endif
3804     }
3805 
3806     sendRemainingDelegateMessages(identifier, response, data.size(), error);
3807     return identifier;
3808 }
3809 
assignIdentifierToInitialRequest(unsigned long identifier,const ResourceRequest & clientRequest)3810 void FrameLoader::assignIdentifierToInitialRequest(unsigned long identifier, const ResourceRequest& clientRequest)
3811 {
3812     return dispatchAssignIdentifierToInitialRequest(identifier, activeDocumentLoader(), clientRequest);
3813 }
3814 
willSendRequest(ResourceLoader * loader,ResourceRequest & clientRequest,const ResourceResponse & redirectResponse)3815 void FrameLoader::willSendRequest(ResourceLoader* loader, ResourceRequest& clientRequest, const ResourceResponse& redirectResponse)
3816 {
3817     applyUserAgent(clientRequest);
3818     dispatchWillSendRequest(loader->documentLoader(), loader->identifier(), clientRequest, redirectResponse);
3819 }
3820 
didReceiveResponse(ResourceLoader * loader,const ResourceResponse & r)3821 void FrameLoader::didReceiveResponse(ResourceLoader* loader, const ResourceResponse& r)
3822 {
3823     activeDocumentLoader()->addResponse(r);
3824 
3825     if (Page* page = m_frame->page())
3826         page->progress()->incrementProgress(loader->identifier(), r);
3827     dispatchDidReceiveResponse(loader->documentLoader(), loader->identifier(), r);
3828 }
3829 
didReceiveData(ResourceLoader * loader,const char * data,int length,int lengthReceived)3830 void FrameLoader::didReceiveData(ResourceLoader* loader, const char* data, int length, int lengthReceived)
3831 {
3832     if (Page* page = m_frame->page())
3833         page->progress()->incrementProgress(loader->identifier(), data, length);
3834     dispatchDidReceiveContentLength(loader->documentLoader(), loader->identifier(), lengthReceived);
3835 }
3836 
didFailToLoad(ResourceLoader * loader,const ResourceError & error)3837 void FrameLoader::didFailToLoad(ResourceLoader* loader, const ResourceError& error)
3838 {
3839     if (Page* page = m_frame->page())
3840         page->progress()->completeProgress(loader->identifier());
3841     if (!error.isNull())
3842         m_client->dispatchDidFailLoading(loader->documentLoader(), loader->identifier(), error);
3843 }
3844 
didLoadResourceByXMLHttpRequest(unsigned long identifier,const ScriptString & sourceString)3845 void FrameLoader::didLoadResourceByXMLHttpRequest(unsigned long identifier, const ScriptString& sourceString)
3846 {
3847     m_client->dispatchDidLoadResourceByXMLHttpRequest(identifier, sourceString);
3848 }
3849 
originalRequest() const3850 const ResourceRequest& FrameLoader::originalRequest() const
3851 {
3852     return activeDocumentLoader()->originalRequestCopy();
3853 }
3854 
receivedMainResourceError(const ResourceError & error,bool isComplete)3855 void FrameLoader::receivedMainResourceError(const ResourceError& error, bool isComplete)
3856 {
3857     // Retain because the stop may release the last reference to it.
3858     RefPtr<Frame> protect(m_frame);
3859 
3860     RefPtr<DocumentLoader> loader = activeDocumentLoader();
3861 
3862     if (isComplete) {
3863         // FIXME: Don't want to do this if an entirely new load is going, so should check
3864         // that both data sources on the frame are either this or nil.
3865         stop();
3866         if (m_client->shouldFallBack(error))
3867             handleFallbackContent();
3868     }
3869 
3870     if (m_state == FrameStateProvisional && m_provisionalDocumentLoader) {
3871         if (m_submittedFormURL == m_provisionalDocumentLoader->originalRequestCopy().url())
3872             m_submittedFormURL = KURL();
3873 
3874         // We might have made a page cache item, but now we're bailing out due to an error before we ever
3875         // transitioned to the new page (before WebFrameState == commit).  The goal here is to restore any state
3876         // so that the existing view (that wenever got far enough to replace) can continue being used.
3877         invalidateCurrentItemCachedPage();
3878 
3879         // Call clientRedirectCancelledOrFinished here so that the frame load delegate is notified that the redirect's
3880         // status has changed, if there was a redirect. The frame load delegate may have saved some state about
3881         // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are definitely
3882         // not going to use this provisional resource, as it was cancelled, notify the frame load delegate that the redirect
3883         // has ended.
3884         if (m_sentRedirectNotification)
3885             clientRedirectCancelledOrFinished(false);
3886     }
3887 
3888 
3889     loader->mainReceivedError(error, isComplete);
3890 }
3891 
callContinueFragmentScrollAfterNavigationPolicy(void * argument,const ResourceRequest & request,PassRefPtr<FormState>,bool shouldContinue)3892 void FrameLoader::callContinueFragmentScrollAfterNavigationPolicy(void* argument,
3893     const ResourceRequest& request, PassRefPtr<FormState>, bool shouldContinue)
3894 {
3895     FrameLoader* loader = static_cast<FrameLoader*>(argument);
3896     loader->continueFragmentScrollAfterNavigationPolicy(request, shouldContinue);
3897 }
3898 
continueFragmentScrollAfterNavigationPolicy(const ResourceRequest & request,bool shouldContinue)3899 void FrameLoader::continueFragmentScrollAfterNavigationPolicy(const ResourceRequest& request, bool shouldContinue)
3900 {
3901     bool isRedirect = m_quickRedirectComing || m_policyLoadType == FrameLoadTypeRedirectWithLockedBackForwardList;
3902     m_quickRedirectComing = false;
3903 
3904     if (!shouldContinue)
3905         return;
3906 
3907     KURL url = request.url();
3908 
3909     m_documentLoader->replaceRequestURLForAnchorScroll(url);
3910     if (!isRedirect && !shouldTreatURLAsSameAsCurrent(url)) {
3911         // NB: must happen after _setURL, since we add based on the current request.
3912         // Must also happen before we openURL and displace the scroll position, since
3913         // adding the BF item will save away scroll state.
3914 
3915         // NB2:  If we were loading a long, slow doc, and the user anchor nav'ed before
3916         // it was done, currItem is now set the that slow doc, and prevItem is whatever was
3917         // before it.  Adding the b/f item will bump the slow doc down to prevItem, even
3918         // though its load is not yet done.  I think this all works out OK, for one because
3919         // we have already saved away the scroll and doc state for the long slow load,
3920         // but it's not an obvious case.
3921 
3922         addHistoryItemForFragmentScroll();
3923     }
3924 
3925     scrollToAnchor(url);
3926 
3927     if (!isRedirect)
3928         // This will clear previousItem from the rest of the frame tree that didn't
3929         // doing any loading. We need to make a pass on this now, since for anchor nav
3930         // we'll not go through a real load and reach Completed state.
3931         checkLoadComplete();
3932 
3933     m_client->dispatchDidChangeLocationWithinPage();
3934     m_client->didFinishLoad();
3935 }
3936 
shouldScrollToAnchor(bool isFormSubmission,FrameLoadType loadType,const KURL & url)3937 bool FrameLoader::shouldScrollToAnchor(bool isFormSubmission, FrameLoadType loadType, const KURL& url)
3938 {
3939     // Should we do anchor navigation within the existing content?
3940 
3941     // We don't do this if we are submitting a form, explicitly reloading,
3942     // currently displaying a frameset, or if the URL does not have a fragment.
3943     // These rules were originally based on what KHTML was doing in KHTMLPart::openURL.
3944 
3945     // FIXME: What about load types other than Standard and Reload?
3946 
3947     return !isFormSubmission
3948         && loadType != FrameLoadTypeReload
3949         && loadType != FrameLoadTypeReloadFromOrigin
3950         && loadType != FrameLoadTypeSame
3951         && !shouldReload(this->url(), url)
3952         // We don't want to just scroll if a link from within a
3953         // frameset is trying to reload the frameset into _top.
3954         && !m_frame->document()->isFrameSet();
3955 }
3956 
checkNewWindowPolicy(const NavigationAction & action,const ResourceRequest & request,PassRefPtr<FormState> formState,const String & frameName)3957 void FrameLoader::checkNewWindowPolicy(const NavigationAction& action, const ResourceRequest& request,
3958     PassRefPtr<FormState> formState, const String& frameName)
3959 {
3960     m_policyCheck.set(request, formState, frameName,
3961         callContinueLoadAfterNewWindowPolicy, this);
3962     m_client->dispatchDecidePolicyForNewWindowAction(&FrameLoader::continueAfterNewWindowPolicy,
3963         action, request, formState, frameName);
3964 }
3965 
continueAfterNewWindowPolicy(PolicyAction policy)3966 void FrameLoader::continueAfterNewWindowPolicy(PolicyAction policy)
3967 {
3968     PolicyCheck check = m_policyCheck;
3969     m_policyCheck.clear();
3970 
3971     switch (policy) {
3972         case PolicyIgnore:
3973             check.clearRequest();
3974             break;
3975         case PolicyDownload:
3976             m_client->startDownload(check.request());
3977             check.clearRequest();
3978             break;
3979         case PolicyUse:
3980             break;
3981     }
3982 
3983     check.call(policy == PolicyUse);
3984 }
3985 
checkNavigationPolicy(const ResourceRequest & request,DocumentLoader * loader,PassRefPtr<FormState> formState,NavigationPolicyDecisionFunction function,void * argument)3986 void FrameLoader::checkNavigationPolicy(const ResourceRequest& request, DocumentLoader* loader,
3987     PassRefPtr<FormState> formState, NavigationPolicyDecisionFunction function, void* argument)
3988 {
3989     NavigationAction action = loader->triggeringAction();
3990     if (action.isEmpty()) {
3991         action = NavigationAction(request.url(), NavigationTypeOther);
3992         loader->setTriggeringAction(action);
3993     }
3994 
3995     // Don't ask more than once for the same request or if we are loading an empty URL.
3996     // This avoids confusion on the part of the client.
3997     if (equalIgnoringHeaderFields(request, loader->lastCheckedRequest()) || (!request.isNull() && request.url().isEmpty())) {
3998         function(argument, request, 0, true);
3999         loader->setLastCheckedRequest(request);
4000         return;
4001     }
4002 
4003     // We are always willing to show alternate content for unreachable URLs;
4004     // treat it like a reload so it maintains the right state for b/f list.
4005     if (loader->substituteData().isValid() && !loader->substituteData().failingURL().isEmpty()) {
4006         if (isBackForwardLoadType(m_policyLoadType))
4007             m_policyLoadType = FrameLoadTypeReload;
4008         function(argument, request, 0, true);
4009         return;
4010     }
4011 
4012     loader->setLastCheckedRequest(request);
4013 
4014     m_policyCheck.set(request, formState.get(), function, argument);
4015 
4016     m_delegateIsDecidingNavigationPolicy = true;
4017     m_client->dispatchDecidePolicyForNavigationAction(&FrameLoader::continueAfterNavigationPolicy,
4018         action, request, formState);
4019     m_delegateIsDecidingNavigationPolicy = false;
4020 }
4021 
continueAfterNavigationPolicy(PolicyAction policy)4022 void FrameLoader::continueAfterNavigationPolicy(PolicyAction policy)
4023 {
4024     PolicyCheck check = m_policyCheck;
4025     m_policyCheck.clear();
4026 
4027     bool shouldContinue = policy == PolicyUse;
4028 
4029     switch (policy) {
4030         case PolicyIgnore:
4031             check.clearRequest();
4032             break;
4033         case PolicyDownload:
4034             m_client->startDownload(check.request());
4035             check.clearRequest();
4036             break;
4037         case PolicyUse: {
4038             ResourceRequest request(check.request());
4039 
4040             if (!m_client->canHandleRequest(request)) {
4041                 handleUnimplementablePolicy(m_client->cannotShowURLError(check.request()));
4042                 check.clearRequest();
4043                 shouldContinue = false;
4044             }
4045             break;
4046         }
4047     }
4048 
4049     check.call(shouldContinue);
4050 }
4051 
callContinueLoadAfterNavigationPolicy(void * argument,const ResourceRequest & request,PassRefPtr<FormState> formState,bool shouldContinue)4052 void FrameLoader::callContinueLoadAfterNavigationPolicy(void* argument,
4053     const ResourceRequest& request, PassRefPtr<FormState> formState, bool shouldContinue)
4054 {
4055     FrameLoader* loader = static_cast<FrameLoader*>(argument);
4056     loader->continueLoadAfterNavigationPolicy(request, formState, shouldContinue);
4057 }
4058 
continueLoadAfterNavigationPolicy(const ResourceRequest &,PassRefPtr<FormState> formState,bool shouldContinue)4059 void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest&, PassRefPtr<FormState> formState, bool shouldContinue)
4060 {
4061     // If we loaded an alternate page to replace an unreachableURL, we'll get in here with a
4062     // nil policyDataSource because loading the alternate page will have passed
4063     // through this method already, nested; otherwise, policyDataSource should still be set.
4064     ASSERT(m_policyDocumentLoader || !m_provisionalDocumentLoader->unreachableURL().isEmpty());
4065 
4066     bool isTargetItem = m_provisionalHistoryItem ? m_provisionalHistoryItem->isTargetItem() : false;
4067 
4068     // Two reasons we can't continue:
4069     //    1) Navigation policy delegate said we can't so request is nil. A primary case of this
4070     //       is the user responding Cancel to the form repost nag sheet.
4071     //    2) User responded Cancel to an alert popped up by the before unload event handler.
4072     // The "before unload" event handler runs only for the main frame.
4073     bool canContinue = shouldContinue && (!isLoadingMainFrame() || m_frame->shouldClose());
4074 
4075     if (!canContinue) {
4076         // If we were waiting for a quick redirect, but the policy delegate decided to ignore it, then we
4077         // need to report that the client redirect was cancelled.
4078         if (m_quickRedirectComing)
4079             clientRedirectCancelledOrFinished(false);
4080 
4081         setPolicyDocumentLoader(0);
4082 
4083         // If the navigation request came from the back/forward menu, and we punt on it, we have the
4084         // problem that we have optimistically moved the b/f cursor already, so move it back.  For sanity,
4085         // we only do this when punting a navigation for the target frame or top-level frame.
4086         if ((isTargetItem || isLoadingMainFrame()) && isBackForwardLoadType(m_policyLoadType))
4087             if (Page* page = m_frame->page()) {
4088                 Frame* mainFrame = page->mainFrame();
4089                 if (HistoryItem* resetItem = mainFrame->loader()->m_currentHistoryItem.get()) {
4090                     page->backForwardList()->goToItem(resetItem);
4091                     Settings* settings = m_frame->settings();
4092                     page->setGlobalHistoryItem((!settings || settings->privateBrowsingEnabled()) ? 0 : resetItem);
4093                 }
4094             }
4095         return;
4096     }
4097 
4098     FrameLoadType type = m_policyLoadType;
4099     stopAllLoaders();
4100 
4101     // <rdar://problem/6250856> - In certain circumstances on pages with multiple frames, stopAllLoaders()
4102     // might detach the current FrameLoader, in which case we should bail on this newly defunct load.
4103     if (!m_frame->page())
4104         return;
4105 
4106 #if ENABLE(JAVASCRIPT_DEBUGGER)
4107     if (Page* page = m_frame->page()) {
4108         if (page->mainFrame() == m_frame)
4109             page->inspectorController()->resumeDebugger();
4110     }
4111 #endif
4112 
4113     setProvisionalDocumentLoader(m_policyDocumentLoader.get());
4114     m_loadType = type;
4115     setState(FrameStateProvisional);
4116 
4117     setPolicyDocumentLoader(0);
4118 
4119     if (isBackForwardLoadType(type) && loadProvisionalItemFromCachedPage())
4120         return;
4121 
4122     if (formState)
4123         m_client->dispatchWillSubmitForm(&FrameLoader::continueLoadAfterWillSubmitForm, formState);
4124     else
4125         continueLoadAfterWillSubmitForm();
4126 }
4127 
4128 
callContinueLoadAfterNewWindowPolicy(void * argument,const ResourceRequest & request,PassRefPtr<FormState> formState,const String & frameName,bool shouldContinue)4129 void FrameLoader::callContinueLoadAfterNewWindowPolicy(void* argument,
4130     const ResourceRequest& request, PassRefPtr<FormState> formState, const String& frameName, bool shouldContinue)
4131 {
4132     FrameLoader* loader = static_cast<FrameLoader*>(argument);
4133     loader->continueLoadAfterNewWindowPolicy(request, formState, frameName, shouldContinue);
4134 }
4135 
continueLoadAfterNewWindowPolicy(const ResourceRequest & request,PassRefPtr<FormState> formState,const String & frameName,bool shouldContinue)4136 void FrameLoader::continueLoadAfterNewWindowPolicy(const ResourceRequest& request,
4137     PassRefPtr<FormState> formState, const String& frameName, bool shouldContinue)
4138 {
4139     if (!shouldContinue)
4140         return;
4141 
4142     RefPtr<Frame> frame = m_frame;
4143     RefPtr<Frame> mainFrame = m_client->dispatchCreatePage();
4144     if (!mainFrame)
4145         return;
4146 
4147     if (frameName != "_blank")
4148         mainFrame->tree()->setName(frameName);
4149 
4150     mainFrame->loader()->setOpenedByDOM();
4151     mainFrame->loader()->m_client->dispatchShow();
4152     mainFrame->loader()->setOpener(frame.get());
4153     mainFrame->loader()->loadWithNavigationAction(request, NavigationAction(), false, FrameLoadTypeStandard, formState);
4154 }
4155 
sendRemainingDelegateMessages(unsigned long identifier,const ResourceResponse & response,int length,const ResourceError & error)4156 void FrameLoader::sendRemainingDelegateMessages(unsigned long identifier, const ResourceResponse& response, int length, const ResourceError& error)
4157 {
4158     if (!response.isNull())
4159         dispatchDidReceiveResponse(m_documentLoader.get(), identifier, response);
4160 
4161     if (length > 0)
4162         dispatchDidReceiveContentLength(m_documentLoader.get(), identifier, length);
4163 
4164     if (error.isNull())
4165         dispatchDidFinishLoading(m_documentLoader.get(), identifier);
4166     else
4167         m_client->dispatchDidFailLoading(m_documentLoader.get(), identifier, error);
4168 }
4169 
requestFromDelegate(ResourceRequest & request,unsigned long & identifier,ResourceError & error)4170 void FrameLoader::requestFromDelegate(ResourceRequest& request, unsigned long& identifier, ResourceError& error)
4171 {
4172     ASSERT(!request.isNull());
4173 
4174     identifier = 0;
4175     if (Page* page = m_frame->page()) {
4176         identifier = page->progress()->createUniqueIdentifier();
4177         dispatchAssignIdentifierToInitialRequest(identifier, m_documentLoader.get(), request);
4178     }
4179 
4180     ResourceRequest newRequest(request);
4181     dispatchWillSendRequest(m_documentLoader.get(), identifier, newRequest, ResourceResponse());
4182 
4183     if (newRequest.isNull())
4184         error = cancelledError(request);
4185     else
4186         error = ResourceError();
4187 
4188     request = newRequest;
4189 }
4190 
loadedResourceFromMemoryCache(const CachedResource * resource)4191 void FrameLoader::loadedResourceFromMemoryCache(const CachedResource* resource)
4192 {
4193     Page* page = m_frame->page();
4194     if (!page)
4195         return;
4196 
4197     page->inspectorController()->didLoadResourceFromMemoryCache(m_documentLoader.get(), resource);
4198 
4199     if (!resource->sendResourceLoadCallbacks() || m_documentLoader->haveToldClientAboutLoad(resource->url()))
4200         return;
4201 
4202     if (!page->areMemoryCacheClientCallsEnabled()) {
4203         m_documentLoader->recordMemoryCacheLoadForFutureClientNotification(resource->url());
4204         m_documentLoader->didTellClientAboutLoad(resource->url());
4205         return;
4206     }
4207 
4208     ResourceRequest request(resource->url());
4209     if (m_client->dispatchDidLoadResourceFromMemoryCache(m_documentLoader.get(), request, resource->response(), resource->encodedSize())) {
4210         m_documentLoader->didTellClientAboutLoad(resource->url());
4211         return;
4212     }
4213 
4214     unsigned long identifier;
4215     ResourceError error;
4216     requestFromDelegate(request, identifier, error);
4217     sendRemainingDelegateMessages(identifier, resource->response(), resource->encodedSize(), error);
4218 }
4219 
applyUserAgent(ResourceRequest & request)4220 void FrameLoader::applyUserAgent(ResourceRequest& request)
4221 {
4222     String userAgent = client()->userAgent(request.url());
4223     ASSERT(!userAgent.isNull());
4224     request.setHTTPUserAgent(userAgent);
4225 }
4226 
shouldInterruptLoadForXFrameOptions(const String & content,const KURL & url)4227 bool FrameLoader::shouldInterruptLoadForXFrameOptions(const String& content, const KURL& url)
4228 {
4229     Frame* topFrame = m_frame->tree()->top();
4230     if (m_frame == topFrame)
4231         return false;
4232 
4233     if (equalIgnoringCase(content, "deny"))
4234         return true;
4235 
4236     if (equalIgnoringCase(content, "sameorigin")) {
4237         RefPtr<SecurityOrigin> origin = SecurityOrigin::create(url);
4238         if (!origin->isSameSchemeHostPort(topFrame->document()->securityOrigin()))
4239             return true;
4240     }
4241 
4242     return false;
4243 }
4244 
canGoBackOrForward(int distance) const4245 bool FrameLoader::canGoBackOrForward(int distance) const
4246 {
4247     if (Page* page = m_frame->page()) {
4248         if (distance == 0)
4249             return true;
4250         if (distance > 0 && distance <= page->backForwardList()->forwardListCount())
4251             return true;
4252         if (distance < 0 && -distance <= page->backForwardList()->backListCount())
4253             return true;
4254     }
4255     return false;
4256 }
4257 
getHistoryLength()4258 int FrameLoader::getHistoryLength()
4259 {
4260     if (Page* page = m_frame->page())
4261         return page->backForwardList()->backListCount() + 1;
4262     return 0;
4263 }
4264 
addHistoryItemForFragmentScroll()4265 void FrameLoader::addHistoryItemForFragmentScroll()
4266 {
4267     addBackForwardItemClippedAtTarget(false);
4268 }
4269 
loadProvisionalItemFromCachedPage()4270 bool FrameLoader::loadProvisionalItemFromCachedPage()
4271 {
4272     RefPtr<CachedPage> cachedPage = pageCache()->get(m_provisionalHistoryItem.get());
4273     if (!cachedPage || !cachedPage->document())
4274         return false;
4275     provisionalDocumentLoader()->loadFromCachedPage(cachedPage.release());
4276     return true;
4277 }
4278 
cachePageForHistoryItem(HistoryItem * item)4279 void FrameLoader::cachePageForHistoryItem(HistoryItem* item)
4280 {
4281     if (!canCachePage() || item->isInPageCache())
4282         return;
4283 
4284     if (Page* page = m_frame->page()) {
4285         RefPtr<CachedPage> cachedPage = CachedPage::create(page);
4286         pageCache()->add(item, cachedPage.release());
4287     }
4288 }
4289 
shouldTreatURLAsSameAsCurrent(const KURL & url) const4290 bool FrameLoader::shouldTreatURLAsSameAsCurrent(const KURL& url) const
4291 {
4292     if (!m_currentHistoryItem)
4293         return false;
4294     return url == m_currentHistoryItem->url() || url == m_currentHistoryItem->originalURL();
4295 }
4296 
createHistoryItem(bool useOriginal)4297 PassRefPtr<HistoryItem> FrameLoader::createHistoryItem(bool useOriginal)
4298 {
4299     DocumentLoader* docLoader = documentLoader();
4300 
4301     KURL unreachableURL = docLoader ? docLoader->unreachableURL() : KURL();
4302 
4303     KURL url;
4304     KURL originalURL;
4305 
4306     if (!unreachableURL.isEmpty()) {
4307         url = unreachableURL;
4308         originalURL = unreachableURL;
4309     } else {
4310         originalURL = docLoader ? docLoader->originalURL() : KURL();
4311         if (useOriginal)
4312             url = originalURL;
4313         else if (docLoader)
4314             url = docLoader->requestURL();
4315     }
4316 
4317     LOG(History, "WebCoreHistory: Creating item for %s", url.string().ascii().data());
4318 
4319     // Frames that have never successfully loaded any content
4320     // may have no URL at all. Currently our history code can't
4321     // deal with such things, so we nip that in the bud here.
4322     // Later we may want to learn to live with nil for URL.
4323     // See bug 3368236 and related bugs for more information.
4324     if (url.isEmpty())
4325         url = blankURL();
4326     if (originalURL.isEmpty())
4327         originalURL = blankURL();
4328 
4329     Frame* parentFrame = m_frame->tree()->parent();
4330     String parent = parentFrame ? parentFrame->tree()->name() : "";
4331     String title = docLoader ? docLoader->title() : "";
4332 
4333     RefPtr<HistoryItem> item = HistoryItem::create(url, m_frame->tree()->name(), parent, title);
4334     item->setOriginalURLString(originalURL.string());
4335 
4336     if (!unreachableURL.isEmpty() || !docLoader || docLoader->response().httpStatusCode() >= 400)
4337         item->setLastVisitWasFailure(true);
4338 
4339     // Save form state if this is a POST
4340     if (docLoader) {
4341         if (useOriginal)
4342             item->setFormInfoFromRequest(docLoader->originalRequest());
4343         else
4344             item->setFormInfoFromRequest(docLoader->request());
4345     }
4346 
4347     // Set the item for which we will save document state
4348     m_previousHistoryItem = m_currentHistoryItem;
4349     m_currentHistoryItem = item;
4350 
4351     return item.release();
4352 }
4353 
addBackForwardItemClippedAtTarget(bool doClip)4354 void FrameLoader::addBackForwardItemClippedAtTarget(bool doClip)
4355 {
4356     // In the case of saving state about a page with frames, we store a tree of items that mirrors the frame tree.
4357     // The item that was the target of the user's navigation is designated as the "targetItem".
4358     // When this function is called with doClip=true we're able to create the whole tree except for the target's children,
4359     // which will be loaded in the future. That part of the tree will be filled out as the child loads are committed.
4360 
4361     Page* page = m_frame->page();
4362     if (!page)
4363         return;
4364 
4365     if (documentLoader()->urlForHistory().isEmpty())
4366         return;
4367 
4368     Frame* mainFrame = page->mainFrame();
4369     ASSERT(mainFrame);
4370     FrameLoader* frameLoader = mainFrame->loader();
4371 
4372     if (!frameLoader->m_didPerformFirstNavigation && page->backForwardList()->entries().size() == 1) {
4373         frameLoader->m_didPerformFirstNavigation = true;
4374         m_client->didPerformFirstNavigation();
4375     }
4376 
4377     RefPtr<HistoryItem> item = frameLoader->createHistoryItemTree(m_frame, doClip);
4378     LOG(BackForward, "WebCoreBackForward - Adding backforward item %p for frame %s", item.get(), documentLoader()->url().string().ascii().data());
4379     page->backForwardList()->addItem(item);
4380 }
4381 
createHistoryItemTree(Frame * targetFrame,bool clipAtTarget)4382 PassRefPtr<HistoryItem> FrameLoader::createHistoryItemTree(Frame* targetFrame, bool clipAtTarget)
4383 {
4384     RefPtr<HistoryItem> bfItem = createHistoryItem(m_frame->tree()->parent() ? true : false);
4385     if (m_previousHistoryItem)
4386         saveScrollPositionAndViewStateToItem(m_previousHistoryItem.get());
4387     if (!(clipAtTarget && m_frame == targetFrame)) {
4388         // save frame state for items that aren't loading (khtml doesn't save those)
4389         saveDocumentState();
4390         for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) {
4391             FrameLoader* childLoader = child->loader();
4392             bool hasChildLoaded = childLoader->frameHasLoaded();
4393 
4394             // If the child is a frame corresponding to an <object> element that never loaded,
4395             // we don't want to create a history item, because that causes fallback content
4396             // to be ignored on reload.
4397 
4398             if (!(!hasChildLoaded && childLoader->isHostedByObjectElement()))
4399                 bfItem->addChildItem(childLoader->createHistoryItemTree(targetFrame, clipAtTarget));
4400         }
4401     }
4402     if (m_frame == targetFrame)
4403         bfItem->setIsTargetItem(true);
4404     return bfItem;
4405 }
4406 
findFrameForNavigation(const AtomicString & name)4407 Frame* FrameLoader::findFrameForNavigation(const AtomicString& name)
4408 {
4409     Frame* frame = m_frame->tree()->find(name);
4410     if (!shouldAllowNavigation(frame))
4411         return 0;
4412     return frame;
4413 }
4414 
saveScrollPositionAndViewStateToItem(HistoryItem * item)4415 void FrameLoader::saveScrollPositionAndViewStateToItem(HistoryItem* item)
4416 {
4417     if (!item || !m_frame->view())
4418         return;
4419 
4420     item->setScrollPoint(m_frame->view()->scrollPosition());
4421     // FIXME: It would be great to work out a way to put this code in WebCore instead of calling through to the client.
4422     m_client->saveViewStateToItem(item);
4423 }
4424 
4425 /*
4426  There is a race condition between the layout and load completion that affects restoring the scroll position.
4427  We try to restore the scroll position at both the first layout and upon load completion.
4428 
4429  1) If first layout happens before the load completes, we want to restore the scroll position then so that the
4430  first time we draw the page is already scrolled to the right place, instead of starting at the top and later
4431  jumping down.  It is possible that the old scroll position is past the part of the doc laid out so far, in
4432  which case the restore silent fails and we will fix it in when we try to restore on doc completion.
4433  2) If the layout happens after the load completes, the attempt to restore at load completion time silently
4434  fails.  We then successfully restore it when the layout happens.
4435 */
restoreScrollPositionAndViewState()4436 void FrameLoader::restoreScrollPositionAndViewState()
4437 {
4438     if (!m_committedFirstRealDocumentLoad)
4439         return;
4440 
4441     ASSERT(m_currentHistoryItem);
4442 
4443     // FIXME: As the ASSERT attests, it seems we should always have a currentItem here.
4444     // One counterexample is <rdar://problem/4917290>
4445     // For now, to cover this issue in release builds, there is no technical harm to returning
4446     // early and from a user standpoint - as in the above radar - the previous page load failed
4447     // so there *is* no scroll or view state to restore!
4448     if (!m_currentHistoryItem)
4449         return;
4450 
4451     // FIXME: It would be great to work out a way to put this code in WebCore instead of calling
4452     // through to the client. It's currently used only for the PDF view on Mac.
4453     m_client->restoreViewState();
4454 
4455     if (FrameView* view = m_frame->view())
4456         if (!view->wasScrolledByUser())
4457             view->setScrollPosition(m_currentHistoryItem->scrollPoint());
4458 }
4459 
invalidateCurrentItemCachedPage()4460 void FrameLoader::invalidateCurrentItemCachedPage()
4461 {
4462     // When we are pre-commit, the currentItem is where the pageCache data resides
4463     CachedPage* cachedPage = pageCache()->get(m_currentHistoryItem.get());
4464 
4465     // FIXME: This is a grotesque hack to fix <rdar://problem/4059059> Crash in RenderFlow::detach
4466     // Somehow the PageState object is not properly updated, and is holding onto a stale document.
4467     // Both Xcode and FileMaker see this crash, Safari does not.
4468 
4469     ASSERT(!cachedPage || cachedPage->document() == m_frame->document());
4470     if (cachedPage && cachedPage->document() == m_frame->document()) {
4471         cachedPage->document()->setInPageCache(false);
4472         cachedPage->clear();
4473     }
4474 
4475     if (cachedPage)
4476         pageCache()->remove(m_currentHistoryItem.get());
4477 }
4478 
saveDocumentState()4479 void FrameLoader::saveDocumentState()
4480 {
4481     if (m_creatingInitialEmptyDocument)
4482         return;
4483 
4484     // For a standard page load, we will have a previous item set, which will be used to
4485     // store the form state.  However, in some cases we will have no previous item, and
4486     // the current item is the right place to save the state.  One example is when we
4487     // detach a bunch of frames because we are navigating from a site with frames to
4488     // another site.  Another is when saving the frame state of a frame that is not the
4489     // target of the current navigation (if we even decide to save with that granularity).
4490 
4491     // Because of previousItem's "masking" of currentItem for this purpose, it's important
4492     // that previousItem be cleared at the end of a page transition.  We leverage the
4493     // checkLoadComplete recursion to achieve this goal.
4494 
4495     HistoryItem* item = m_previousHistoryItem ? m_previousHistoryItem.get() : m_currentHistoryItem.get();
4496     if (!item)
4497         return;
4498 
4499     Document* document = m_frame->document();
4500     ASSERT(document);
4501 
4502     if (item->isCurrentDocument(document)) {
4503         LOG(Loading, "WebCoreLoading %s: saving form state to %p", m_frame->tree()->name().string().utf8().data(), item);
4504         item->setDocumentState(document->formElementsState());
4505     }
4506 }
4507 
4508 // Loads content into this frame, as specified by history item
loadItem(HistoryItem * item,FrameLoadType loadType)4509 void FrameLoader::loadItem(HistoryItem* item, FrameLoadType loadType)
4510 {
4511     if (!m_frame->page())
4512         return;
4513 
4514     KURL itemURL = item->url();
4515     KURL itemOriginalURL = item->originalURL();
4516     KURL currentURL;
4517     if (documentLoader())
4518         currentURL = documentLoader()->url();
4519     RefPtr<FormData> formData = item->formData();
4520 
4521     // Are we navigating to an anchor within the page?
4522     // Note if we have child frames we do a real reload, since the child frames might not
4523     // match our current frame structure, or they might not have the right content.  We could
4524     // check for all that as an additional optimization.
4525     // We also do not do anchor-style navigation if we're posting a form or navigating from
4526     // a page that was resulted from a form post.
4527     bool shouldScroll = !formData && !(m_currentHistoryItem && m_currentHistoryItem->formData()) && urlsMatchItem(item);
4528 
4529 #if ENABLE(WML)
4530     // All WML decks should go through the real load mechanism, not the scroll-to-anchor code
4531     if (frameContainsWMLContent(m_frame))
4532         shouldScroll = false;
4533 #endif
4534 
4535     if (shouldScroll) {
4536         // Must do this maintenance here, since we don't go through a real page reload
4537         saveScrollPositionAndViewStateToItem(m_currentHistoryItem.get());
4538 
4539         if (FrameView* view = m_frame->view())
4540             view->setWasScrolledByUser(false);
4541 
4542         m_currentHistoryItem = item;
4543 
4544         // FIXME: Form state might need to be saved here too.
4545 
4546         // We always call scrollToAnchor here, even if the URL doesn't have an
4547         // anchor fragment. This is so we'll keep the WebCore Frame's URL up-to-date.
4548         scrollToAnchor(item->url());
4549 
4550         // must do this maintenance here, since we don't go through a real page reload
4551         restoreScrollPositionAndViewState();
4552 
4553         // Fake the URL change by updating the data source's request.  This will no longer
4554         // be necessary if we do the better fix described above.
4555         documentLoader()->replaceRequestURLForAnchorScroll(itemURL);
4556 
4557         m_client->dispatchDidChangeLocationWithinPage();
4558 
4559         // FrameLoaderClient::didFinishLoad() tells the internal load delegate the load finished with no error
4560         m_client->didFinishLoad();
4561     } else {
4562         // Remember this item so we can traverse any child items as child frames load
4563         m_provisionalHistoryItem = item;
4564 
4565         bool inPageCache = false;
4566 
4567         // Check if we'll be using the page cache.  We only use the page cache
4568         // if one exists and it is less than _backForwardCacheExpirationInterval
4569         // seconds old.  If the cache is expired it gets flushed here.
4570         if (RefPtr<CachedPage> cachedPage = pageCache()->get(item)) {
4571             double interval = currentTime() - cachedPage->timeStamp();
4572 
4573             // FIXME: 1800 should not be hardcoded, it should come from
4574             // WebKitBackForwardCacheExpirationIntervalKey in WebKit.
4575             // Or we should remove WebKitBackForwardCacheExpirationIntervalKey.
4576             if (interval <= 1800) {
4577                 loadWithDocumentLoader(cachedPage->documentLoader(), loadType, 0);
4578                 inPageCache = true;
4579             } else {
4580                 LOG(PageCache, "Not restoring page for %s from back/forward cache because cache entry has expired", m_provisionalHistoryItem->url().string().ascii().data());
4581                 pageCache()->remove(item);
4582             }
4583         }
4584 
4585         if (!inPageCache) {
4586             bool addedExtraFields = false;
4587             ResourceRequest request(itemURL);
4588 
4589             if (!item->referrer().isNull())
4590                 request.setHTTPReferrer(item->referrer());
4591 
4592             // If this was a repost that failed the page cache, we might try to repost the form.
4593             NavigationAction action;
4594             if (formData) {
4595 
4596                 formData->generateFiles(m_frame->page()->chrome()->client());
4597 
4598                 request.setHTTPMethod("POST");
4599                 request.setHTTPBody(formData);
4600                 request.setHTTPContentType(item->formContentType());
4601                 RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::createFromString(item->referrer());
4602                 addHTTPOriginIfNeeded(request, securityOrigin->toString());
4603 
4604                 // Make sure to add extra fields to the request after the Origin header is added for the FormData case.
4605                 // See https://bugs.webkit.org/show_bug.cgi?id=22194 for more discussion.
4606                 addExtraFieldsToRequest(request, m_loadType, true, formData);
4607                 addedExtraFields = true;
4608 
4609                 // FIXME: Slight hack to test if the NSURL cache contains the page we're going to.
4610                 // We want to know this before talking to the policy delegate, since it affects whether
4611                 // we show the DoYouReallyWantToRepost nag.
4612                 //
4613                 // This trick has a small bug (3123893) where we might find a cache hit, but then
4614                 // have the item vanish when we try to use it in the ensuing nav.  This should be
4615                 // extremely rare, but in that case the user will get an error on the navigation.
4616 
4617                 if (ResourceHandle::willLoadFromCache(request, m_frame))
4618                     action = NavigationAction(itemURL, loadType, false);
4619                 else {
4620                     request.setCachePolicy(ReloadIgnoringCacheData);
4621                     action = NavigationAction(itemURL, NavigationTypeFormResubmitted);
4622                 }
4623             } else {
4624                 switch (loadType) {
4625                     case FrameLoadTypeReload:
4626                     case FrameLoadTypeReloadFromOrigin:
4627                         request.setCachePolicy(ReloadIgnoringCacheData);
4628                         break;
4629                     case FrameLoadTypeBack:
4630                     case FrameLoadTypeBackWMLDeckNotAccessible:
4631                     case FrameLoadTypeForward:
4632                     case FrameLoadTypeIndexedBackForward:
4633                         if (itemURL.protocol() != "https")
4634                             request.setCachePolicy(ReturnCacheDataElseLoad);
4635                         break;
4636                     case FrameLoadTypeStandard:
4637                     case FrameLoadTypeRedirectWithLockedBackForwardList:
4638                         break;
4639                     case FrameLoadTypeSame:
4640                     default:
4641                         ASSERT_NOT_REACHED();
4642                 }
4643 
4644                 action = NavigationAction(itemOriginalURL, loadType, false);
4645             }
4646 
4647             if (!addedExtraFields)
4648                 addExtraFieldsToRequest(request, m_loadType, true, formData);
4649 
4650             loadWithNavigationAction(request, action, false, loadType, 0);
4651         }
4652     }
4653 }
4654 
4655 // Walk the frame tree and ensure that the URLs match the URLs in the item.
urlsMatchItem(HistoryItem * item) const4656 bool FrameLoader::urlsMatchItem(HistoryItem* item) const
4657 {
4658     const KURL& currentURL = documentLoader()->url();
4659     if (!equalIgnoringFragmentIdentifier(currentURL, item->url()))
4660         return false;
4661 
4662     const HistoryItemVector& childItems = item->children();
4663 
4664     unsigned size = childItems.size();
4665     for (unsigned i = 0; i < size; ++i) {
4666         Frame* childFrame = m_frame->tree()->child(childItems[i]->target());
4667         if (childFrame && !childFrame->loader()->urlsMatchItem(childItems[i].get()))
4668             return false;
4669     }
4670 
4671     return true;
4672 }
4673 
4674 // Main funnel for navigating to a previous location (back/forward, non-search snap-back)
4675 // This includes recursion to handle loading into framesets properly
goToItem(HistoryItem * targetItem,FrameLoadType type)4676 void FrameLoader::goToItem(HistoryItem* targetItem, FrameLoadType type)
4677 {
4678     ASSERT(!m_frame->tree()->parent());
4679 
4680     // shouldGoToHistoryItem is a private delegate method. This is needed to fix:
4681     // <rdar://problem/3951283> can view pages from the back/forward cache that should be disallowed by Parental Controls
4682     // Ultimately, history item navigations should go through the policy delegate. That's covered in:
4683     // <rdar://problem/3979539> back/forward cache navigations should consult policy delegate
4684     Page* page = m_frame->page();
4685     if (!page)
4686         return;
4687     if (!m_client->shouldGoToHistoryItem(targetItem))
4688         return;
4689 
4690     // Set the BF cursor before commit, which lets the user quickly click back/forward again.
4691     // - plus, it only makes sense for the top level of the operation through the frametree,
4692     // as opposed to happening for some/one of the page commits that might happen soon
4693     BackForwardList* bfList = page->backForwardList();
4694     HistoryItem* currentItem = bfList->currentItem();
4695     bfList->goToItem(targetItem);
4696     Settings* settings = m_frame->settings();
4697     page->setGlobalHistoryItem((!settings || settings->privateBrowsingEnabled()) ? 0 : targetItem);
4698     recursiveGoToItem(targetItem, currentItem, type);
4699 }
4700 
4701 // The general idea here is to traverse the frame tree and the item tree in parallel,
4702 // tracking whether each frame already has the content the item requests.  If there is
4703 // a match (by URL), we just restore scroll position and recurse.  Otherwise we must
4704 // reload that frame, and all its kids.
recursiveGoToItem(HistoryItem * item,HistoryItem * fromItem,FrameLoadType type)4705 void FrameLoader::recursiveGoToItem(HistoryItem* item, HistoryItem* fromItem, FrameLoadType type)
4706 {
4707     ASSERT(item);
4708     ASSERT(fromItem);
4709 
4710     KURL itemURL = item->url();
4711     KURL currentURL;
4712     if (documentLoader())
4713         currentURL = documentLoader()->url();
4714 
4715     // Always reload the target frame of the item we're going to.  This ensures that we will
4716     // do -some- load for the transition, which means a proper notification will be posted
4717     // to the app.
4718     // The exact URL has to match, including fragment.  We want to go through the _load
4719     // method, even if to do a within-page navigation.
4720     // The current frame tree and the frame tree snapshot in the item have to match.
4721     if (!item->isTargetItem() &&
4722         itemURL == currentURL &&
4723         ((m_frame->tree()->name().isEmpty() && item->target().isEmpty()) || m_frame->tree()->name() == item->target()) &&
4724         childFramesMatchItem(item))
4725     {
4726         // This content is good, so leave it alone and look for children that need reloading
4727         // Save form state (works from currentItem, since prevItem is nil)
4728         ASSERT(!m_previousHistoryItem);
4729         saveDocumentState();
4730         saveScrollPositionAndViewStateToItem(m_currentHistoryItem.get());
4731 
4732         if (FrameView* view = m_frame->view())
4733             view->setWasScrolledByUser(false);
4734 
4735         m_currentHistoryItem = item;
4736 
4737         // Restore form state (works from currentItem)
4738         restoreDocumentState();
4739 
4740         // Restore the scroll position (we choose to do this rather than going back to the anchor point)
4741         restoreScrollPositionAndViewState();
4742 
4743         const HistoryItemVector& childItems = item->children();
4744 
4745         int size = childItems.size();
4746         for (int i = 0; i < size; ++i) {
4747             String childFrameName = childItems[i]->target();
4748             HistoryItem* fromChildItem = fromItem->childItemWithTarget(childFrameName);
4749             ASSERT(fromChildItem || fromItem->isTargetItem());
4750             Frame* childFrame = m_frame->tree()->child(childFrameName);
4751             ASSERT(childFrame);
4752             childFrame->loader()->recursiveGoToItem(childItems[i].get(), fromChildItem, type);
4753         }
4754     } else {
4755         loadItem(item, type);
4756     }
4757 }
4758 
4759 // helper method that determines whether the subframes described by the item's subitems
4760 // match our own current frameset
childFramesMatchItem(HistoryItem * item) const4761 bool FrameLoader::childFramesMatchItem(HistoryItem* item) const
4762 {
4763     const HistoryItemVector& childItems = item->children();
4764     if (childItems.size() != m_frame->tree()->childCount())
4765         return false;
4766 
4767     unsigned size = childItems.size();
4768     for (unsigned i = 0; i < size; ++i) {
4769         if (!m_frame->tree()->child(childItems[i]->target()))
4770             return false;
4771     }
4772 
4773     // Found matches for all item targets
4774     return true;
4775 }
4776 
4777 // There are 3 things you might think of as "history", all of which are handled by these functions.
4778 //
4779 //     1) Back/forward: The m_currentHistoryItem is part of this mechanism.
4780 //     2) Global history: Handled by the client.
4781 //     3) Visited links: Handled by the PageGroup.
4782 
updateHistoryForStandardLoad()4783 void FrameLoader::updateHistoryForStandardLoad()
4784 {
4785     LOG(History, "WebCoreHistory: Updating History for Standard Load in frame %s", documentLoader()->url().string().ascii().data());
4786 
4787     Settings* settings = m_frame->settings();
4788     bool needPrivacy = !settings || settings->privateBrowsingEnabled();
4789     const KURL& historyURL = documentLoader()->urlForHistory();
4790 
4791     if (!documentLoader()->isClientRedirect()) {
4792         if (!historyURL.isEmpty()) {
4793             addBackForwardItemClippedAtTarget(true);
4794             if (!needPrivacy) {
4795                 m_client->updateGlobalHistory();
4796                 m_documentLoader->setDidCreateGlobalHistoryEntry(true);
4797                 if (m_documentLoader->unreachableURL().isEmpty())
4798                     m_client->updateGlobalHistoryRedirectLinks();
4799             }
4800             if (Page* page = m_frame->page())
4801                 page->setGlobalHistoryItem(needPrivacy ? 0 : page->backForwardList()->currentItem());
4802         }
4803     } else if (documentLoader()->unreachableURL().isEmpty() && m_currentHistoryItem) {
4804         m_currentHistoryItem->setURL(documentLoader()->url());
4805         m_currentHistoryItem->setFormInfoFromRequest(documentLoader()->request());
4806     }
4807 
4808     if (!historyURL.isEmpty() && !needPrivacy) {
4809         if (Page* page = m_frame->page())
4810             page->group().addVisitedLink(historyURL);
4811 
4812         if (!m_documentLoader->didCreateGlobalHistoryEntry() && documentLoader()->unreachableURL().isEmpty() && !url().isEmpty())
4813             m_client->updateGlobalHistoryRedirectLinks();
4814     }
4815 }
4816 
updateHistoryForClientRedirect()4817 void FrameLoader::updateHistoryForClientRedirect()
4818 {
4819 #if !LOG_DISABLED
4820     if (documentLoader())
4821         LOG(History, "WebCoreHistory: Updating History for client redirect in frame %s", documentLoader()->title().utf8().data());
4822 #endif
4823 
4824     // Clear out form data so we don't try to restore it into the incoming page.  Must happen after
4825     // webcore has closed the URL and saved away the form state.
4826     if (m_currentHistoryItem) {
4827         m_currentHistoryItem->clearDocumentState();
4828         m_currentHistoryItem->clearScrollPoint();
4829     }
4830 
4831     Settings* settings = m_frame->settings();
4832     bool needPrivacy = !settings || settings->privateBrowsingEnabled();
4833     const KURL& historyURL = documentLoader()->urlForHistory();
4834 
4835     if (!historyURL.isEmpty() && !needPrivacy) {
4836         if (Page* page = m_frame->page())
4837             page->group().addVisitedLink(historyURL);
4838     }
4839 }
4840 
updateHistoryForBackForwardNavigation()4841 void FrameLoader::updateHistoryForBackForwardNavigation()
4842 {
4843 #if !LOG_DISABLED
4844     if (documentLoader())
4845         LOG(History, "WebCoreHistory: Updating History for back/forward navigation in frame %s", documentLoader()->title().utf8().data());
4846 #endif
4847 
4848     // Must grab the current scroll position before disturbing it
4849     saveScrollPositionAndViewStateToItem(m_previousHistoryItem.get());
4850 }
4851 
updateHistoryForReload()4852 void FrameLoader::updateHistoryForReload()
4853 {
4854 #if !LOG_DISABLED
4855     if (documentLoader())
4856         LOG(History, "WebCoreHistory: Updating History for reload in frame %s", documentLoader()->title().utf8().data());
4857 #endif
4858 
4859     if (m_currentHistoryItem) {
4860         pageCache()->remove(m_currentHistoryItem.get());
4861 
4862         if (loadType() == FrameLoadTypeReload || loadType() == FrameLoadTypeReloadFromOrigin)
4863             saveScrollPositionAndViewStateToItem(m_currentHistoryItem.get());
4864 
4865         // Sometimes loading a page again leads to a different result because of cookies. Bugzilla 4072
4866         if (documentLoader()->unreachableURL().isEmpty())
4867             m_currentHistoryItem->setURL(documentLoader()->requestURL());
4868     }
4869 }
4870 
updateHistoryForRedirectWithLockedBackForwardList()4871 void FrameLoader::updateHistoryForRedirectWithLockedBackForwardList()
4872 {
4873 #if !LOG_DISABLED
4874     if (documentLoader())
4875         LOG(History, "WebCoreHistory: Updating History for redirect load in frame %s", documentLoader()->title().utf8().data());
4876 #endif
4877 
4878     Settings* settings = m_frame->settings();
4879     bool needPrivacy = !settings || settings->privateBrowsingEnabled();
4880     const KURL& historyURL = documentLoader()->urlForHistory();
4881 
4882     if (documentLoader()->isClientRedirect()) {
4883         if (!m_currentHistoryItem && !m_frame->tree()->parent()) {
4884             if (!historyURL.isEmpty()) {
4885                 addBackForwardItemClippedAtTarget(true);
4886                 if (!needPrivacy) {
4887                     m_client->updateGlobalHistory();
4888                     m_documentLoader->setDidCreateGlobalHistoryEntry(true);
4889                     if (m_documentLoader->unreachableURL().isEmpty())
4890                         m_client->updateGlobalHistoryRedirectLinks();
4891                 }
4892                 if (Page* page = m_frame->page())
4893                     page->setGlobalHistoryItem(needPrivacy ? 0 : page->backForwardList()->currentItem());
4894             }
4895         }
4896         if (m_currentHistoryItem) {
4897             m_currentHistoryItem->setURL(documentLoader()->url());
4898             m_currentHistoryItem->setFormInfoFromRequest(documentLoader()->request());
4899         }
4900     } else {
4901         Frame* parentFrame = m_frame->tree()->parent();
4902         if (parentFrame && parentFrame->loader()->m_currentHistoryItem)
4903             parentFrame->loader()->m_currentHistoryItem->setChildItem(createHistoryItem(true));
4904     }
4905 
4906     if (!historyURL.isEmpty() && !needPrivacy) {
4907         if (Page* page = m_frame->page())
4908             page->group().addVisitedLink(historyURL);
4909 
4910         if (!m_documentLoader->didCreateGlobalHistoryEntry() && documentLoader()->unreachableURL().isEmpty() && !url().isEmpty())
4911             m_client->updateGlobalHistoryRedirectLinks();
4912     }
4913 }
4914 
updateHistoryForCommit()4915 void FrameLoader::updateHistoryForCommit()
4916 {
4917 #if !LOG_DISABLED
4918     if (documentLoader())
4919         LOG(History, "WebCoreHistory: Updating History for commit in frame %s", documentLoader()->title().utf8().data());
4920 #endif
4921     FrameLoadType type = loadType();
4922     if (isBackForwardLoadType(type) ||
4923         ((type == FrameLoadTypeReload || type == FrameLoadTypeReloadFromOrigin) && !provisionalDocumentLoader()->unreachableURL().isEmpty())) {
4924         // Once committed, we want to use current item for saving DocState, and
4925         // the provisional item for restoring state.
4926         // Note previousItem must be set before we close the URL, which will
4927         // happen when the data source is made non-provisional below
4928         m_previousHistoryItem = m_currentHistoryItem;
4929         ASSERT(m_provisionalHistoryItem);
4930         m_currentHistoryItem = m_provisionalHistoryItem;
4931         m_provisionalHistoryItem = 0;
4932     }
4933 }
4934 
updateHistoryForAnchorScroll()4935 void FrameLoader::updateHistoryForAnchorScroll()
4936 {
4937     if (m_URL.isEmpty())
4938         return;
4939 
4940     Settings* settings = m_frame->settings();
4941     if (!settings || settings->privateBrowsingEnabled())
4942         return;
4943 
4944     Page* page = m_frame->page();
4945     if (!page)
4946         return;
4947 
4948     page->group().addVisitedLink(m_URL);
4949 }
4950 
4951 // Walk the frame tree, telling all frames to save their form state into their current
4952 // history item.
saveDocumentAndScrollState()4953 void FrameLoader::saveDocumentAndScrollState()
4954 {
4955     for (Frame* frame = m_frame; frame; frame = frame->tree()->traverseNext(m_frame)) {
4956         frame->loader()->saveDocumentState();
4957         frame->loader()->saveScrollPositionAndViewStateToItem(frame->loader()->currentHistoryItem());
4958     }
4959 }
4960 
currentHistoryItem()4961 HistoryItem* FrameLoader::currentHistoryItem()
4962 {
4963     return m_currentHistoryItem.get();
4964 }
4965 
setCurrentHistoryItem(PassRefPtr<HistoryItem> item)4966 void FrameLoader::setCurrentHistoryItem(PassRefPtr<HistoryItem> item)
4967 {
4968     m_currentHistoryItem = item;
4969 }
4970 
setMainDocumentError(DocumentLoader * loader,const ResourceError & error)4971 void FrameLoader::setMainDocumentError(DocumentLoader* loader, const ResourceError& error)
4972 {
4973     m_client->setMainDocumentError(loader, error);
4974 }
4975 
mainReceivedCompleteError(DocumentLoader * loader,const ResourceError &)4976 void FrameLoader::mainReceivedCompleteError(DocumentLoader* loader, const ResourceError&)
4977 {
4978     loader->setPrimaryLoadComplete(true);
4979     m_client->dispatchDidLoadMainResource(activeDocumentLoader());
4980     checkCompleted();
4981     if (m_frame->page())
4982         checkLoadComplete();
4983 }
4984 
mainReceivedError(const ResourceError & error,bool isComplete)4985 void FrameLoader::mainReceivedError(const ResourceError& error, bool isComplete)
4986 {
4987     activeDocumentLoader()->mainReceivedError(error, isComplete);
4988 }
4989 
cancelledError(const ResourceRequest & request) const4990 ResourceError FrameLoader::cancelledError(const ResourceRequest& request) const
4991 {
4992     ResourceError error = m_client->cancelledError(request);
4993     error.setIsCancellation(true);
4994     return error;
4995 }
4996 
blockedError(const ResourceRequest & request) const4997 ResourceError FrameLoader::blockedError(const ResourceRequest& request) const
4998 {
4999     return m_client->blockedError(request);
5000 }
5001 
cannotShowURLError(const ResourceRequest & request) const5002 ResourceError FrameLoader::cannotShowURLError(const ResourceRequest& request) const
5003 {
5004     return m_client->cannotShowURLError(request);
5005 }
5006 
fileDoesNotExistError(const ResourceResponse & response) const5007 ResourceError FrameLoader::fileDoesNotExistError(const ResourceResponse& response) const
5008 {
5009     return m_client->fileDoesNotExistError(response);
5010 }
5011 
didFinishLoad(ResourceLoader * loader)5012 void FrameLoader::didFinishLoad(ResourceLoader* loader)
5013 {
5014     if (Page* page = m_frame->page())
5015         page->progress()->completeProgress(loader->identifier());
5016     dispatchDidFinishLoading(loader->documentLoader(), loader->identifier());
5017 }
5018 
shouldUseCredentialStorage(ResourceLoader * loader)5019 bool FrameLoader::shouldUseCredentialStorage(ResourceLoader* loader)
5020 {
5021     return m_client->shouldUseCredentialStorage(loader->documentLoader(), loader->identifier());
5022 }
5023 
didReceiveAuthenticationChallenge(ResourceLoader * loader,const AuthenticationChallenge & currentWebChallenge)5024 void FrameLoader::didReceiveAuthenticationChallenge(ResourceLoader* loader, const AuthenticationChallenge& currentWebChallenge)
5025 {
5026     m_client->dispatchDidReceiveAuthenticationChallenge(loader->documentLoader(), loader->identifier(), currentWebChallenge);
5027 }
5028 
didCancelAuthenticationChallenge(ResourceLoader * loader,const AuthenticationChallenge & currentWebChallenge)5029 void FrameLoader::didCancelAuthenticationChallenge(ResourceLoader* loader, const AuthenticationChallenge& currentWebChallenge)
5030 {
5031     m_client->dispatchDidCancelAuthenticationChallenge(loader->documentLoader(), loader->identifier(), currentWebChallenge);
5032 }
5033 
PolicyCheck()5034 PolicyCheck::PolicyCheck()
5035     : m_navigationFunction(0)
5036     , m_newWindowFunction(0)
5037     , m_contentFunction(0)
5038 {
5039 }
5040 
clear()5041 void PolicyCheck::clear()
5042 {
5043     clearRequest();
5044     m_navigationFunction = 0;
5045     m_newWindowFunction = 0;
5046     m_contentFunction = 0;
5047 }
5048 
set(const ResourceRequest & request,PassRefPtr<FormState> formState,NavigationPolicyDecisionFunction function,void * argument)5049 void PolicyCheck::set(const ResourceRequest& request, PassRefPtr<FormState> formState,
5050     NavigationPolicyDecisionFunction function, void* argument)
5051 {
5052     m_request = request;
5053     m_formState = formState;
5054     m_frameName = String();
5055 
5056     m_navigationFunction = function;
5057     m_newWindowFunction = 0;
5058     m_contentFunction = 0;
5059     m_argument = argument;
5060 }
5061 
set(const ResourceRequest & request,PassRefPtr<FormState> formState,const String & frameName,NewWindowPolicyDecisionFunction function,void * argument)5062 void PolicyCheck::set(const ResourceRequest& request, PassRefPtr<FormState> formState,
5063     const String& frameName, NewWindowPolicyDecisionFunction function, void* argument)
5064 {
5065     m_request = request;
5066     m_formState = formState;
5067     m_frameName = frameName;
5068 
5069     m_navigationFunction = 0;
5070     m_newWindowFunction = function;
5071     m_contentFunction = 0;
5072     m_argument = argument;
5073 }
5074 
set(ContentPolicyDecisionFunction function,void * argument)5075 void PolicyCheck::set(ContentPolicyDecisionFunction function, void* argument)
5076 {
5077     m_request = ResourceRequest();
5078     m_formState = 0;
5079     m_frameName = String();
5080 
5081     m_navigationFunction = 0;
5082     m_newWindowFunction = 0;
5083     m_contentFunction = function;
5084     m_argument = argument;
5085 }
5086 
call(bool shouldContinue)5087 void PolicyCheck::call(bool shouldContinue)
5088 {
5089     if (m_navigationFunction)
5090         m_navigationFunction(m_argument, m_request, m_formState.get(), shouldContinue);
5091     if (m_newWindowFunction)
5092         m_newWindowFunction(m_argument, m_request, m_formState.get(), m_frameName, shouldContinue);
5093     ASSERT(!m_contentFunction);
5094 }
5095 
call(PolicyAction action)5096 void PolicyCheck::call(PolicyAction action)
5097 {
5098     ASSERT(!m_navigationFunction);
5099     ASSERT(!m_newWindowFunction);
5100     ASSERT(m_contentFunction);
5101     m_contentFunction(m_argument, action);
5102 }
5103 
clearRequest()5104 void PolicyCheck::clearRequest()
5105 {
5106     m_request = ResourceRequest();
5107     m_formState = 0;
5108     m_frameName = String();
5109 }
5110 
cancel()5111 void PolicyCheck::cancel()
5112 {
5113     clearRequest();
5114     if (m_navigationFunction)
5115         m_navigationFunction(m_argument, m_request, m_formState.get(), false);
5116     if (m_newWindowFunction)
5117         m_newWindowFunction(m_argument, m_request, m_formState.get(), m_frameName, false);
5118     if (m_contentFunction)
5119         m_contentFunction(m_argument, PolicyIgnore);
5120 }
5121 
setTitle(const String & title)5122 void FrameLoader::setTitle(const String& title)
5123 {
5124     documentLoader()->setTitle(title);
5125 }
5126 
originalRequestURL() const5127 KURL FrameLoader::originalRequestURL() const
5128 {
5129     return activeDocumentLoader()->originalRequest().url();
5130 }
5131 
referrer() const5132 String FrameLoader::referrer() const
5133 {
5134     return documentLoader()->request().httpReferrer();
5135 }
5136 
dispatchDocumentElementAvailable()5137 void FrameLoader::dispatchDocumentElementAvailable()
5138 {
5139     m_client->documentElementAvailable();
5140 }
5141 
dispatchWindowObjectAvailable()5142 void FrameLoader::dispatchWindowObjectAvailable()
5143 {
5144     if (!m_frame->script()->isEnabled() || !m_frame->script()->haveWindowShell())
5145         return;
5146 
5147     m_client->windowObjectCleared();
5148 
5149     if (Page* page = m_frame->page()) {
5150         if (InspectorController* inspector = page->inspectorController())
5151             inspector->inspectedWindowScriptObjectCleared(m_frame);
5152         if (InspectorController* inspector = page->parentInspectorController())
5153             inspector->windowScriptObjectAvailable();
5154     }
5155 }
5156 
createJavaAppletWidget(const IntSize & size,HTMLAppletElement * element,const HashMap<String,String> & args)5157 PassRefPtr<Widget> FrameLoader::createJavaAppletWidget(const IntSize& size, HTMLAppletElement* element, const HashMap<String, String>& args)
5158 {
5159     String baseURLString;
5160     String codeBaseURLString;
5161     Vector<String> paramNames;
5162     Vector<String> paramValues;
5163     HashMap<String, String>::const_iterator end = args.end();
5164     for (HashMap<String, String>::const_iterator it = args.begin(); it != end; ++it) {
5165         if (equalIgnoringCase(it->first, "baseurl"))
5166             baseURLString = it->second;
5167         else if (equalIgnoringCase(it->first, "codebase"))
5168             codeBaseURLString = it->second;
5169         paramNames.append(it->first);
5170         paramValues.append(it->second);
5171     }
5172 
5173     if (!codeBaseURLString.isEmpty()) {
5174         KURL codeBaseURL = completeURL(codeBaseURLString);
5175         if (!canLoad(codeBaseURL, String(), element->document())) {
5176             FrameLoader::reportLocalLoadFailed(m_frame, codeBaseURL.string());
5177             return 0;
5178         }
5179     }
5180 
5181     if (baseURLString.isEmpty())
5182         baseURLString = m_frame->document()->baseURL().string();
5183     KURL baseURL = completeURL(baseURLString);
5184 
5185     RefPtr<Widget> widget = m_client->createJavaAppletWidget(size, element, baseURL, paramNames, paramValues);
5186     if (!widget)
5187         return 0;
5188 
5189     m_containsPlugIns = true;
5190     return widget;
5191 }
5192 
didChangeTitle(DocumentLoader * loader)5193 void FrameLoader::didChangeTitle(DocumentLoader* loader)
5194 {
5195     m_client->didChangeTitle(loader);
5196 
5197     if (loader == m_documentLoader) {
5198         // Must update the entries in the back-forward list too.
5199         if (m_currentHistoryItem)
5200             m_currentHistoryItem->setTitle(loader->title());
5201         // This must go through the WebFrame because it has the right notion of the current b/f item.
5202         m_client->setTitle(loader->title(), loader->urlForHistory());
5203         m_client->setMainFrameDocumentReady(true); // update observers with new DOMDocument
5204         m_client->dispatchDidReceiveTitle(loader->title());
5205     }
5206 }
5207 
dispatchDidCommitLoad()5208 void FrameLoader::dispatchDidCommitLoad()
5209 {
5210     if (m_creatingInitialEmptyDocument)
5211         return;
5212 
5213 #ifndef NDEBUG
5214     m_didDispatchDidCommitLoad = true;
5215 #endif
5216 
5217     m_client->dispatchDidCommitLoad();
5218 
5219     if (Page* page = m_frame->page())
5220         page->inspectorController()->didCommitLoad(m_documentLoader.get());
5221 }
5222 
dispatchAssignIdentifierToInitialRequest(unsigned long identifier,DocumentLoader * loader,const ResourceRequest & request)5223 void FrameLoader::dispatchAssignIdentifierToInitialRequest(unsigned long identifier, DocumentLoader* loader, const ResourceRequest& request)
5224 {
5225     m_client->assignIdentifierToInitialRequest(identifier, loader, request);
5226 
5227     if (Page* page = m_frame->page())
5228         page->inspectorController()->identifierForInitialRequest(identifier, loader, request);
5229 }
5230 
dispatchWillSendRequest(DocumentLoader * loader,unsigned long identifier,ResourceRequest & request,const ResourceResponse & redirectResponse)5231 void FrameLoader::dispatchWillSendRequest(DocumentLoader* loader, unsigned long identifier, ResourceRequest& request, const ResourceResponse& redirectResponse)
5232 {
5233     StringImpl* oldRequestURL = request.url().string().impl();
5234     m_documentLoader->didTellClientAboutLoad(request.url());
5235 
5236     m_client->dispatchWillSendRequest(loader, identifier, request, redirectResponse);
5237 
5238     // If the URL changed, then we want to put that new URL in the "did tell client" set too.
5239     if (!request.isNull() && oldRequestURL != request.url().string().impl())
5240         m_documentLoader->didTellClientAboutLoad(request.url());
5241 
5242     if (Page* page = m_frame->page())
5243         page->inspectorController()->willSendRequest(loader, identifier, request, redirectResponse);
5244 }
5245 
dispatchDidReceiveResponse(DocumentLoader * loader,unsigned long identifier,const ResourceResponse & r)5246 void FrameLoader::dispatchDidReceiveResponse(DocumentLoader* loader, unsigned long identifier, const ResourceResponse& r)
5247 {
5248     m_client->dispatchDidReceiveResponse(loader, identifier, r);
5249 
5250     if (Page* page = m_frame->page())
5251         page->inspectorController()->didReceiveResponse(loader, identifier, r);
5252 }
5253 
dispatchDidReceiveContentLength(DocumentLoader * loader,unsigned long identifier,int length)5254 void FrameLoader::dispatchDidReceiveContentLength(DocumentLoader* loader, unsigned long identifier, int length)
5255 {
5256     m_client->dispatchDidReceiveContentLength(loader, identifier, length);
5257 
5258     if (Page* page = m_frame->page())
5259         page->inspectorController()->didReceiveContentLength(loader, identifier, length);
5260 }
5261 
dispatchDidFinishLoading(DocumentLoader * loader,unsigned long identifier)5262 void FrameLoader::dispatchDidFinishLoading(DocumentLoader* loader, unsigned long identifier)
5263 {
5264     m_client->dispatchDidFinishLoading(loader, identifier);
5265 
5266     if (Page* page = m_frame->page())
5267         page->inspectorController()->didFinishLoading(loader, identifier);
5268 }
5269 
tellClientAboutPastMemoryCacheLoads()5270 void FrameLoader::tellClientAboutPastMemoryCacheLoads()
5271 {
5272     ASSERT(m_frame->page());
5273     ASSERT(m_frame->page()->areMemoryCacheClientCallsEnabled());
5274 
5275     if (!m_documentLoader)
5276         return;
5277 
5278     Vector<String> pastLoads;
5279     m_documentLoader->takeMemoryCacheLoadsForClientNotification(pastLoads);
5280 
5281     size_t size = pastLoads.size();
5282     for (size_t i = 0; i < size; ++i) {
5283         CachedResource* resource = cache()->resourceForURL(pastLoads[i]);
5284 
5285         // FIXME: These loads, loaded from cache, but now gone from the cache by the time
5286         // Page::setMemoryCacheClientCallsEnabled(true) is called, will not be seen by the client.
5287         // Consider if there's some efficient way of remembering enough to deliver this client call.
5288         // We have the URL, but not the rest of the response or the length.
5289         if (!resource)
5290             continue;
5291 
5292         ResourceRequest request(resource->url());
5293         m_client->dispatchDidLoadResourceFromMemoryCache(m_documentLoader.get(), request, resource->response(), resource->encodedSize());
5294     }
5295 }
5296 
hasHTMLView() const5297 bool FrameLoaderClient::hasHTMLView() const
5298 {
5299     return true;
5300 }
5301 
5302 } // namespace WebCore
5303