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