1 /*
2 * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
4 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
5 * Copyright (C) 2008 Alp Toker <alp@atoker.com>
6 * Copyright (C) Research In Motion Limited 2009. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
18 * its contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
22 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
25 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include "config.h"
34 #include "FrameLoader.h"
35
36 #include "ApplicationCacheHost.h"
37 #if ENABLE(ARCHIVE) // ANDROID extension: disabled to reduce code size
38 #include "Archive.h"
39 #include "ArchiveFactory.h"
40 #endif
41 #include "BackForwardList.h"
42 #include "CString.h"
43 #include "Cache.h"
44 #include "CachedPage.h"
45 #include "Chrome.h"
46 #include "DOMImplementation.h"
47 #include "DOMWindow.h"
48 #include "DocLoader.h"
49 #include "Document.h"
50 #include "DocumentLoader.h"
51 #include "Editor.h"
52 #include "EditorClient.h"
53 #include "Element.h"
54 #include "Event.h"
55 #include "EventNames.h"
56 #include "FloatRect.h"
57 #include "FormState.h"
58 #include "Frame.h"
59 #include "FrameLoadRequest.h"
60 #include "FrameLoaderClient.h"
61 #include "FrameTree.h"
62 #include "FrameView.h"
63 #include "HTMLAnchorElement.h"
64 #include "HTMLAppletElement.h"
65 #include "HTMLFormElement.h"
66 #include "HTMLFrameElement.h"
67 #include "HTMLNames.h"
68 #include "HTMLObjectElement.h"
69 #include "HTTPParsers.h"
70 #include "HistoryItem.h"
71 #include "IconDatabase.h"
72 #include "IconLoader.h"
73 #include "InspectorController.h"
74 #include "Logging.h"
75 #include "MIMETypeRegistry.h"
76 #include "MainResourceLoader.h"
77 #include "Page.h"
78 #include "PageCache.h"
79 #include "PageGroup.h"
80 #include "PageTransitionEvent.h"
81 #include "PlaceholderDocument.h"
82 #include "PluginData.h"
83 #include "PluginDatabase.h"
84 #include "PluginDocument.h"
85 #include "ProgressTracker.h"
86 #include "RenderPart.h"
87 #include "RenderView.h"
88 #include "RenderWidget.h"
89 #include "ResourceHandle.h"
90 #include "ResourceRequest.h"
91 #include "ScriptController.h"
92 #include "ScriptSourceCode.h"
93 #include "ScriptString.h"
94 #include "ScriptValue.h"
95 #include "SecurityOrigin.h"
96 #include "SegmentedString.h"
97 #include "Settings.h"
98
99 #if ENABLE(SHARED_WORKERS)
100 #include "SharedWorkerRepository.h"
101 #endif
102
103 #include "TextResourceDecoder.h"
104 #include "WindowFeatures.h"
105 #include "XMLHttpRequest.h"
106 #include "XMLTokenizer.h"
107 #include "XSSAuditor.h"
108 #include <wtf/CurrentTime.h>
109 #include <wtf/StdLibExtras.h>
110
111
112 #if ENABLE(SVG)
113 #include "SVGDocument.h"
114 #include "SVGLocatable.h"
115 #include "SVGNames.h"
116 #include "SVGPreserveAspectRatio.h"
117 #include "SVGSVGElement.h"
118 #include "SVGViewElement.h"
119 #include "SVGViewSpec.h"
120 #endif
121
122 #ifdef ANDROID_INSTRUMENT
123 #include "TimeCounter.h"
124 #include "RenderArena.h"
125 #endif
126
127 namespace WebCore {
128
129 #if ENABLE(SVG)
130 using namespace SVGNames;
131 #endif
132 using namespace HTMLNames;
133
134 #if ENABLE(XHTMLMP)
135 static const char defaultAcceptHeader[] = "application/xml,application/vnd.wap.xhtml+xml,application/xhtml+xml;profile='http://www.wapforum.org/xhtml',text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5";
136 #else
137 static const char defaultAcceptHeader[] = "application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5";
138 #endif
139 static double storedTimeOfLastCompletedLoad;
140
isBackForwardLoadType(FrameLoadType type)141 bool isBackForwardLoadType(FrameLoadType type)
142 {
143 switch (type) {
144 case FrameLoadTypeStandard:
145 case FrameLoadTypeReload:
146 case FrameLoadTypeReloadFromOrigin:
147 case FrameLoadTypeSame:
148 case FrameLoadTypeRedirectWithLockedBackForwardList:
149 case FrameLoadTypeReplace:
150 return false;
151 case FrameLoadTypeBack:
152 case FrameLoadTypeBackWMLDeckNotAccessible:
153 case FrameLoadTypeForward:
154 case FrameLoadTypeIndexedBackForward:
155 return true;
156 }
157 ASSERT_NOT_REACHED();
158 return false;
159 }
160
numRequests(Document * document)161 static int numRequests(Document* document)
162 {
163 if (!document)
164 return 0;
165
166 return document->docLoader()->requestCount();
167 }
168
canReferToParentFrameEncoding(const Frame * frame,const Frame * parentFrame)169 static inline bool canReferToParentFrameEncoding(const Frame* frame, const Frame* parentFrame)
170 {
171 return parentFrame && parentFrame->document()->securityOrigin()->canAccess(frame->document()->securityOrigin());
172 }
173
FrameLoader(Frame * frame,FrameLoaderClient * client)174 FrameLoader::FrameLoader(Frame* frame, FrameLoaderClient* client)
175 : m_frame(frame)
176 , m_client(client)
177 , m_policyChecker(frame)
178 , m_history(frame)
179 , m_notifer(frame)
180 , m_state(FrameStateCommittedPage)
181 , m_loadType(FrameLoadTypeStandard)
182 , m_delegateIsHandlingProvisionalLoadError(false)
183 , m_firstLayoutDone(false)
184 , m_quickRedirectComing(false)
185 , m_sentRedirectNotification(false)
186 , m_inStopAllLoaders(false)
187 , m_isExecutingJavaScriptFormAction(false)
188 , m_didCallImplicitClose(false)
189 , m_wasUnloadEventEmitted(false)
190 , m_unloadEventBeingDispatched(false)
191 , m_isComplete(false)
192 , m_isLoadingMainResource(false)
193 , m_needsClear(false)
194 , m_receivedData(false)
195 , m_encodingWasChosenByUser(false)
196 , m_containsPlugIns(false)
197 , m_checkTimer(this, &FrameLoader::checkTimerFired)
198 , m_shouldCallCheckCompleted(false)
199 , m_shouldCallCheckLoadComplete(false)
200 , m_opener(0)
201 , m_creatingInitialEmptyDocument(false)
202 , m_isDisplayingInitialEmptyDocument(false)
203 , m_committedFirstRealDocumentLoad(false)
204 , m_didPerformFirstNavigation(false)
205 , m_loadingFromCachedPage(false)
206 , m_suppressOpenerInNewFrame(false)
207 , m_sandboxFlags(SandboxAll)
208 #ifndef NDEBUG
209 , m_didDispatchDidCommitLoad(false)
210 #endif
211 {
212 }
213
~FrameLoader()214 FrameLoader::~FrameLoader()
215 {
216 setOpener(0);
217
218 HashSet<Frame*>::iterator end = m_openedFrames.end();
219 for (HashSet<Frame*>::iterator it = m_openedFrames.begin(); it != end; ++it)
220 (*it)->loader()->m_opener = 0;
221
222 m_client->frameLoaderDestroyed();
223 }
224
init()225 void FrameLoader::init()
226 {
227 // this somewhat odd set of steps is needed to give the frame an initial empty document
228 m_isDisplayingInitialEmptyDocument = false;
229 m_creatingInitialEmptyDocument = true;
230 setPolicyDocumentLoader(m_client->createDocumentLoader(ResourceRequest(KURL(ParsedURLString, "")), SubstituteData()).get());
231 setProvisionalDocumentLoader(m_policyDocumentLoader.get());
232 setState(FrameStateProvisional);
233 m_provisionalDocumentLoader->setResponse(ResourceResponse(KURL(), "text/html", 0, String(), String()));
234 m_provisionalDocumentLoader->finishedLoading();
235 begin(KURL(), false);
236 end();
237 m_frame->document()->cancelParsing();
238 m_creatingInitialEmptyDocument = false;
239 m_didCallImplicitClose = true;
240
241 // Propagate sandbox attributes to this Frameloader and its descendants.
242 updateSandboxFlags();
243 }
244
setDefersLoading(bool defers)245 void FrameLoader::setDefersLoading(bool defers)
246 {
247 if (m_documentLoader)
248 m_documentLoader->setDefersLoading(defers);
249 if (m_provisionalDocumentLoader)
250 m_provisionalDocumentLoader->setDefersLoading(defers);
251 if (m_policyDocumentLoader)
252 m_policyDocumentLoader->setDefersLoading(defers);
253
254 if (!defers) {
255 m_frame->redirectScheduler()->startTimer();
256 startCheckCompleteTimer();
257 }
258 }
259
createWindow(FrameLoader * frameLoaderForFrameLookup,const FrameLoadRequest & request,const WindowFeatures & features,bool & created)260 Frame* FrameLoader::createWindow(FrameLoader* frameLoaderForFrameLookup, const FrameLoadRequest& request, const WindowFeatures& features, bool& created)
261 {
262 ASSERT(!features.dialog || request.frameName().isEmpty());
263
264 if (!request.frameName().isEmpty() && request.frameName() != "_blank") {
265 Frame* frame = frameLoaderForFrameLookup->frame()->tree()->find(request.frameName());
266 if (frame && shouldAllowNavigation(frame)) {
267 if (!request.resourceRequest().url().isEmpty())
268 frame->loader()->loadFrameRequest(request, false, false, 0, 0, SendReferrer);
269 if (Page* page = frame->page())
270 #ifdef ANDROID_USER_GESTURE
271 page->chrome()->focus(isProcessingUserGesture());
272 #else
273 page->chrome()->focus();
274 #endif
275 created = false;
276 return frame;
277 }
278 }
279
280 // FIXME: Setting the referrer should be the caller's responsibility.
281 FrameLoadRequest requestWithReferrer = request;
282 requestWithReferrer.resourceRequest().setHTTPReferrer(m_outgoingReferrer);
283 addHTTPOriginIfNeeded(requestWithReferrer.resourceRequest(), outgoingOrigin());
284
285 Page* oldPage = m_frame->page();
286 if (!oldPage)
287 return 0;
288
289 Page* page = oldPage->chrome()->createWindow(m_frame, requestWithReferrer, features);
290 if (!page)
291 return 0;
292
293 Frame* frame = page->mainFrame();
294 if (request.frameName() != "_blank")
295 frame->tree()->setName(request.frameName());
296
297 page->chrome()->setToolbarsVisible(features.toolBarVisible || features.locationBarVisible);
298 page->chrome()->setStatusbarVisible(features.statusBarVisible);
299 page->chrome()->setScrollbarsVisible(features.scrollbarsVisible);
300 page->chrome()->setMenubarVisible(features.menuBarVisible);
301 page->chrome()->setResizable(features.resizable);
302
303 // 'x' and 'y' specify the location of the window, while 'width' and 'height'
304 // specify the size of the page. We can only resize the window, so
305 // adjust for the difference between the window size and the page size.
306
307 FloatRect windowRect = page->chrome()->windowRect();
308 FloatSize pageSize = page->chrome()->pageRect().size();
309 if (features.xSet)
310 windowRect.setX(features.x);
311 if (features.ySet)
312 windowRect.setY(features.y);
313 if (features.widthSet)
314 windowRect.setWidth(features.width + (windowRect.width() - pageSize.width()));
315 if (features.heightSet)
316 windowRect.setHeight(features.height + (windowRect.height() - pageSize.height()));
317 page->chrome()->setWindowRect(windowRect);
318
319 page->chrome()->show();
320
321 created = true;
322 return frame;
323 }
324
canHandleRequest(const ResourceRequest & request)325 bool FrameLoader::canHandleRequest(const ResourceRequest& request)
326 {
327 return m_client->canHandleRequest(request);
328 }
329
changeLocation(const KURL & url,const String & referrer,bool lockHistory,bool lockBackForwardList,bool userGesture,bool refresh)330 void FrameLoader::changeLocation(const KURL& url, const String& referrer, bool lockHistory, bool lockBackForwardList, bool userGesture, bool refresh)
331 {
332 RefPtr<Frame> protect(m_frame);
333
334 ResourceRequest request(url, referrer, refresh ? ReloadIgnoringCacheData : UseProtocolCachePolicy);
335 #ifdef ANDROID_USER_GESTURE
336 request.setUserGesture(userGesture);
337 #endif
338
339 if (m_frame->script()->executeIfJavaScriptURL(request.url(), userGesture))
340 return;
341
342 urlSelected(request, "_self", 0, lockHistory, lockBackForwardList, userGesture, SendReferrer);
343 }
344
urlSelected(const ResourceRequest & request,const String & passedTarget,PassRefPtr<Event> triggeringEvent,bool lockHistory,bool lockBackForwardList,bool userGesture,ReferrerPolicy referrerPolicy)345 void FrameLoader::urlSelected(const ResourceRequest& request, const String& passedTarget, PassRefPtr<Event> triggeringEvent, bool lockHistory, bool lockBackForwardList, bool userGesture, ReferrerPolicy referrerPolicy)
346 {
347 ASSERT(!m_suppressOpenerInNewFrame);
348
349 if (m_frame->script()->executeIfJavaScriptURL(request.url(), userGesture, false))
350 return;
351
352 String target = passedTarget;
353 if (target.isEmpty())
354 target = m_frame->document()->baseTarget();
355
356 FrameLoadRequest frameRequest(request, target);
357
358 if (referrerPolicy == NoReferrer)
359 m_suppressOpenerInNewFrame = true;
360 else if (frameRequest.resourceRequest().httpReferrer().isEmpty())
361 frameRequest.resourceRequest().setHTTPReferrer(m_outgoingReferrer);
362 addHTTPOriginIfNeeded(frameRequest.resourceRequest(), outgoingOrigin());
363
364 loadFrameRequest(frameRequest, lockHistory, lockBackForwardList, triggeringEvent, 0, referrerPolicy);
365
366 m_suppressOpenerInNewFrame = false;
367 }
368
requestFrame(HTMLFrameOwnerElement * ownerElement,const String & urlString,const AtomicString & frameName)369 bool FrameLoader::requestFrame(HTMLFrameOwnerElement* ownerElement, const String& urlString, const AtomicString& frameName)
370 {
371 // Support for <frame src="javascript:string">
372 KURL scriptURL;
373 KURL url;
374 if (protocolIsJavaScript(urlString)) {
375 scriptURL = completeURL(urlString); // completeURL() encodes the URL.
376 url = blankURL();
377 } else
378 url = completeURL(urlString);
379
380 Frame* frame = ownerElement->contentFrame();
381 if (frame)
382 frame->redirectScheduler()->scheduleLocationChange(url.string(), m_outgoingReferrer, true, true, isProcessingUserGesture());
383 else
384 frame = loadSubframe(ownerElement, url, frameName, m_outgoingReferrer);
385
386 if (!frame)
387 return false;
388
389 if (!scriptURL.isEmpty())
390 frame->script()->executeIfJavaScriptURL(scriptURL);
391
392 return true;
393 }
394
loadSubframe(HTMLFrameOwnerElement * ownerElement,const KURL & url,const String & name,const String & referrer)395 Frame* FrameLoader::loadSubframe(HTMLFrameOwnerElement* ownerElement, const KURL& url, const String& name, const String& referrer)
396 {
397 bool allowsScrolling = true;
398 int marginWidth = -1;
399 int marginHeight = -1;
400 if (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag)) {
401 HTMLFrameElementBase* o = static_cast<HTMLFrameElementBase*>(ownerElement);
402 allowsScrolling = o->scrollingMode() != ScrollbarAlwaysOff;
403 marginWidth = o->getMarginWidth();
404 marginHeight = o->getMarginHeight();
405 }
406
407 if (!SecurityOrigin::canLoad(url, referrer, 0)) {
408 FrameLoader::reportLocalLoadFailed(m_frame, url.string());
409 return 0;
410 }
411
412 bool hideReferrer = SecurityOrigin::shouldHideReferrer(url, referrer);
413 RefPtr<Frame> frame = m_client->createFrame(url, name, ownerElement, hideReferrer ? String() : referrer, allowsScrolling, marginWidth, marginHeight);
414
415 if (!frame) {
416 checkCallImplicitClose();
417 return 0;
418 }
419
420 // All new frames will have m_isComplete set to true at this point due to synchronously loading
421 // an empty document in FrameLoader::init(). But many frames will now be starting an
422 // asynchronous load of url, so we set m_isComplete to false and then check if the load is
423 // actually completed below. (Note that we set m_isComplete to false even for synchronous
424 // loads, so that checkCompleted() below won't bail early.)
425 // FIXME: Can we remove this entirely? m_isComplete normally gets set to false when a load is committed.
426 frame->loader()->m_isComplete = false;
427
428 RenderObject* renderer = ownerElement->renderer();
429 FrameView* view = frame->view();
430 if (renderer && renderer->isWidget() && view)
431 toRenderWidget(renderer)->setWidget(view);
432
433 checkCallImplicitClose();
434
435 // Some loads are performed synchronously (e.g., about:blank and loads
436 // cancelled by returning a null ResourceRequest from requestFromDelegate).
437 // In these cases, the synchronous load would have finished
438 // before we could connect the signals, so make sure to send the
439 // completed() signal for the child by hand and mark the load as being
440 // complete.
441 // FIXME: In this case the Frame will have finished loading before
442 // it's being added to the child list. It would be a good idea to
443 // create the child first, then invoke the loader separately.
444 if (frame->loader()->state() == FrameStateComplete)
445 frame->loader()->checkCompleted();
446
447 return frame.get();
448 }
449
submitForm(const char * action,const String & url,PassRefPtr<FormData> formData,const String & target,const String & contentType,const String & boundary,bool lockHistory,PassRefPtr<Event> event,PassRefPtr<FormState> formState)450 void FrameLoader::submitForm(const char* action, const String& url, PassRefPtr<FormData> formData,
451 const String& target, const String& contentType, const String& boundary,
452 bool lockHistory, PassRefPtr<Event> event, PassRefPtr<FormState> formState)
453 {
454 ASSERT(action);
455 ASSERT(strcmp(action, "GET") == 0 || strcmp(action, "POST") == 0);
456 ASSERT(formData);
457 ASSERT(formState);
458 ASSERT(formState->sourceFrame() == m_frame);
459
460 if (!m_frame->page())
461 return;
462
463 KURL u = completeURL(url.isNull() ? "" : url);
464 if (u.isEmpty())
465 return;
466
467 if (isDocumentSandboxed(SandboxForms))
468 return;
469
470 if (protocolIsJavaScript(u)) {
471 m_isExecutingJavaScriptFormAction = true;
472 m_frame->script()->executeIfJavaScriptURL(u, false, false);
473 m_isExecutingJavaScriptFormAction = false;
474 return;
475 }
476
477 FrameLoadRequest frameRequest;
478 #ifdef ANDROID_USER_GESTURE
479 frameRequest.resourceRequest().setUserGesture(isProcessingUserGesture());
480 #endif
481
482 String targetOrBaseTarget = target.isEmpty() ? m_frame->document()->baseTarget() : target;
483 Frame* targetFrame = findFrameForNavigation(targetOrBaseTarget);
484 if (!targetFrame) {
485 targetFrame = m_frame;
486 frameRequest.setFrameName(targetOrBaseTarget);
487 }
488 if (!targetFrame->page())
489 return;
490
491 // FIXME: We'd like to remove this altogether and fix the multiple form submission issue another way.
492
493 // We do not want to submit more than one form from the same page, nor do we want to submit a single
494 // form more than once. This flag prevents these from happening; not sure how other browsers prevent this.
495 // The flag is reset in each time we start handle a new mouse or key down event, and
496 // also in setView since this part may get reused for a page from the back/forward cache.
497 // The form multi-submit logic here is only needed when we are submitting a form that affects this frame.
498
499 // FIXME: Frame targeting is only one of the ways the submission could end up doing something other
500 // than replacing this frame's content, so this check is flawed. On the other hand, the check is hardly
501 // needed any more now that we reset m_submittedFormURL on each mouse or key down event.
502
503 if (m_frame->tree()->isDescendantOf(targetFrame)) {
504 if (m_submittedFormURL == u)
505 return;
506 m_submittedFormURL = u;
507 }
508
509 formData->generateFiles(m_frame->page()->chrome()->client());
510
511 if (!m_outgoingReferrer.isEmpty())
512 frameRequest.resourceRequest().setHTTPReferrer(m_outgoingReferrer);
513
514 if (strcmp(action, "GET") == 0)
515 u.setQuery(formData->flattenToString());
516 else {
517 frameRequest.resourceRequest().setHTTPMethod("POST");
518 frameRequest.resourceRequest().setHTTPBody(formData);
519
520 // construct some user headers if necessary
521 if (contentType.isNull() || contentType == "application/x-www-form-urlencoded")
522 frameRequest.resourceRequest().setHTTPContentType(contentType);
523 else // contentType must be "multipart/form-data"
524 frameRequest.resourceRequest().setHTTPContentType(contentType + "; boundary=" + boundary);
525 }
526
527 frameRequest.resourceRequest().setURL(u);
528 addHTTPOriginIfNeeded(frameRequest.resourceRequest(), outgoingOrigin());
529
530 targetFrame->redirectScheduler()->scheduleFormSubmission(frameRequest, lockHistory, event, formState);
531 }
532
stopLoading(UnloadEventPolicy unloadEventPolicy,DatabasePolicy databasePolicy)533 void FrameLoader::stopLoading(UnloadEventPolicy unloadEventPolicy, DatabasePolicy databasePolicy)
534 {
535 if (m_frame->document() && m_frame->document()->tokenizer())
536 m_frame->document()->tokenizer()->stopParsing();
537
538 if (unloadEventPolicy != UnloadEventPolicyNone) {
539 if (m_frame->document()) {
540 if (m_didCallImplicitClose && !m_wasUnloadEventEmitted) {
541 Node* currentFocusedNode = m_frame->document()->focusedNode();
542 if (currentFocusedNode)
543 currentFocusedNode->aboutToUnload();
544 m_unloadEventBeingDispatched = true;
545 if (m_frame->domWindow()) {
546 if (unloadEventPolicy == UnloadEventPolicyUnloadAndPageHide)
547 m_frame->domWindow()->dispatchEvent(PageTransitionEvent::create(eventNames().pagehideEvent, m_frame->document()->inPageCache()), m_frame->document());
548 if (!m_frame->document()->inPageCache())
549 m_frame->domWindow()->dispatchEvent(Event::create(eventNames().unloadEvent, false, false), m_frame->domWindow()->document());
550 }
551 m_unloadEventBeingDispatched = false;
552 if (m_frame->document())
553 m_frame->document()->updateStyleIfNeeded();
554 m_wasUnloadEventEmitted = true;
555 }
556 }
557
558 // Dispatching the unload event could have made m_frame->document() null.
559 if (m_frame->document() && !m_frame->document()->inPageCache()) {
560 // Don't remove event listeners from a transitional empty document (see bug 28716 for more information).
561 bool keepEventListeners = m_isDisplayingInitialEmptyDocument && m_provisionalDocumentLoader
562 && m_frame->document()->securityOrigin()->isSecureTransitionTo(m_provisionalDocumentLoader->url());
563
564 if (!keepEventListeners)
565 m_frame->document()->removeAllEventListeners();
566 }
567 }
568
569 m_isComplete = true; // to avoid calling completed() in finishedParsing()
570 m_isLoadingMainResource = false;
571 m_didCallImplicitClose = true; // don't want that one either
572
573 if (m_frame->document() && m_frame->document()->parsing()) {
574 finishedParsing();
575 m_frame->document()->setParsing(false);
576 }
577
578 m_workingURL = KURL();
579
580 if (Document* doc = m_frame->document()) {
581 if (DocLoader* docLoader = doc->docLoader())
582 cache()->loader()->cancelRequests(docLoader);
583
584 #if ENABLE(DATABASE)
585 if (databasePolicy == DatabasePolicyStop)
586 doc->stopDatabases(0);
587 #else
588 UNUSED_PARAM(databasePolicy);
589 #endif
590 }
591
592 // tell all subframes to stop as well
593 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
594 child->loader()->stopLoading(unloadEventPolicy);
595
596 m_frame->redirectScheduler()->cancel();
597 }
598
stop()599 void FrameLoader::stop()
600 {
601 // http://bugs.webkit.org/show_bug.cgi?id=10854
602 // The frame's last ref may be removed and it will be deleted by checkCompleted().
603 RefPtr<Frame> protector(m_frame);
604
605 if (m_frame->document()->tokenizer())
606 m_frame->document()->tokenizer()->stopParsing();
607 m_frame->document()->finishParsing();
608
609 if (m_iconLoader)
610 m_iconLoader->stopLoading();
611 }
612
closeURL()613 bool FrameLoader::closeURL()
614 {
615 history()->saveDocumentState();
616
617 // Should only send the pagehide event here if the current document exists and has not been placed in the page cache.
618 Document* currentDocument = m_frame->document();
619 stopLoading(currentDocument && !currentDocument->inPageCache() ? UnloadEventPolicyUnloadAndPageHide : UnloadEventPolicyUnloadOnly);
620
621 m_frame->editor()->clearUndoRedoOperations();
622 return true;
623 }
624
iconURL()625 KURL FrameLoader::iconURL()
626 {
627 // If this isn't a top level frame, return nothing
628 if (m_frame->tree() && m_frame->tree()->parent())
629 return KURL();
630
631 // If we have an iconURL from a Link element, return that
632 if (!m_frame->document()->iconURL().isEmpty())
633 return KURL(ParsedURLString, m_frame->document()->iconURL());
634
635 // Don't return a favicon iconURL unless we're http or https
636 if (!m_URL.protocolInHTTPFamily())
637 return KURL();
638
639 KURL url;
640 bool couldSetProtocol = url.setProtocol(m_URL.protocol());
641 ASSERT_UNUSED(couldSetProtocol, couldSetProtocol);
642 url.setHost(m_URL.host());
643 if (m_URL.hasPort())
644 url.setPort(m_URL.port());
645 url.setPath("/favicon.ico");
646 return url;
647 }
648
didOpenURL(const KURL & url)649 bool FrameLoader::didOpenURL(const KURL& url)
650 {
651 if (m_frame->redirectScheduler()->redirectScheduledDuringLoad()) {
652 // A redirect was scheduled before the document was created.
653 // This can happen when one frame changes another frame's location.
654 return false;
655 }
656
657 m_frame->redirectScheduler()->cancel();
658 m_frame->editor()->clearLastEditCommand();
659
660 m_isComplete = false;
661 m_isLoadingMainResource = true;
662 m_didCallImplicitClose = false;
663
664 // If we are still in the process of initializing an empty document then
665 // its frame is not in a consistent state for rendering, so avoid setJSStatusBarText
666 // since it may cause clients to attempt to render the frame.
667 if (!m_creatingInitialEmptyDocument) {
668 m_frame->setJSStatusBarText(String());
669 m_frame->setJSDefaultStatusBarText(String());
670 }
671 m_URL = url;
672 if (m_URL.protocolInHTTPFamily() && !m_URL.host().isEmpty() && m_URL.path().isEmpty())
673 m_URL.setPath("/");
674 m_workingURL = m_URL;
675
676 started();
677
678 return true;
679 }
680
didExplicitOpen()681 void FrameLoader::didExplicitOpen()
682 {
683 m_isComplete = false;
684 m_didCallImplicitClose = false;
685
686 // Calling document.open counts as committing the first real document load.
687 m_committedFirstRealDocumentLoad = true;
688
689 // Prevent window.open(url) -- eg window.open("about:blank") -- from blowing away results
690 // from a subsequent window.document.open / window.document.write call.
691 // Canceling redirection here works for all cases because document.open
692 // implicitly precedes document.write.
693 m_frame->redirectScheduler()->cancel();
694 if (m_frame->document()->url() != blankURL())
695 m_URL = m_frame->document()->url();
696 }
697
698
cancelAndClear()699 void FrameLoader::cancelAndClear()
700 {
701 m_frame->redirectScheduler()->cancel();
702
703 if (!m_isComplete)
704 closeURL();
705
706 clear(false);
707 m_frame->script()->updatePlatformScriptObjects();
708 }
709
replaceDocument(const String & html)710 void FrameLoader::replaceDocument(const String& html)
711 {
712 stopAllLoaders();
713 begin(m_URL, true, m_frame->document()->securityOrigin());
714 write(html);
715 end();
716 }
717
clear(bool clearWindowProperties,bool clearScriptObjects,bool clearFrameView)718 void FrameLoader::clear(bool clearWindowProperties, bool clearScriptObjects, bool clearFrameView)
719 {
720 m_frame->editor()->clear();
721
722 if (!m_needsClear)
723 return;
724 m_needsClear = false;
725
726 if (!m_frame->document()->inPageCache()) {
727 m_frame->document()->cancelParsing();
728 m_frame->document()->stopActiveDOMObjects();
729 if (m_frame->document()->attached()) {
730 m_frame->document()->willRemove();
731 m_frame->document()->detach();
732
733 m_frame->document()->removeFocusedNodeOfSubtree(m_frame->document());
734 }
735 }
736
737 // Do this after detaching the document so that the unload event works.
738 if (clearWindowProperties) {
739 m_frame->clearDOMWindow();
740 m_frame->script()->clearWindowShell();
741 }
742
743 m_frame->selection()->clear();
744 m_frame->eventHandler()->clear();
745 if (clearFrameView && m_frame->view())
746 m_frame->view()->clear();
747
748 m_frame->setSelectionGranularity(CharacterGranularity);
749
750 // Do not drop the document before the ScriptController and view are cleared
751 // as some destructors might still try to access the document.
752 m_frame->setDocument(0);
753 m_decoder = 0;
754
755 m_containsPlugIns = false;
756
757 if (clearScriptObjects)
758 m_frame->script()->clearScriptObjects();
759
760 m_frame->redirectScheduler()->clear();
761
762 m_checkTimer.stop();
763 m_shouldCallCheckCompleted = false;
764 m_shouldCallCheckLoadComplete = false;
765
766 m_receivedData = false;
767 m_isDisplayingInitialEmptyDocument = false;
768
769 if (!m_encodingWasChosenByUser)
770 m_encoding = String();
771 }
772
receivedFirstData()773 void FrameLoader::receivedFirstData()
774 {
775 begin(m_workingURL, false);
776
777 dispatchDidCommitLoad();
778 dispatchDidClearWindowObjectsInAllWorlds();
779
780 if (m_documentLoader) {
781 String ptitle = m_documentLoader->title();
782 // If we have a title let the WebView know about it.
783 if (!ptitle.isNull())
784 m_client->dispatchDidReceiveTitle(ptitle);
785 }
786
787 m_workingURL = KURL();
788
789 double delay;
790 String url;
791 if (!m_documentLoader)
792 return;
793 if (m_frame->inViewSourceMode())
794 return;
795 if (!parseHTTPRefresh(m_documentLoader->response().httpHeaderField("Refresh"), false, delay, url))
796 return;
797
798 if (url.isEmpty())
799 url = m_URL.string();
800 else
801 url = m_frame->document()->completeURL(url).string();
802
803 m_frame->redirectScheduler()->scheduleRedirect(delay, url);
804 }
805
responseMIMEType() const806 const String& FrameLoader::responseMIMEType() const
807 {
808 return m_responseMIMEType;
809 }
810
setResponseMIMEType(const String & type)811 void FrameLoader::setResponseMIMEType(const String& type)
812 {
813 m_responseMIMEType = type;
814 }
815
begin()816 void FrameLoader::begin()
817 {
818 begin(KURL());
819 }
820
begin(const KURL & url,bool dispatch,SecurityOrigin * origin)821 void FrameLoader::begin(const KURL& url, bool dispatch, SecurityOrigin* origin)
822 {
823 // We need to take a reference to the security origin because |clear|
824 // might destroy the document that owns it.
825 RefPtr<SecurityOrigin> forcedSecurityOrigin = origin;
826
827 RefPtr<Document> document;
828
829 // Create a new document before clearing the frame, because it may need to inherit an aliased security context.
830 if (!m_isDisplayingInitialEmptyDocument && m_client->shouldUsePluginDocument(m_responseMIMEType))
831 document = PluginDocument::create(m_frame);
832 else if (!m_client->hasHTMLView())
833 document = PlaceholderDocument::create(m_frame);
834 else
835 document = DOMImplementation::createDocument(m_responseMIMEType, m_frame, m_frame->inViewSourceMode());
836
837 bool resetScripting = !(m_isDisplayingInitialEmptyDocument && m_frame->document()->securityOrigin()->isSecureTransitionTo(url));
838 clear(resetScripting, resetScripting);
839 if (resetScripting)
840 m_frame->script()->updatePlatformScriptObjects();
841
842 m_needsClear = true;
843 m_isComplete = false;
844 m_didCallImplicitClose = false;
845 m_isLoadingMainResource = true;
846 m_isDisplayingInitialEmptyDocument = m_creatingInitialEmptyDocument;
847
848 KURL ref(url);
849 ref.setUser(String());
850 ref.setPass(String());
851 ref.removeFragmentIdentifier();
852 m_outgoingReferrer = ref.string();
853 m_URL = url;
854
855 document->setURL(m_URL);
856 m_frame->setDocument(document);
857
858 if (m_pendingStateObject) {
859 document->statePopped(m_pendingStateObject.get());
860 m_pendingStateObject.clear();
861 }
862
863 if (m_decoder)
864 document->setDecoder(m_decoder.get());
865 if (forcedSecurityOrigin)
866 document->setSecurityOrigin(forcedSecurityOrigin.get());
867
868 m_frame->domWindow()->setURL(document->url());
869 m_frame->domWindow()->setSecurityOrigin(document->securityOrigin());
870
871 if (dispatch)
872 dispatchDidClearWindowObjectsInAllWorlds();
873
874 updateFirstPartyForCookies();
875
876 Settings* settings = document->settings();
877 document->docLoader()->setAutoLoadImages(settings && settings->loadsImagesAutomatically());
878 #ifdef ANDROID_BLOCK_NETWORK_IMAGE
879 document->docLoader()->setBlockNetworkImage(settings && settings->blockNetworkImage());
880 #endif
881
882 if (m_documentLoader) {
883 String dnsPrefetchControl = m_documentLoader->response().httpHeaderField("X-DNS-Prefetch-Control");
884 if (!dnsPrefetchControl.isEmpty())
885 document->parseDNSPrefetchControlHeader(dnsPrefetchControl);
886 }
887
888 history()->restoreDocumentState();
889
890 document->implicitOpen();
891
892 if (m_frame->view() && m_client->hasHTMLView())
893 m_frame->view()->setContentsSize(IntSize());
894 }
895
write(const char * str,int len,bool flush)896 void FrameLoader::write(const char* str, int len, bool flush)
897 {
898 if (len == 0 && !flush)
899 return;
900
901 if (len == -1)
902 len = strlen(str);
903
904 Tokenizer* tokenizer = m_frame->document()->tokenizer();
905 if (tokenizer && tokenizer->wantsRawData()) {
906 if (len > 0)
907 tokenizer->writeRawData(str, len);
908 return;
909 }
910
911 if (!m_decoder) {
912 if (Settings* settings = m_frame->settings()) {
913 m_decoder = TextResourceDecoder::create(m_responseMIMEType,
914 settings->defaultTextEncodingName(),
915 settings->usesEncodingDetector());
916 Frame* parentFrame = m_frame->tree()->parent();
917 // Set the hint encoding to the parent frame encoding only if
918 // the parent and the current frames share the security origin.
919 // We impose this condition because somebody can make a child frame
920 // containing a carefully crafted html/javascript in one encoding
921 // that can be mistaken for hintEncoding (or related encoding) by
922 // an auto detector. When interpreted in the latter, it could be
923 // an attack vector.
924 // FIXME: This might be too cautious for non-7bit-encodings and
925 // we may consider relaxing this later after testing.
926 if (canReferToParentFrameEncoding(m_frame, parentFrame))
927 m_decoder->setHintEncoding(parentFrame->document()->decoder());
928 } else
929 m_decoder = TextResourceDecoder::create(m_responseMIMEType, String());
930 Frame* parentFrame = m_frame->tree()->parent();
931 if (m_encoding.isEmpty()) {
932 if (canReferToParentFrameEncoding(m_frame, parentFrame))
933 m_decoder->setEncoding(parentFrame->document()->inputEncoding(), TextResourceDecoder::EncodingFromParentFrame);
934 } else {
935 m_decoder->setEncoding(m_encoding,
936 m_encodingWasChosenByUser ? TextResourceDecoder::UserChosenEncoding : TextResourceDecoder::EncodingFromHTTPHeader);
937 }
938 m_frame->document()->setDecoder(m_decoder.get());
939 }
940
941 String decoded = m_decoder->decode(str, len);
942 if (flush)
943 decoded += m_decoder->flush();
944 if (decoded.isEmpty())
945 return;
946
947 if (!m_receivedData) {
948 m_receivedData = true;
949 if (m_decoder->encoding().usesVisualOrdering())
950 m_frame->document()->setVisuallyOrdered();
951 m_frame->document()->recalcStyle(Node::Force);
952 }
953
954 if (tokenizer) {
955 ASSERT(!tokenizer->wantsRawData());
956 tokenizer->write(decoded, true);
957 }
958 }
959
write(const String & str)960 void FrameLoader::write(const String& str)
961 {
962 if (str.isNull())
963 return;
964
965 if (!m_receivedData) {
966 m_receivedData = true;
967 m_frame->document()->setParseMode(Document::Strict);
968 }
969
970 if (Tokenizer* tokenizer = m_frame->document()->tokenizer())
971 tokenizer->write(str, true);
972 }
973
end()974 void FrameLoader::end()
975 {
976 m_isLoadingMainResource = false;
977 endIfNotLoadingMainResource();
978 }
979
endIfNotLoadingMainResource()980 void FrameLoader::endIfNotLoadingMainResource()
981 {
982 if (m_isLoadingMainResource || !m_frame->page() || !m_frame->document())
983 return;
984
985 // http://bugs.webkit.org/show_bug.cgi?id=10854
986 // The frame's last ref may be removed and it can be deleted by checkCompleted(),
987 // so we'll add a protective refcount
988 RefPtr<Frame> protector(m_frame);
989
990 // make sure nothing's left in there
991 write(0, 0, true);
992 m_frame->document()->finishParsing();
993 }
994
iconLoadDecisionAvailable()995 void FrameLoader::iconLoadDecisionAvailable()
996 {
997 if (!m_mayLoadIconLater)
998 return;
999 LOG(IconDatabase, "FrameLoader %p was told a load decision is available for its icon", this);
1000 startIconLoader();
1001 m_mayLoadIconLater = false;
1002 }
1003
startIconLoader()1004 void FrameLoader::startIconLoader()
1005 {
1006 // FIXME: We kick off the icon loader when the frame is done receiving its main resource.
1007 // But we should instead do it when we're done parsing the head element.
1008 if (!isLoadingMainFrame())
1009 return;
1010
1011 if (!iconDatabase() || !iconDatabase()->isEnabled())
1012 return;
1013
1014 KURL url(iconURL());
1015 String urlString(url.string());
1016 if (urlString.isEmpty())
1017 return;
1018
1019 // If we're not reloading and the icon database doesn't say to load now then bail before we actually start the load
1020 if (loadType() != FrameLoadTypeReload && loadType() != FrameLoadTypeReloadFromOrigin) {
1021 IconLoadDecision decision = iconDatabase()->loadDecisionForIconURL(urlString, m_documentLoader.get());
1022 if (decision == IconLoadNo) {
1023 LOG(IconDatabase, "FrameLoader::startIconLoader() - Told not to load this icon, committing iconURL %s to database for pageURL mapping", urlString.ascii().data());
1024 commitIconURLToIconDatabase(url);
1025
1026 // We were told not to load this icon - that means this icon is already known by the database
1027 // 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
1028 // has done it. This is after registering for the notification so the WebView can call the appropriate delegate method.
1029 // Otherwise if the icon data *is* available, notify the delegate
1030 if (!iconDatabase()->iconDataKnownForIconURL(urlString)) {
1031 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());
1032 m_client->registerForIconNotification();
1033 iconDatabase()->iconForPageURL(m_URL.string(), IntSize(0, 0));
1034 iconDatabase()->iconForPageURL(originalRequestURL().string(), IntSize(0, 0));
1035 } else
1036 m_client->dispatchDidReceiveIcon();
1037
1038 return;
1039 }
1040
1041 if (decision == IconLoadUnknown) {
1042 // In this case, we may end up loading the icon later, but we still want to commit the icon url mapping to the database
1043 // 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
1044 // We also tell the client to register for the notification that the icon is received now so it isn't missed in case the
1045 // icon is later read in from disk
1046 LOG(IconDatabase, "FrameLoader %p might load icon %s later", this, urlString.ascii().data());
1047 m_mayLoadIconLater = true;
1048 m_client->registerForIconNotification();
1049 commitIconURLToIconDatabase(url);
1050 return;
1051 }
1052 }
1053
1054 // People who want to avoid loading images generally want to avoid loading all images.
1055 // Now that we've accounted for URL mapping, avoid starting the network load if images aren't set to display automatically.
1056 Settings* settings = m_frame->settings();
1057 if (settings && !settings->loadsImagesAutomatically())
1058 return;
1059
1060 // This is either a reload or the icon database said "yes, load the icon", so kick off the load!
1061 if (!m_iconLoader)
1062 m_iconLoader.set(IconLoader::create(m_frame).release());
1063
1064 m_iconLoader->startLoading();
1065 }
1066
commitIconURLToIconDatabase(const KURL & icon)1067 void FrameLoader::commitIconURLToIconDatabase(const KURL& icon)
1068 {
1069 ASSERT(iconDatabase());
1070 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());
1071 iconDatabase()->setIconURLForPageURL(icon.string(), m_URL.string());
1072 iconDatabase()->setIconURLForPageURL(icon.string(), originalRequestURL().string());
1073 }
1074
finishedParsing()1075 void FrameLoader::finishedParsing()
1076 {
1077 if (m_creatingInitialEmptyDocument)
1078 return;
1079
1080 m_frame->injectUserScripts(InjectAtDocumentEnd);
1081
1082 // This can be called from the Frame's destructor, in which case we shouldn't protect ourselves
1083 // because doing so will cause us to re-enter the destructor when protector goes out of scope.
1084 // Null-checking the FrameView indicates whether or not we're in the destructor.
1085 RefPtr<Frame> protector = m_frame->view() ? m_frame : 0;
1086
1087 m_client->dispatchDidFinishDocumentLoad();
1088
1089 checkCompleted();
1090
1091 if (!m_frame->view())
1092 return; // We are being destroyed by something checkCompleted called.
1093
1094 // Check if the scrollbars are really needed for the content.
1095 // If not, remove them, relayout, and repaint.
1096 m_frame->view()->restoreScrollbar();
1097 m_frame->view()->scrollToFragment(m_URL);
1098 }
1099
loadDone()1100 void FrameLoader::loadDone()
1101 {
1102 checkCompleted();
1103 }
1104
allChildrenAreComplete() const1105 bool FrameLoader::allChildrenAreComplete() const
1106 {
1107 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) {
1108 if (!child->loader()->m_isComplete)
1109 return false;
1110 }
1111 return true;
1112 }
1113
allAncestorsAreComplete() const1114 bool FrameLoader::allAncestorsAreComplete() const
1115 {
1116 for (Frame* ancestor = m_frame; ancestor; ancestor = ancestor->tree()->parent()) {
1117 if (!ancestor->loader()->m_isComplete)
1118 return false;
1119 }
1120 return true;
1121 }
1122
checkCompleted()1123 void FrameLoader::checkCompleted()
1124 {
1125 m_shouldCallCheckCompleted = false;
1126
1127 if (m_frame->view())
1128 m_frame->view()->checkStopDelayingDeferredRepaints();
1129
1130 // Any frame that hasn't completed yet?
1131 if (!allChildrenAreComplete())
1132 return;
1133
1134 // Have we completed before?
1135 if (m_isComplete)
1136 return;
1137
1138 // Are we still parsing?
1139 if (m_frame->document()->parsing())
1140 return;
1141
1142 // Still waiting for images/scripts?
1143 if (numRequests(m_frame->document()))
1144 return;
1145
1146 // OK, completed.
1147 m_isComplete = true;
1148
1149 RefPtr<Frame> protect(m_frame);
1150 checkCallImplicitClose(); // if we didn't do it before
1151
1152 m_frame->redirectScheduler()->startTimer();
1153
1154 completed();
1155 if (m_frame->page())
1156 checkLoadComplete();
1157 }
1158
checkTimerFired(Timer<FrameLoader> *)1159 void FrameLoader::checkTimerFired(Timer<FrameLoader>*)
1160 {
1161 if (Page* page = m_frame->page()) {
1162 if (page->defersLoading())
1163 return;
1164 }
1165 if (m_shouldCallCheckCompleted)
1166 checkCompleted();
1167 if (m_shouldCallCheckLoadComplete)
1168 checkLoadComplete();
1169 }
1170
startCheckCompleteTimer()1171 void FrameLoader::startCheckCompleteTimer()
1172 {
1173 if (!(m_shouldCallCheckCompleted || m_shouldCallCheckLoadComplete))
1174 return;
1175 if (m_checkTimer.isActive())
1176 return;
1177 m_checkTimer.startOneShot(0);
1178 }
1179
scheduleCheckCompleted()1180 void FrameLoader::scheduleCheckCompleted()
1181 {
1182 m_shouldCallCheckCompleted = true;
1183 startCheckCompleteTimer();
1184 }
1185
scheduleCheckLoadComplete()1186 void FrameLoader::scheduleCheckLoadComplete()
1187 {
1188 m_shouldCallCheckLoadComplete = true;
1189 startCheckCompleteTimer();
1190 }
1191
checkCallImplicitClose()1192 void FrameLoader::checkCallImplicitClose()
1193 {
1194 if (m_didCallImplicitClose || m_frame->document()->parsing())
1195 return;
1196
1197 if (!allChildrenAreComplete())
1198 return; // still got a frame running -> too early
1199
1200 m_didCallImplicitClose = true;
1201 m_wasUnloadEventEmitted = false;
1202 m_frame->document()->implicitClose();
1203 }
1204
baseURL() const1205 KURL FrameLoader::baseURL() const
1206 {
1207 ASSERT(m_frame->document());
1208 return m_frame->document()->baseURL();
1209 }
1210
completeURL(const String & url)1211 KURL FrameLoader::completeURL(const String& url)
1212 {
1213 ASSERT(m_frame->document());
1214 return m_frame->document()->completeURL(url);
1215 }
1216
loadURLIntoChildFrame(const KURL & url,const String & referer,Frame * childFrame)1217 void FrameLoader::loadURLIntoChildFrame(const KURL& url, const String& referer, Frame* childFrame)
1218 {
1219 ASSERT(childFrame);
1220
1221 HistoryItem* parentItem = history()->currentItem();
1222 FrameLoadType loadType = this->loadType();
1223 FrameLoadType childLoadType = FrameLoadTypeRedirectWithLockedBackForwardList;
1224
1225 KURL workingURL = url;
1226
1227 // If we're moving in the back/forward list, we might want to replace the content
1228 // of this child frame with whatever was there at that point.
1229 if (parentItem && parentItem->children().size() && isBackForwardLoadType(loadType)) {
1230 HistoryItem* childItem = parentItem->childItemWithTarget(childFrame->tree()->name());
1231 if (childItem) {
1232 // Use the original URL to ensure we get all the side-effects, such as
1233 // onLoad handlers, of any redirects that happened. An example of where
1234 // this is needed is Radar 3213556.
1235 workingURL = KURL(ParsedURLString, childItem->originalURLString());
1236 childLoadType = loadType;
1237 childFrame->loader()->history()->setProvisionalItem(childItem);
1238 }
1239 }
1240
1241 #if ENABLE(ARCHIVE) // ANDROID extension: disabled to reduce code size
1242 RefPtr<Archive> subframeArchive = activeDocumentLoader()->popArchiveForSubframe(childFrame->tree()->name());
1243
1244 if (subframeArchive)
1245 childFrame->loader()->loadArchive(subframeArchive.release());
1246 else
1247 #endif
1248 #ifdef ANDROID_USER_GESTURE
1249 childFrame->loader()->loadURL(workingURL, referer, String(), false, childLoadType, 0, 0, false);
1250 #else
1251 childFrame->loader()->loadURL(workingURL, referer, String(), false, childLoadType, 0, 0);
1252 #endif
1253 }
1254
1255 #if ENABLE(ARCHIVE) // ANDROID extension: disabled to reduce code size
loadArchive(PassRefPtr<Archive> prpArchive)1256 void FrameLoader::loadArchive(PassRefPtr<Archive> prpArchive)
1257 {
1258 RefPtr<Archive> archive = prpArchive;
1259
1260 ArchiveResource* mainResource = archive->mainResource();
1261 ASSERT(mainResource);
1262 if (!mainResource)
1263 return;
1264
1265 SubstituteData substituteData(mainResource->data(), mainResource->mimeType(), mainResource->textEncoding(), KURL());
1266
1267 ResourceRequest request(mainResource->url());
1268 #if PLATFORM(MAC)
1269 request.applyWebArchiveHackForMail();
1270 #endif
1271
1272 RefPtr<DocumentLoader> documentLoader = m_client->createDocumentLoader(request, substituteData);
1273 documentLoader->addAllArchiveResources(archive.get());
1274 load(documentLoader.get());
1275 }
1276 #endif
1277
encoding() const1278 String FrameLoader::encoding() const
1279 {
1280 if (m_encodingWasChosenByUser && !m_encoding.isEmpty())
1281 return m_encoding;
1282 if (m_decoder && m_decoder->encoding().isValid())
1283 return m_decoder->encoding().name();
1284 Settings* settings = m_frame->settings();
1285 return settings ? settings->defaultTextEncodingName() : String();
1286 }
1287
requestObject(RenderPart * renderer,const String & url,const AtomicString & frameName,const String & mimeType,const Vector<String> & paramNames,const Vector<String> & paramValues)1288 bool FrameLoader::requestObject(RenderPart* renderer, const String& url, const AtomicString& frameName,
1289 const String& mimeType, const Vector<String>& paramNames, const Vector<String>& paramValues)
1290 {
1291 if (url.isEmpty() && mimeType.isEmpty())
1292 return false;
1293
1294 if (!m_frame->script()->xssAuditor()->canLoadObject(url)) {
1295 // It is unsafe to honor the request for this object.
1296 return false;
1297 }
1298
1299 KURL completedURL;
1300 if (!url.isEmpty())
1301 completedURL = completeURL(url);
1302
1303 bool useFallback;
1304 if (shouldUsePlugin(completedURL, mimeType, renderer->hasFallbackContent(), useFallback)) {
1305 Settings* settings = m_frame->settings();
1306 if (!m_client->allowPlugins(settings && settings->arePluginsEnabled())
1307 || (!settings->isJavaEnabled() && MIMETypeRegistry::isJavaAppletMIMEType(mimeType)))
1308 return false;
1309 if (isDocumentSandboxed(SandboxPlugins))
1310 return false;
1311 return loadPlugin(renderer, completedURL, mimeType, paramNames, paramValues, useFallback);
1312 }
1313
1314 ASSERT(renderer->node()->hasTagName(objectTag) || renderer->node()->hasTagName(embedTag));
1315 HTMLPlugInElement* element = static_cast<HTMLPlugInElement*>(renderer->node());
1316
1317 // If the plug-in element already contains a subframe, requestFrame will re-use it. Otherwise,
1318 // it will create a new frame and set it as the RenderPart's widget, causing what was previously
1319 // in the widget to be torn down.
1320 return requestFrame(element, completedURL, frameName);
1321 }
1322
shouldUsePlugin(const KURL & url,const String & mimeType,bool hasFallback,bool & useFallback)1323 bool FrameLoader::shouldUsePlugin(const KURL& url, const String& mimeType, bool hasFallback, bool& useFallback)
1324 {
1325 if (m_client->shouldUsePluginDocument(mimeType)) {
1326 useFallback = false;
1327 return true;
1328 }
1329
1330 // Allow other plug-ins to win over QuickTime because if the user has installed a plug-in that
1331 // can handle TIFF (which QuickTime can also handle) they probably intended to override QT.
1332 if (m_frame->page() && (mimeType == "image/tiff" || mimeType == "image/tif" || mimeType == "image/x-tiff")) {
1333 const PluginData* pluginData = m_frame->page()->pluginData();
1334 String pluginName = pluginData ? pluginData->pluginNameForMimeType(mimeType) : String();
1335 if (!pluginName.isEmpty() && !pluginName.contains("QuickTime", false))
1336 return true;
1337 }
1338
1339 ObjectContentType objectType = m_client->objectContentType(url, mimeType);
1340 // If an object's content can't be handled and it has no fallback, let
1341 // it be handled as a plugin to show the broken plugin icon.
1342 useFallback = objectType == ObjectContentNone && hasFallback;
1343 return objectType == ObjectContentNone || objectType == ObjectContentNetscapePlugin || objectType == ObjectContentOtherPlugin;
1344 }
1345
defaultObjectContentType(const KURL & url,const String & mimeTypeIn)1346 ObjectContentType FrameLoader::defaultObjectContentType(const KURL& url, const String& mimeTypeIn)
1347 {
1348 String mimeType = mimeTypeIn;
1349 // We don't use MIMETypeRegistry::getMIMETypeForPath() because it returns "application/octet-stream" upon failure
1350 if (mimeType.isEmpty())
1351 mimeType = MIMETypeRegistry::getMIMETypeForExtension(url.path().substring(url.path().reverseFind('.') + 1));
1352
1353 if (mimeType.isEmpty())
1354 return ObjectContentFrame; // Go ahead and hope that we can display the content.
1355
1356 if (MIMETypeRegistry::isSupportedImageMIMEType(mimeType))
1357 return WebCore::ObjectContentImage;
1358
1359 #if !PLATFORM(MAC) && !PLATFORM(CHROMIUM) // Mac has no PluginDatabase, nor does Chromium
1360 if (PluginDatabase::installedPlugins()->isMIMETypeRegistered(mimeType))
1361 return WebCore::ObjectContentNetscapePlugin;
1362 #endif
1363
1364 if (MIMETypeRegistry::isSupportedNonImageMIMEType(mimeType))
1365 return WebCore::ObjectContentFrame;
1366
1367 return WebCore::ObjectContentNone;
1368 }
1369
toPlugInElement(Node * node)1370 static HTMLPlugInElement* toPlugInElement(Node* node)
1371 {
1372 if (!node)
1373 return 0;
1374
1375 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
1376 ASSERT(node->hasTagName(objectTag) || node->hasTagName(embedTag)
1377 || node->hasTagName(videoTag) || node->hasTagName(audioTag)
1378 || node->hasTagName(appletTag));
1379 #else
1380 ASSERT(node->hasTagName(objectTag) || node->hasTagName(embedTag)
1381 || node->hasTagName(appletTag));
1382 #endif
1383
1384 return static_cast<HTMLPlugInElement*>(node);
1385 }
1386
loadPlugin(RenderPart * renderer,const KURL & url,const String & mimeType,const Vector<String> & paramNames,const Vector<String> & paramValues,bool useFallback)1387 bool FrameLoader::loadPlugin(RenderPart* renderer, const KURL& url, const String& mimeType,
1388 const Vector<String>& paramNames, const Vector<String>& paramValues, bool useFallback)
1389 {
1390 RefPtr<Widget> widget;
1391
1392 if (renderer && !useFallback) {
1393 HTMLPlugInElement* element = toPlugInElement(renderer->node());
1394
1395 if (!SecurityOrigin::canLoad(url, String(), frame()->document())) {
1396 FrameLoader::reportLocalLoadFailed(m_frame, url.string());
1397 return false;
1398 }
1399
1400 checkIfRunInsecureContent(m_frame->document()->securityOrigin(), url);
1401
1402 widget = m_client->createPlugin(IntSize(renderer->contentWidth(), renderer->contentHeight()),
1403 element, url, paramNames, paramValues, mimeType,
1404 m_frame->document()->isPluginDocument() && !m_containsPlugIns);
1405 if (widget) {
1406 renderer->setWidget(widget);
1407 m_containsPlugIns = true;
1408 }
1409 }
1410
1411 return widget != 0;
1412 }
1413
outgoingReferrer() const1414 String FrameLoader::outgoingReferrer() const
1415 {
1416 return m_outgoingReferrer;
1417 }
1418
outgoingOrigin() const1419 String FrameLoader::outgoingOrigin() const
1420 {
1421 return m_frame->document()->securityOrigin()->toString();
1422 }
1423
isMixedContent(SecurityOrigin * context,const KURL & url)1424 bool FrameLoader::isMixedContent(SecurityOrigin* context, const KURL& url)
1425 {
1426 if (context->protocol() != "https")
1427 return false; // We only care about HTTPS security origins.
1428
1429 if (!url.isValid() || url.protocolIs("https") || url.protocolIs("about") || url.protocolIs("data"))
1430 return false; // Loading these protocols is secure.
1431
1432 return true;
1433 }
1434
checkIfDisplayInsecureContent(SecurityOrigin * context,const KURL & url)1435 void FrameLoader::checkIfDisplayInsecureContent(SecurityOrigin* context, const KURL& url)
1436 {
1437 if (!isMixedContent(context, url))
1438 return;
1439
1440 String message = String::format("The page at %s displayed insecure content from %s.\n",
1441 m_URL.string().utf8().data(), url.string().utf8().data());
1442 m_frame->domWindow()->console()->addMessage(HTMLMessageSource, LogMessageType, WarningMessageLevel, message, 1, String());
1443
1444 m_client->didDisplayInsecureContent();
1445 }
1446
checkIfRunInsecureContent(SecurityOrigin * context,const KURL & url)1447 void FrameLoader::checkIfRunInsecureContent(SecurityOrigin* context, const KURL& url)
1448 {
1449 if (!isMixedContent(context, url))
1450 return;
1451
1452 String message = String::format("The page at %s ran insecure content from %s.\n",
1453 m_URL.string().utf8().data(), url.string().utf8().data());
1454 m_frame->domWindow()->console()->addMessage(HTMLMessageSource, LogMessageType, WarningMessageLevel, message, 1, String());
1455
1456 m_client->didRunInsecureContent(context);
1457 }
1458
opener()1459 Frame* FrameLoader::opener()
1460 {
1461 return m_opener;
1462 }
1463
setOpener(Frame * opener)1464 void FrameLoader::setOpener(Frame* opener)
1465 {
1466 if (m_opener)
1467 m_opener->loader()->m_openedFrames.remove(m_frame);
1468 if (opener)
1469 opener->loader()->m_openedFrames.add(m_frame);
1470 m_opener = opener;
1471
1472 if (m_frame->document()) {
1473 m_frame->document()->initSecurityContext();
1474 m_frame->domWindow()->setSecurityOrigin(m_frame->document()->securityOrigin());
1475 }
1476 }
1477
handleFallbackContent()1478 void FrameLoader::handleFallbackContent()
1479 {
1480 HTMLFrameOwnerElement* owner = m_frame->ownerElement();
1481 if (!owner || !owner->hasTagName(objectTag))
1482 return;
1483 static_cast<HTMLObjectElement*>(owner)->renderFallbackContent();
1484 }
1485
provisionalLoadStarted()1486 void FrameLoader::provisionalLoadStarted()
1487 {
1488 #ifdef ANDROID_INSTRUMENT
1489 if (!m_frame->tree()->parent())
1490 android::TimeCounter::reset();
1491 #endif
1492 m_firstLayoutDone = false;
1493 m_frame->redirectScheduler()->cancel(true);
1494 m_client->provisionalLoadStarted();
1495 }
1496
isProcessingUserGesture()1497 bool FrameLoader::isProcessingUserGesture()
1498 {
1499 Frame* frame = m_frame->tree()->top();
1500 if (!frame->script()->canExecuteScripts())
1501 return true; // If JavaScript is disabled, a user gesture must have initiated the navigation.
1502 return frame->script()->processingUserGesture(mainThreadNormalWorld()); // FIXME: Use pageIsProcessingUserGesture.
1503 }
1504
resetMultipleFormSubmissionProtection()1505 void FrameLoader::resetMultipleFormSubmissionProtection()
1506 {
1507 m_submittedFormURL = KURL();
1508 }
1509
setEncoding(const String & name,bool userChosen)1510 void FrameLoader::setEncoding(const String& name, bool userChosen)
1511 {
1512 if (!m_workingURL.isEmpty())
1513 receivedFirstData();
1514 m_encoding = name;
1515 m_encodingWasChosenByUser = userChosen;
1516 }
1517
addData(const char * bytes,int length)1518 void FrameLoader::addData(const char* bytes, int length)
1519 {
1520 ASSERT(m_workingURL.isEmpty());
1521 ASSERT(m_frame->document());
1522 ASSERT(m_frame->document()->parsing());
1523 write(bytes, length);
1524 }
1525
1526 #if ENABLE(WML)
frameContainsWMLContent(Frame * frame)1527 static inline bool frameContainsWMLContent(Frame* frame)
1528 {
1529 Document* document = frame ? frame->document() : 0;
1530 if (!document)
1531 return false;
1532
1533 return document->containsWMLContent() || document->isWMLDocument();
1534 }
1535 #endif
1536
canCachePageContainingThisFrame()1537 bool FrameLoader::canCachePageContainingThisFrame()
1538 {
1539 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) {
1540 if (!child->loader()->canCachePageContainingThisFrame())
1541 return false;
1542 }
1543
1544 return m_documentLoader
1545 && m_documentLoader->mainDocumentError().isNull()
1546 // FIXME: If we ever change this so that frames with plug-ins will be cached,
1547 // we need to make sure that we don't cache frames that have outstanding NPObjects
1548 // (objects created by the plug-in). Since there is no way to pause/resume a Netscape plug-in,
1549 // they would need to be destroyed and then recreated, and there is no way that we can recreate
1550 // the right NPObjects. See <rdar://problem/5197041> for more information.
1551 && !m_containsPlugIns
1552 && !m_URL.protocolIs("https")
1553 && (!m_frame->domWindow() || !m_frame->domWindow()->hasEventListeners(eventNames().unloadEvent))
1554 #if ENABLE(DATABASE)
1555 && !m_frame->document()->hasOpenDatabases()
1556 #endif
1557 #if ENABLE(SHARED_WORKERS)
1558 && !SharedWorkerRepository::hasSharedWorkers(m_frame->document())
1559 #endif
1560 && !m_frame->document()->usingGeolocation()
1561 && history()->currentItem()
1562 && !m_quickRedirectComing
1563 && !m_documentLoader->isLoadingInAPISense()
1564 && !m_documentLoader->isStopping()
1565 && m_frame->document()->canSuspendActiveDOMObjects()
1566 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
1567 // FIXME: We should investigating caching frames that have an associated
1568 // application cache. <rdar://problem/5917899> tracks that work.
1569 && m_documentLoader->applicationCacheHost()->canCacheInPageCache()
1570 #endif
1571 #if ENABLE(WML)
1572 && !frameContainsWMLContent(m_frame)
1573 #endif
1574 && m_client->canCachePage()
1575 ;
1576 }
1577
canCachePage()1578 bool FrameLoader::canCachePage()
1579 {
1580 #ifndef NDEBUG
1581 logCanCachePageDecision();
1582 #endif
1583
1584 // Cache the page, if possible.
1585 // Don't write to the cache if in the middle of a redirect, since we will want to
1586 // store the final page we end up on.
1587 // No point writing to the cache on a reload or loadSame, since we will just write
1588 // over it again when we leave that page.
1589 // FIXME: <rdar://problem/4886592> - We should work out the complexities of caching pages with frames as they
1590 // are the most interesting pages on the web, and often those that would benefit the most from caching!
1591 FrameLoadType loadType = this->loadType();
1592
1593 return !m_frame->tree()->parent()
1594 && canCachePageContainingThisFrame()
1595 && m_frame->page()
1596 && m_frame->page()->backForwardList()->enabled()
1597 && m_frame->page()->backForwardList()->capacity() > 0
1598 && m_frame->page()->settings()->usesPageCache()
1599 && loadType != FrameLoadTypeReload
1600 && loadType != FrameLoadTypeReloadFromOrigin
1601 && loadType != FrameLoadTypeSame
1602 ;
1603 }
1604
1605 #ifndef NDEBUG
pageCacheLogPrefix(int indentLevel)1606 static String& pageCacheLogPrefix(int indentLevel)
1607 {
1608 static int previousIndent = -1;
1609 DEFINE_STATIC_LOCAL(String, prefix, ());
1610
1611 if (indentLevel != previousIndent) {
1612 previousIndent = indentLevel;
1613 prefix.truncate(0);
1614 for (int i = 0; i < previousIndent; ++i)
1615 prefix += " ";
1616 }
1617
1618 return prefix;
1619 }
1620
pageCacheLog(const String & prefix,const String & message)1621 static void pageCacheLog(const String& prefix, const String& message)
1622 {
1623 LOG(PageCache, "%s%s", prefix.utf8().data(), message.utf8().data());
1624 }
1625
1626 #define PCLOG(...) pageCacheLog(pageCacheLogPrefix(indentLevel), String::format(__VA_ARGS__))
1627
logCanCachePageDecision()1628 void FrameLoader::logCanCachePageDecision()
1629 {
1630 // Only bother logging for main frames that have actually loaded and have content.
1631 if (m_creatingInitialEmptyDocument)
1632 return;
1633 KURL currentURL = m_documentLoader ? m_documentLoader->url() : KURL();
1634 if (currentURL.isEmpty())
1635 return;
1636
1637 int indentLevel = 0;
1638 PCLOG("--------\n Determining if page can be cached:");
1639
1640 bool cannotCache = !logCanCacheFrameDecision(1);
1641
1642 FrameLoadType loadType = this->loadType();
1643 do {
1644 if (m_frame->tree()->parent())
1645 { PCLOG(" -Frame has a parent frame"); cannotCache = true; }
1646 if (!m_frame->page()) {
1647 PCLOG(" -There is no Page object");
1648 cannotCache = true;
1649 break;
1650 }
1651 if (!m_frame->page()->backForwardList()->enabled())
1652 { PCLOG(" -The back/forward list is disabled"); cannotCache = true; }
1653 if (!(m_frame->page()->backForwardList()->capacity() > 0))
1654 { PCLOG(" -The back/forward list has a 0 capacity"); cannotCache = true; }
1655 if (!m_frame->page()->settings()->usesPageCache())
1656 { PCLOG(" -Page settings says b/f cache disabled"); cannotCache = true; }
1657 if (loadType == FrameLoadTypeReload)
1658 { PCLOG(" -Load type is: Reload"); cannotCache = true; }
1659 if (loadType == FrameLoadTypeReloadFromOrigin)
1660 { PCLOG(" -Load type is: Reload from origin"); cannotCache = true; }
1661 if (loadType == FrameLoadTypeSame)
1662 { PCLOG(" -Load type is: Same"); cannotCache = true; }
1663 } while (false);
1664
1665 PCLOG(cannotCache ? " Page CANNOT be cached\n--------" : " Page CAN be cached\n--------");
1666 }
1667
logCanCacheFrameDecision(int indentLevel)1668 bool FrameLoader::logCanCacheFrameDecision(int indentLevel)
1669 {
1670 // Only bother logging for frames that have actually loaded and have content.
1671 if (m_creatingInitialEmptyDocument)
1672 return false;
1673 KURL currentURL = m_documentLoader ? m_documentLoader->url() : KURL();
1674 if (currentURL.isEmpty())
1675 return false;
1676
1677 PCLOG("+---");
1678 KURL newURL = m_provisionalDocumentLoader ? m_provisionalDocumentLoader->url() : KURL();
1679 if (!newURL.isEmpty())
1680 PCLOG(" Determining if frame can be cached navigating from (%s) to (%s):", currentURL.string().utf8().data(), newURL.string().utf8().data());
1681 else
1682 PCLOG(" Determining if subframe with URL (%s) can be cached:", currentURL.string().utf8().data());
1683
1684 bool cannotCache = false;
1685
1686 do {
1687 if (!m_documentLoader) {
1688 PCLOG(" -There is no DocumentLoader object");
1689 cannotCache = true;
1690 break;
1691 }
1692 if (!m_documentLoader->mainDocumentError().isNull())
1693 { PCLOG(" -Main document has an error"); cannotCache = true; }
1694 if (m_containsPlugIns)
1695 { PCLOG(" -Frame contains plugins"); cannotCache = true; }
1696 if (m_URL.protocolIs("https"))
1697 { PCLOG(" -Frame is HTTPS"); cannotCache = true; }
1698 if (m_frame->domWindow() && m_frame->domWindow()->hasEventListeners(eventNames().unloadEvent))
1699 { PCLOG(" -Frame has an unload event listener"); cannotCache = true; }
1700 #if ENABLE(DATABASE)
1701 if (m_frame->document()->hasOpenDatabases())
1702 { PCLOG(" -Frame has open database handles"); cannotCache = true; }
1703 #endif
1704 #if ENABLE(SHARED_WORKERS)
1705 if (SharedWorkerRepository::hasSharedWorkers(m_frame->document()))
1706 { PCLOG(" -Frame has associated SharedWorkers"); cannotCache = true; }
1707 #endif
1708 if (m_frame->document()->usingGeolocation())
1709 { PCLOG(" -Frame uses Geolocation"); cannotCache = true; }
1710 if (!history()->currentItem())
1711 { PCLOG(" -No current history item"); cannotCache = true; }
1712 if (m_quickRedirectComing)
1713 { PCLOG(" -Quick redirect is coming"); cannotCache = true; }
1714 if (m_documentLoader->isLoadingInAPISense())
1715 { PCLOG(" -DocumentLoader is still loading in API sense"); cannotCache = true; }
1716 if (m_documentLoader->isStopping())
1717 { PCLOG(" -DocumentLoader is in the middle of stopping"); cannotCache = true; }
1718 if (!m_frame->document()->canSuspendActiveDOMObjects())
1719 { PCLOG(" -The document cannot suspect its active DOM Objects"); cannotCache = true; }
1720 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
1721 if (!m_documentLoader->applicationCacheHost()->canCacheInPageCache())
1722 { PCLOG(" -The DocumentLoader uses an application cache"); cannotCache = true; }
1723 #endif
1724 if (!m_client->canCachePage())
1725 { PCLOG(" -The client says this frame cannot be cached"); cannotCache = true; }
1726 } while (false);
1727
1728 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
1729 if (!child->loader()->logCanCacheFrameDecision(indentLevel + 1))
1730 cannotCache = true;
1731
1732 PCLOG(cannotCache ? " Frame CANNOT be cached" : " Frame CAN be cached");
1733 PCLOG("+---");
1734
1735 return !cannotCache;
1736 }
1737 #endif
1738
updateFirstPartyForCookies()1739 void FrameLoader::updateFirstPartyForCookies()
1740 {
1741 if (m_frame->tree()->parent())
1742 setFirstPartyForCookies(m_frame->tree()->parent()->document()->firstPartyForCookies());
1743 else
1744 setFirstPartyForCookies(m_URL);
1745 }
1746
setFirstPartyForCookies(const KURL & url)1747 void FrameLoader::setFirstPartyForCookies(const KURL& url)
1748 {
1749 m_frame->document()->setFirstPartyForCookies(url);
1750 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
1751 child->loader()->setFirstPartyForCookies(url);
1752 }
1753
1754 // This does the same kind of work that didOpenURL does, except it relies on the fact
1755 // that a higher level already checked that the URLs match and the scrolling is the right thing to do.
loadInSameDocument(const KURL & url,SerializedScriptValue * stateObject,bool isNewNavigation)1756 void FrameLoader::loadInSameDocument(const KURL& url, SerializedScriptValue* stateObject, bool isNewNavigation)
1757 {
1758 // If we have a state object, we cannot also be a new navigation.
1759 ASSERT(!stateObject || (stateObject && !isNewNavigation));
1760
1761 // Update the data source's request with the new URL to fake the URL change
1762 m_frame->document()->setURL(url);
1763 documentLoader()->replaceRequestURLForSameDocumentNavigation(url);
1764 if (isNewNavigation && !shouldTreatURLAsSameAsCurrent(url) && !stateObject) {
1765 // NB: must happen after replaceRequestURLForSameDocumentNavigation(), since we add
1766 // based on the current request. Must also happen before we openURL and displace the
1767 // scroll position, since adding the BF item will save away scroll state.
1768
1769 // NB2: If we were loading a long, slow doc, and the user anchor nav'ed before
1770 // it was done, currItem is now set the that slow doc, and prevItem is whatever was
1771 // before it. Adding the b/f item will bump the slow doc down to prevItem, even
1772 // though its load is not yet done. I think this all works out OK, for one because
1773 // we have already saved away the scroll and doc state for the long slow load,
1774 // but it's not an obvious case.
1775
1776 history()->updateBackForwardListForFragmentScroll();
1777 }
1778
1779 bool hashChange = equalIgnoringFragmentIdentifier(url, m_URL) && url.fragmentIdentifier() != m_URL.fragmentIdentifier();
1780 m_URL = url;
1781 history()->updateForSameDocumentNavigation();
1782
1783 // If we were in the autoscroll/panScroll mode we want to stop it before following the link to the anchor
1784 if (hashChange)
1785 m_frame->eventHandler()->stopAutoscrollTimer();
1786
1787 // It's important to model this as a load that starts and immediately finishes.
1788 // Otherwise, the parent frame may think we never finished loading.
1789 started();
1790
1791 if (hashChange) {
1792 if (FrameView* view = m_frame->view())
1793 view->scrollToFragment(m_URL);
1794 }
1795
1796 m_isComplete = false;
1797 checkCompleted();
1798
1799 if (isNewNavigation) {
1800 // This will clear previousItem from the rest of the frame tree that didn't
1801 // doing any loading. We need to make a pass on this now, since for anchor nav
1802 // we'll not go through a real load and reach Completed state.
1803 checkLoadComplete();
1804 }
1805
1806 if (stateObject) {
1807 m_frame->document()->statePopped(stateObject);
1808 m_client->dispatchDidPopStateWithinPage();
1809 }
1810
1811 if (hashChange) {
1812 m_frame->document()->dispatchWindowEvent(Event::create(eventNames().hashchangeEvent, false, false));
1813 m_client->dispatchDidChangeLocationWithinPage();
1814 }
1815
1816 // FrameLoaderClient::didFinishLoad() tells the internal load delegate the load finished with no error
1817 m_client->didFinishLoad();
1818 }
1819
isComplete() const1820 bool FrameLoader::isComplete() const
1821 {
1822 return m_isComplete;
1823 }
1824
completed()1825 void FrameLoader::completed()
1826 {
1827 RefPtr<Frame> protect(m_frame);
1828
1829 for (Frame* descendant = m_frame->tree()->traverseNext(m_frame); descendant; descendant = descendant->tree()->traverseNext(m_frame))
1830 descendant->redirectScheduler()->startTimer();
1831
1832 if (Frame* parent = m_frame->tree()->parent())
1833 parent->loader()->checkCompleted();
1834
1835 if (m_frame->view())
1836 m_frame->view()->maintainScrollPositionAtAnchor(0);
1837 }
1838
started()1839 void FrameLoader::started()
1840 {
1841 for (Frame* frame = m_frame; frame; frame = frame->tree()->parent())
1842 frame->loader()->m_isComplete = false;
1843 }
1844
containsPlugins() const1845 bool FrameLoader::containsPlugins() const
1846 {
1847 return m_containsPlugIns;
1848 }
1849
prepareForLoadStart()1850 void FrameLoader::prepareForLoadStart()
1851 {
1852 if (Page* page = m_frame->page())
1853 page->progress()->progressStarted(m_frame);
1854 m_client->dispatchDidStartProvisionalLoad();
1855 }
1856
setupForReplace()1857 void FrameLoader::setupForReplace()
1858 {
1859 setState(FrameStateProvisional);
1860 m_provisionalDocumentLoader = m_documentLoader;
1861 m_documentLoader = 0;
1862 detachChildren();
1863 }
1864
setupForReplaceByMIMEType(const String & newMIMEType)1865 void FrameLoader::setupForReplaceByMIMEType(const String& newMIMEType)
1866 {
1867 activeDocumentLoader()->setupForReplaceByMIMEType(newMIMEType);
1868 }
1869
1870 // This is a hack to allow keep navigation to http/https feeds working. To remove this
1871 // we need to introduce new API akin to registerURLSchemeAsLocal, that registers a
1872 // protocols navigation policy.
isFeedWithNestedProtocolInHTTPFamily(const KURL & url)1873 static bool isFeedWithNestedProtocolInHTTPFamily(const KURL& url)
1874 {
1875 const String& urlString = url.string();
1876 if (!urlString.startsWith("feed", false))
1877 return false;
1878
1879 return urlString.startsWith("feed://", false)
1880 || urlString.startsWith("feed:http:", false) || urlString.startsWith("feed:https:", false)
1881 || urlString.startsWith("feeds:http:", false) || urlString.startsWith("feeds:https:", false)
1882 || urlString.startsWith("feedsearch:http:", false) || urlString.startsWith("feedsearch:https:", false);
1883 }
1884
loadFrameRequest(const FrameLoadRequest & request,bool lockHistory,bool lockBackForwardList,PassRefPtr<Event> event,PassRefPtr<FormState> formState,ReferrerPolicy referrerPolicy)1885 void FrameLoader::loadFrameRequest(const FrameLoadRequest& request, bool lockHistory, bool lockBackForwardList,
1886 PassRefPtr<Event> event, PassRefPtr<FormState> formState, ReferrerPolicy referrerPolicy)
1887 {
1888 KURL url = request.resourceRequest().url();
1889
1890 String referrer;
1891 String argsReferrer = request.resourceRequest().httpReferrer();
1892 if (!argsReferrer.isEmpty())
1893 referrer = argsReferrer;
1894 else
1895 referrer = m_outgoingReferrer;
1896
1897 ASSERT(frame()->document());
1898 if (SecurityOrigin::shouldTreatURLAsLocal(url.string()) && !isFeedWithNestedProtocolInHTTPFamily(url)) {
1899 if (!SecurityOrigin::canLoad(url, String(), frame()->document()) && !SecurityOrigin::canLoad(url, referrer, 0)) {
1900 FrameLoader::reportLocalLoadFailed(m_frame, url.string());
1901 return;
1902 }
1903 }
1904
1905 if (SecurityOrigin::shouldHideReferrer(url, referrer) || referrerPolicy == NoReferrer)
1906 referrer = String();
1907
1908 FrameLoadType loadType;
1909 if (request.resourceRequest().cachePolicy() == ReloadIgnoringCacheData)
1910 loadType = FrameLoadTypeReload;
1911 else if (lockBackForwardList)
1912 loadType = FrameLoadTypeRedirectWithLockedBackForwardList;
1913 else
1914 loadType = FrameLoadTypeStandard;
1915
1916 #ifdef ANDROID_USER_GESTURE
1917 if (request.resourceRequest().httpMethod() == "POST")
1918 loadPostRequest(request.resourceRequest(), referrer, request.frameName(), lockHistory, loadType, event, formState.get(), request.resourceRequest().getUserGesture());
1919 else
1920 loadURL(request.resourceRequest().url(), referrer, request.frameName(), lockHistory, loadType, event, formState.get(), request.resourceRequest().getUserGesture());
1921 #else
1922 if (request.resourceRequest().httpMethod() == "POST")
1923 loadPostRequest(request.resourceRequest(), referrer, request.frameName(), lockHistory, loadType, event, formState.get());
1924 else
1925 loadURL(request.resourceRequest().url(), referrer, request.frameName(), lockHistory, loadType, event, formState.get());
1926 #endif
1927
1928 // FIXME: It's possible this targetFrame will not be the same frame that was targeted by the actual
1929 // load if frame names have changed.
1930 Frame* sourceFrame = formState ? formState->sourceFrame() : m_frame;
1931 Frame* targetFrame = sourceFrame->loader()->findFrameForNavigation(request.frameName());
1932 if (targetFrame && targetFrame != sourceFrame) {
1933 if (Page* page = targetFrame->page())
1934 #ifdef ANDROID_USER_GESTURE
1935 page->chrome()->focus(request.resourceRequest().getUserGesture());
1936 #else
1937 page->chrome()->focus();
1938 #endif
1939 }
1940 }
1941
1942 #ifdef ANDROID_USER_GESTURE
loadURL(const KURL & newURL,const String & referrer,const String & frameName,bool lockHistory,FrameLoadType newLoadType,PassRefPtr<Event> event,PassRefPtr<FormState> prpFormState,bool userGesture)1943 void FrameLoader::loadURL(const KURL& newURL, const String& referrer, const String& frameName, bool lockHistory, FrameLoadType newLoadType,
1944 PassRefPtr<Event> event, PassRefPtr<FormState> prpFormState, bool userGesture)
1945 #else
1946 void FrameLoader::loadURL(const KURL& newURL, const String& referrer, const String& frameName, bool lockHistory, FrameLoadType newLoadType,
1947 PassRefPtr<Event> event, PassRefPtr<FormState> prpFormState)
1948 #endif
1949 {
1950 RefPtr<FormState> formState = prpFormState;
1951 bool isFormSubmission = formState;
1952
1953 ResourceRequest request(newURL);
1954 #ifdef ANDROID_USER_GESTURE
1955 request.setUserGesture(userGesture);
1956 #endif
1957 if (!referrer.isEmpty()) {
1958 request.setHTTPReferrer(referrer);
1959 RefPtr<SecurityOrigin> referrerOrigin = SecurityOrigin::createFromString(referrer);
1960 addHTTPOriginIfNeeded(request, referrerOrigin->toString());
1961 }
1962 addExtraFieldsToRequest(request, newLoadType, true, event || isFormSubmission);
1963 if (newLoadType == FrameLoadTypeReload || newLoadType == FrameLoadTypeReloadFromOrigin)
1964 request.setCachePolicy(ReloadIgnoringCacheData);
1965
1966 ASSERT(newLoadType != FrameLoadTypeSame);
1967
1968 // The search for a target frame is done earlier in the case of form submission.
1969 Frame* targetFrame = isFormSubmission ? 0 : findFrameForNavigation(frameName);
1970 if (targetFrame && targetFrame != m_frame) {
1971 #ifdef ANDROID_USER_GESTURE
1972 targetFrame->loader()->loadURL(newURL, referrer, String(), lockHistory, newLoadType, event, formState.release(), userGesture);
1973 #else
1974 targetFrame->loader()->loadURL(newURL, referrer, String(), lockHistory, newLoadType, event, formState.release());
1975 #endif
1976 return;
1977 }
1978
1979 if (m_unloadEventBeingDispatched)
1980 return;
1981
1982 NavigationAction action(newURL, newLoadType, isFormSubmission, event);
1983
1984 if (!targetFrame && !frameName.isEmpty()) {
1985 policyChecker()->checkNewWindowPolicy(action, FrameLoader::callContinueLoadAfterNewWindowPolicy,
1986 request, formState.release(), frameName, this);
1987 return;
1988 }
1989
1990 RefPtr<DocumentLoader> oldDocumentLoader = m_documentLoader;
1991
1992 bool sameURL = shouldTreatURLAsSameAsCurrent(newURL);
1993
1994 // Make sure to do scroll to anchor processing even if the URL is
1995 // exactly the same so pages with '#' links and DHTML side effects
1996 // work properly.
1997 if (shouldScrollToAnchor(isFormSubmission, newLoadType, newURL)) {
1998 oldDocumentLoader->setTriggeringAction(action);
1999 policyChecker()->stopCheck();
2000 policyChecker()->setLoadType(newLoadType);
2001 policyChecker()->checkNavigationPolicy(request, oldDocumentLoader.get(), formState.release(),
2002 callContinueFragmentScrollAfterNavigationPolicy, this);
2003 } else {
2004 // must grab this now, since this load may stop the previous load and clear this flag
2005 bool isRedirect = m_quickRedirectComing;
2006 loadWithNavigationAction(request, action, lockHistory, newLoadType, formState.release());
2007 if (isRedirect) {
2008 m_quickRedirectComing = false;
2009 if (m_provisionalDocumentLoader)
2010 m_provisionalDocumentLoader->setIsClientRedirect(true);
2011 } else if (sameURL)
2012 // Example of this case are sites that reload the same URL with a different cookie
2013 // driving the generated content, or a master frame with links that drive a target
2014 // frame, where the user has clicked on the same link repeatedly.
2015 m_loadType = FrameLoadTypeSame;
2016 }
2017 }
2018
load(const ResourceRequest & request,bool lockHistory)2019 void FrameLoader::load(const ResourceRequest& request, bool lockHistory)
2020 {
2021 load(request, SubstituteData(), lockHistory);
2022 }
2023
load(const ResourceRequest & request,const SubstituteData & substituteData,bool lockHistory)2024 void FrameLoader::load(const ResourceRequest& request, const SubstituteData& substituteData, bool lockHistory)
2025 {
2026 if (m_inStopAllLoaders)
2027 return;
2028
2029 // FIXME: is this the right place to reset loadType? Perhaps this should be done after loading is finished or aborted.
2030 m_loadType = FrameLoadTypeStandard;
2031 RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request, substituteData);
2032 if (lockHistory && m_documentLoader)
2033 loader->setClientRedirectSourceForHistory(m_documentLoader->didCreateGlobalHistoryEntry() ? m_documentLoader->urlForHistory() : m_documentLoader->clientRedirectSourceForHistory());
2034 load(loader.get());
2035 }
2036
load(const ResourceRequest & request,const String & frameName,bool lockHistory)2037 void FrameLoader::load(const ResourceRequest& request, const String& frameName, bool lockHistory)
2038 {
2039 if (frameName.isEmpty()) {
2040 load(request, lockHistory);
2041 return;
2042 }
2043
2044 Frame* frame = findFrameForNavigation(frameName);
2045 if (frame) {
2046 frame->loader()->load(request, lockHistory);
2047 return;
2048 }
2049
2050 policyChecker()->checkNewWindowPolicy(NavigationAction(request.url(), NavigationTypeOther), FrameLoader::callContinueLoadAfterNewWindowPolicy, request, 0, frameName, this);
2051 }
2052
loadWithNavigationAction(const ResourceRequest & request,const NavigationAction & action,bool lockHistory,FrameLoadType type,PassRefPtr<FormState> formState)2053 void FrameLoader::loadWithNavigationAction(const ResourceRequest& request, const NavigationAction& action, bool lockHistory, FrameLoadType type, PassRefPtr<FormState> formState)
2054 {
2055 RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request, SubstituteData());
2056 if (lockHistory && m_documentLoader)
2057 loader->setClientRedirectSourceForHistory(m_documentLoader->didCreateGlobalHistoryEntry() ? m_documentLoader->urlForHistory() : m_documentLoader->clientRedirectSourceForHistory());
2058
2059 loader->setTriggeringAction(action);
2060 if (m_documentLoader)
2061 loader->setOverrideEncoding(m_documentLoader->overrideEncoding());
2062
2063 loadWithDocumentLoader(loader.get(), type, formState);
2064 }
2065
load(DocumentLoader * newDocumentLoader)2066 void FrameLoader::load(DocumentLoader* newDocumentLoader)
2067 {
2068 ResourceRequest& r = newDocumentLoader->request();
2069 addExtraFieldsToMainResourceRequest(r);
2070 FrameLoadType type;
2071
2072 if (shouldTreatURLAsSameAsCurrent(newDocumentLoader->originalRequest().url())) {
2073 r.setCachePolicy(ReloadIgnoringCacheData);
2074 type = FrameLoadTypeSame;
2075 } else
2076 type = FrameLoadTypeStandard;
2077
2078 if (m_documentLoader)
2079 newDocumentLoader->setOverrideEncoding(m_documentLoader->overrideEncoding());
2080
2081 // When we loading alternate content for an unreachable URL that we're
2082 // visiting in the history list, we treat it as a reload so the history list
2083 // is appropriately maintained.
2084 //
2085 // FIXME: This seems like a dangerous overloading of the meaning of "FrameLoadTypeReload" ...
2086 // shouldn't a more explicit type of reload be defined, that means roughly
2087 // "load without affecting history" ?
2088 if (shouldReloadToHandleUnreachableURL(newDocumentLoader)) {
2089 ASSERT(type == FrameLoadTypeStandard);
2090 type = FrameLoadTypeReload;
2091 }
2092
2093 loadWithDocumentLoader(newDocumentLoader, type, 0);
2094 }
2095
loadWithDocumentLoader(DocumentLoader * loader,FrameLoadType type,PassRefPtr<FormState> prpFormState)2096 void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType type, PassRefPtr<FormState> prpFormState)
2097 {
2098 ASSERT(m_client->hasWebView());
2099
2100 // Unfortunately the view must be non-nil, this is ultimately due
2101 // to parser requiring a FrameView. We should fix this dependency.
2102
2103 ASSERT(m_frame->view());
2104
2105 if (m_unloadEventBeingDispatched)
2106 return;
2107
2108 policyChecker()->setLoadType(type);
2109 RefPtr<FormState> formState = prpFormState;
2110 bool isFormSubmission = formState;
2111
2112 const KURL& newURL = loader->request().url();
2113
2114 if (shouldScrollToAnchor(isFormSubmission, policyChecker()->loadType(), newURL)) {
2115 RefPtr<DocumentLoader> oldDocumentLoader = m_documentLoader;
2116 NavigationAction action(newURL, policyChecker()->loadType(), isFormSubmission);
2117
2118 oldDocumentLoader->setTriggeringAction(action);
2119 policyChecker()->stopCheck();
2120 policyChecker()->checkNavigationPolicy(loader->request(), oldDocumentLoader.get(), formState,
2121 callContinueFragmentScrollAfterNavigationPolicy, this);
2122 } else {
2123 if (Frame* parent = m_frame->tree()->parent())
2124 loader->setOverrideEncoding(parent->loader()->documentLoader()->overrideEncoding());
2125
2126 policyChecker()->stopCheck();
2127 setPolicyDocumentLoader(loader);
2128 if (loader->triggeringAction().isEmpty())
2129 loader->setTriggeringAction(NavigationAction(newURL, policyChecker()->loadType(), isFormSubmission));
2130
2131 if (Element* ownerElement = m_frame->document()->ownerElement()) {
2132 if (!ownerElement->dispatchBeforeLoadEvent(loader->request().url().string())) {
2133 continueLoadAfterNavigationPolicy(loader->request(), formState, false);
2134 return;
2135 }
2136 }
2137
2138 policyChecker()->checkNavigationPolicy(loader->request(), loader, formState,
2139 callContinueLoadAfterNavigationPolicy, this);
2140 }
2141 }
2142
reportLocalLoadFailed(Frame * frame,const String & url)2143 void FrameLoader::reportLocalLoadFailed(Frame* frame, const String& url)
2144 {
2145 ASSERT(!url.isEmpty());
2146 if (!frame)
2147 return;
2148
2149 frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "Not allowed to load local resource: " + url, 0, String());
2150 }
2151
initialRequest() const2152 const ResourceRequest& FrameLoader::initialRequest() const
2153 {
2154 return activeDocumentLoader()->originalRequest();
2155 }
2156
receivedData(const char * data,int length)2157 void FrameLoader::receivedData(const char* data, int length)
2158 {
2159 activeDocumentLoader()->receivedData(data, length);
2160 }
2161
willLoadMediaElementURL(KURL & url)2162 bool FrameLoader::willLoadMediaElementURL(KURL& url)
2163 {
2164 ResourceRequest request(url);
2165
2166 unsigned long identifier;
2167 ResourceError error;
2168 requestFromDelegate(request, identifier, error);
2169 notifier()->sendRemainingDelegateMessages(m_documentLoader.get(), identifier, ResourceResponse(url, String(), -1, String(), String()), -1, error);
2170
2171 url = request.url();
2172
2173 return error.isNull();
2174 }
2175
interruptionForPolicyChangeError(const ResourceRequest & request)2176 ResourceError FrameLoader::interruptionForPolicyChangeError(const ResourceRequest& request)
2177 {
2178 return m_client->interruptForPolicyChangeError(request);
2179 }
2180
shouldReloadToHandleUnreachableURL(DocumentLoader * docLoader)2181 bool FrameLoader::shouldReloadToHandleUnreachableURL(DocumentLoader* docLoader)
2182 {
2183 KURL unreachableURL = docLoader->unreachableURL();
2184
2185 if (unreachableURL.isEmpty())
2186 return false;
2187
2188 if (!isBackForwardLoadType(policyChecker()->loadType()))
2189 return false;
2190
2191 // We only treat unreachableURLs specially during the delegate callbacks
2192 // for provisional load errors and navigation policy decisions. The former
2193 // case handles well-formed URLs that can't be loaded, and the latter
2194 // case handles malformed URLs and unknown schemes. Loading alternate content
2195 // at other times behaves like a standard load.
2196 DocumentLoader* compareDocumentLoader = 0;
2197 if (policyChecker()->delegateIsDecidingNavigationPolicy() || policyChecker()->delegateIsHandlingUnimplementablePolicy())
2198 compareDocumentLoader = m_policyDocumentLoader.get();
2199 else if (m_delegateIsHandlingProvisionalLoadError)
2200 compareDocumentLoader = m_provisionalDocumentLoader.get();
2201
2202 return compareDocumentLoader && unreachableURL == compareDocumentLoader->request().url();
2203 }
2204
reloadWithOverrideEncoding(const String & encoding)2205 void FrameLoader::reloadWithOverrideEncoding(const String& encoding)
2206 {
2207 if (!m_documentLoader)
2208 return;
2209
2210 ResourceRequest request = m_documentLoader->request();
2211 KURL unreachableURL = m_documentLoader->unreachableURL();
2212 if (!unreachableURL.isEmpty())
2213 request.setURL(unreachableURL);
2214
2215 request.setCachePolicy(ReturnCacheDataElseLoad);
2216
2217 RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request, SubstituteData());
2218 setPolicyDocumentLoader(loader.get());
2219
2220 loader->setOverrideEncoding(encoding);
2221
2222 loadWithDocumentLoader(loader.get(), FrameLoadTypeReload, 0);
2223 }
2224
reload(bool endToEndReload)2225 void FrameLoader::reload(bool endToEndReload)
2226 {
2227 if (!m_documentLoader)
2228 return;
2229
2230 // If a window is created by javascript, its main frame can have an empty but non-nil URL.
2231 // Reloading in this case will lose the current contents (see 4151001).
2232 if (m_documentLoader->request().url().isEmpty())
2233 return;
2234
2235 ResourceRequest initialRequest = m_documentLoader->request();
2236
2237 // Replace error-page URL with the URL we were trying to reach.
2238 KURL unreachableURL = m_documentLoader->unreachableURL();
2239 if (!unreachableURL.isEmpty())
2240 initialRequest.setURL(unreachableURL);
2241
2242 // Create a new document loader for the reload, this will become m_documentLoader eventually,
2243 // but first it has to be the "policy" document loader, and then the "provisional" document loader.
2244 RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(initialRequest, SubstituteData());
2245
2246 ResourceRequest& request = loader->request();
2247
2248 // FIXME: We don't have a mechanism to revalidate the main resource without reloading at the moment.
2249 request.setCachePolicy(ReloadIgnoringCacheData);
2250
2251 // If we're about to re-post, set up action so the application can warn the user.
2252 if (request.httpMethod() == "POST")
2253 loader->setTriggeringAction(NavigationAction(request.url(), NavigationTypeFormResubmitted));
2254
2255 loader->setOverrideEncoding(m_documentLoader->overrideEncoding());
2256
2257 loadWithDocumentLoader(loader.get(), endToEndReload ? FrameLoadTypeReloadFromOrigin : FrameLoadTypeReload, 0);
2258 }
2259
canAccessAncestor(const SecurityOrigin * activeSecurityOrigin,Frame * targetFrame)2260 static bool canAccessAncestor(const SecurityOrigin* activeSecurityOrigin, Frame* targetFrame)
2261 {
2262 // targetFrame can be NULL when we're trying to navigate a top-level frame
2263 // that has a NULL opener.
2264 if (!targetFrame)
2265 return false;
2266
2267 for (Frame* ancestorFrame = targetFrame; ancestorFrame; ancestorFrame = ancestorFrame->tree()->parent()) {
2268 Document* ancestorDocument = ancestorFrame->document();
2269 if (!ancestorDocument)
2270 return true;
2271
2272 const SecurityOrigin* ancestorSecurityOrigin = ancestorDocument->securityOrigin();
2273 if (activeSecurityOrigin->canAccess(ancestorSecurityOrigin))
2274 return true;
2275 }
2276
2277 return false;
2278 }
2279
shouldAllowNavigation(Frame * targetFrame) const2280 bool FrameLoader::shouldAllowNavigation(Frame* targetFrame) const
2281 {
2282 // The navigation change is safe if the active frame is:
2283 // - in the same security origin as the target or one of the target's
2284 // ancestors.
2285 //
2286 // Or the target frame is:
2287 // - a top-level frame in the frame hierarchy and the active frame can
2288 // navigate the target frame's opener per above or it is the opener of
2289 // the target frame.
2290
2291 if (!targetFrame)
2292 return true;
2293
2294 // Performance optimization.
2295 if (m_frame == targetFrame)
2296 return true;
2297
2298 // A sandboxed frame can only navigate itself and its descendants.
2299 if (isDocumentSandboxed(SandboxNavigation) && !targetFrame->tree()->isDescendantOf(m_frame))
2300 return false;
2301
2302 // Let a frame navigate the top-level window that contains it. This is
2303 // important to allow because it lets a site "frame-bust" (escape from a
2304 // frame created by another web site).
2305 if (targetFrame == m_frame->tree()->top())
2306 return true;
2307
2308 // Let a frame navigate its opener if the opener is a top-level window.
2309 if (!targetFrame->tree()->parent() && m_frame->loader()->opener() == targetFrame)
2310 return true;
2311
2312 Document* activeDocument = m_frame->document();
2313 ASSERT(activeDocument);
2314 const SecurityOrigin* activeSecurityOrigin = activeDocument->securityOrigin();
2315
2316 // For top-level windows, check the opener.
2317 if (!targetFrame->tree()->parent() && canAccessAncestor(activeSecurityOrigin, targetFrame->loader()->opener()))
2318 return true;
2319
2320 // In general, check the frame's ancestors.
2321 if (canAccessAncestor(activeSecurityOrigin, targetFrame))
2322 return true;
2323
2324 Settings* settings = targetFrame->settings();
2325 if (settings && !settings->privateBrowsingEnabled()) {
2326 Document* targetDocument = targetFrame->document();
2327 // FIXME: this error message should contain more specifics of why the navigation change is not allowed.
2328 String message = String::format("Unsafe JavaScript attempt to initiate a navigation change for frame with URL %s from frame with URL %s.\n",
2329 targetDocument->url().string().utf8().data(), activeDocument->url().string().utf8().data());
2330
2331 // FIXME: should we print to the console of the activeFrame as well?
2332 targetFrame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, message, 1, String());
2333 }
2334
2335 return false;
2336 }
2337
stopLoadingSubframes()2338 void FrameLoader::stopLoadingSubframes()
2339 {
2340 for (RefPtr<Frame> child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
2341 child->loader()->stopAllLoaders();
2342 }
2343
stopAllLoaders(DatabasePolicy databasePolicy)2344 void FrameLoader::stopAllLoaders(DatabasePolicy databasePolicy)
2345 {
2346 ASSERT(!m_frame->document() || !m_frame->document()->inPageCache());
2347 if (m_unloadEventBeingDispatched)
2348 return;
2349
2350 // If this method is called from within this method, infinite recursion can occur (3442218). Avoid this.
2351 if (m_inStopAllLoaders)
2352 return;
2353
2354 m_inStopAllLoaders = true;
2355
2356 policyChecker()->stopCheck();
2357
2358 stopLoadingSubframes();
2359 if (m_provisionalDocumentLoader)
2360 m_provisionalDocumentLoader->stopLoading(databasePolicy);
2361 if (m_documentLoader)
2362 m_documentLoader->stopLoading(databasePolicy);
2363
2364 setProvisionalDocumentLoader(0);
2365
2366 #if ENABLE(ARCHIVE) // ANDROID extension: disabled to reduce code size
2367 if (m_documentLoader)
2368 m_documentLoader->clearArchiveResources();
2369 #endif
2370
2371 m_checkTimer.stop();
2372
2373 m_inStopAllLoaders = false;
2374 }
2375
stopForUserCancel(bool deferCheckLoadComplete)2376 void FrameLoader::stopForUserCancel(bool deferCheckLoadComplete)
2377 {
2378 stopAllLoaders();
2379
2380 if (deferCheckLoadComplete)
2381 scheduleCheckLoadComplete();
2382 else if (m_frame->page())
2383 checkLoadComplete();
2384 }
2385
activeDocumentLoader() const2386 DocumentLoader* FrameLoader::activeDocumentLoader() const
2387 {
2388 if (m_state == FrameStateProvisional)
2389 return m_provisionalDocumentLoader.get();
2390 return m_documentLoader.get();
2391 }
2392
isLoading() const2393 bool FrameLoader::isLoading() const
2394 {
2395 DocumentLoader* docLoader = activeDocumentLoader();
2396 if (!docLoader)
2397 return false;
2398 return docLoader->isLoadingMainResource() || docLoader->isLoadingSubresources() || docLoader->isLoadingPlugIns();
2399 }
2400
frameHasLoaded() const2401 bool FrameLoader::frameHasLoaded() const
2402 {
2403 return m_committedFirstRealDocumentLoad || (m_provisionalDocumentLoader && !m_creatingInitialEmptyDocument);
2404 }
2405
setDocumentLoader(DocumentLoader * loader)2406 void FrameLoader::setDocumentLoader(DocumentLoader* loader)
2407 {
2408 if (!loader && !m_documentLoader)
2409 return;
2410
2411 ASSERT(loader != m_documentLoader);
2412 ASSERT(!loader || loader->frameLoader() == this);
2413
2414 m_client->prepareForDataSourceReplacement();
2415 detachChildren();
2416 if (m_documentLoader)
2417 m_documentLoader->detachFromFrame();
2418
2419 m_documentLoader = loader;
2420 }
2421
setPolicyDocumentLoader(DocumentLoader * loader)2422 void FrameLoader::setPolicyDocumentLoader(DocumentLoader* loader)
2423 {
2424 if (m_policyDocumentLoader == loader)
2425 return;
2426
2427 ASSERT(m_frame);
2428 if (loader)
2429 loader->setFrame(m_frame);
2430 if (m_policyDocumentLoader
2431 && m_policyDocumentLoader != m_provisionalDocumentLoader
2432 && m_policyDocumentLoader != m_documentLoader)
2433 m_policyDocumentLoader->detachFromFrame();
2434
2435 m_policyDocumentLoader = loader;
2436 }
2437
setProvisionalDocumentLoader(DocumentLoader * loader)2438 void FrameLoader::setProvisionalDocumentLoader(DocumentLoader* loader)
2439 {
2440 ASSERT(!loader || !m_provisionalDocumentLoader);
2441 ASSERT(!loader || loader->frameLoader() == this);
2442
2443 if (m_provisionalDocumentLoader && m_provisionalDocumentLoader != m_documentLoader)
2444 m_provisionalDocumentLoader->detachFromFrame();
2445
2446 m_provisionalDocumentLoader = loader;
2447 }
2448
timeOfLastCompletedLoad()2449 double FrameLoader::timeOfLastCompletedLoad()
2450 {
2451 return storedTimeOfLastCompletedLoad;
2452 }
2453
setState(FrameState newState)2454 void FrameLoader::setState(FrameState newState)
2455 {
2456 m_state = newState;
2457
2458 if (newState == FrameStateProvisional)
2459 provisionalLoadStarted();
2460 else if (newState == FrameStateComplete) {
2461 frameLoadCompleted();
2462 storedTimeOfLastCompletedLoad = currentTime();
2463 if (m_documentLoader)
2464 m_documentLoader->stopRecordingResponses();
2465 }
2466 }
2467
clearProvisionalLoad()2468 void FrameLoader::clearProvisionalLoad()
2469 {
2470 setProvisionalDocumentLoader(0);
2471 if (Page* page = m_frame->page())
2472 page->progress()->progressCompleted(m_frame);
2473 setState(FrameStateComplete);
2474 }
2475
markLoadComplete()2476 void FrameLoader::markLoadComplete()
2477 {
2478 setState(FrameStateComplete);
2479 }
2480
commitProvisionalLoad(PassRefPtr<CachedPage> prpCachedPage)2481 void FrameLoader::commitProvisionalLoad(PassRefPtr<CachedPage> prpCachedPage)
2482 {
2483 RefPtr<CachedPage> cachedPage = prpCachedPage;
2484 RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader;
2485
2486 LOG(PageCache, "WebCoreLoading %s: About to commit provisional load from previous URL '%s' to new URL '%s'", m_frame->tree()->name().string().utf8().data(), m_URL.string().utf8().data(),
2487 pdl ? pdl->url().string().utf8().data() : "<no provisional DocumentLoader>");
2488
2489 // Check to see if we need to cache the page we are navigating away from into the back/forward cache.
2490 // We are doing this here because we know for sure that a new page is about to be loaded.
2491 cachePageForHistoryItem(history()->currentItem());
2492
2493 if (m_loadType != FrameLoadTypeReplace)
2494 closeOldDataSources();
2495
2496 if (!cachedPage && !m_creatingInitialEmptyDocument)
2497 m_client->makeRepresentation(pdl.get());
2498
2499 transitionToCommitted(cachedPage);
2500
2501 // Call clientRedirectCancelledOrFinished() here so that the frame load delegate is notified that the redirect's
2502 // status has changed, if there was a redirect. The frame load delegate may have saved some state about
2503 // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are
2504 // just about to commit a new page, there cannot possibly be a pending redirect at this point.
2505 if (m_sentRedirectNotification)
2506 clientRedirectCancelledOrFinished(false);
2507
2508 if (cachedPage && cachedPage->document())
2509 open(*cachedPage);
2510 else {
2511 KURL url = pdl->substituteData().responseURL();
2512 if (url.isEmpty())
2513 url = pdl->url();
2514 if (url.isEmpty())
2515 url = pdl->responseURL();
2516 if (url.isEmpty())
2517 url = blankURL();
2518
2519 didOpenURL(url);
2520 }
2521
2522 LOG(Loading, "WebCoreLoading %s: Finished committing provisional load to URL %s", m_frame->tree()->name().string().utf8().data(), m_URL.string().utf8().data());
2523
2524 if (m_loadType == FrameLoadTypeStandard && m_documentLoader->isClientRedirect())
2525 history()->updateForClientRedirect();
2526
2527 if (m_loadingFromCachedPage) {
2528 m_frame->document()->documentDidBecomeActive();
2529
2530 // Force a layout to update view size and thereby update scrollbars.
2531 m_frame->view()->forceLayout();
2532
2533 const ResponseVector& responses = m_documentLoader->responses();
2534 size_t count = responses.size();
2535 for (size_t i = 0; i < count; i++) {
2536 const ResourceResponse& response = responses[i];
2537 // FIXME: If the WebKit client changes or cancels the request, this is not respected.
2538 ResourceError error;
2539 unsigned long identifier;
2540 ResourceRequest request(response.url());
2541 requestFromDelegate(request, identifier, error);
2542 // FIXME: If we get a resource with more than 2B bytes, this code won't do the right thing.
2543 // However, with today's computers and networking speeds, this won't happen in practice.
2544 // Could be an issue with a giant local file.
2545 notifier()->sendRemainingDelegateMessages(m_documentLoader.get(), identifier, response, static_cast<int>(response.expectedContentLength()), error);
2546 }
2547
2548 pageCache()->remove(history()->currentItem());
2549
2550 m_documentLoader->setPrimaryLoadComplete(true);
2551
2552 // FIXME: Why only this frame and not parent frames?
2553 checkLoadCompleteForThisFrame();
2554 }
2555 }
2556
transitionToCommitted(PassRefPtr<CachedPage> cachedPage)2557 void FrameLoader::transitionToCommitted(PassRefPtr<CachedPage> cachedPage)
2558 {
2559 ASSERT(m_client->hasWebView());
2560 ASSERT(m_state == FrameStateProvisional);
2561
2562 if (m_state != FrameStateProvisional)
2563 return;
2564
2565 m_client->setCopiesOnScroll();
2566 history()->updateForCommit();
2567
2568 // The call to closeURL() invokes the unload event handler, which can execute arbitrary
2569 // JavaScript. If the script initiates a new load, we need to abandon the current load,
2570 // or the two will stomp each other.
2571 DocumentLoader* pdl = m_provisionalDocumentLoader.get();
2572 if (m_documentLoader)
2573 closeURL();
2574 if (pdl != m_provisionalDocumentLoader)
2575 return;
2576
2577 // Nothing else can interupt this commit - set the Provisional->Committed transition in stone
2578 if (m_documentLoader)
2579 m_documentLoader->stopLoadingSubresources();
2580 if (m_documentLoader)
2581 m_documentLoader->stopLoadingPlugIns();
2582
2583 setDocumentLoader(m_provisionalDocumentLoader.get());
2584 setProvisionalDocumentLoader(0);
2585 setState(FrameStateCommittedPage);
2586
2587 // Handle adding the URL to the back/forward list.
2588 DocumentLoader* dl = m_documentLoader.get();
2589 String ptitle = dl->title();
2590
2591 switch (m_loadType) {
2592 case FrameLoadTypeForward:
2593 case FrameLoadTypeBack:
2594 case FrameLoadTypeBackWMLDeckNotAccessible:
2595 case FrameLoadTypeIndexedBackForward:
2596 if (Page* page = m_frame->page()) {
2597 if (page->backForwardList()) {
2598 history()->updateForBackForwardNavigation();
2599
2600 if (history()->currentItem())
2601 m_pendingStateObject = history()->currentItem()->stateObject();
2602
2603 // Create a document view for this document, or used the cached view.
2604 if (cachedPage) {
2605 DocumentLoader* cachedDocumentLoader = cachedPage->documentLoader();
2606 ASSERT(cachedDocumentLoader);
2607 cachedDocumentLoader->setFrame(m_frame);
2608 m_client->transitionToCommittedFromCachedFrame(cachedPage->cachedMainFrame());
2609
2610 } else
2611 m_client->transitionToCommittedForNewPage();
2612 }
2613 }
2614 break;
2615
2616 case FrameLoadTypeReload:
2617 case FrameLoadTypeReloadFromOrigin:
2618 case FrameLoadTypeSame:
2619 case FrameLoadTypeReplace:
2620 history()->updateForReload();
2621 m_client->transitionToCommittedForNewPage();
2622 break;
2623
2624 case FrameLoadTypeStandard:
2625 history()->updateForStandardLoad();
2626 #ifndef BUILDING_ON_TIGER
2627 // This code was originally added for a Leopard performance imporvement. We decided to
2628 // ifdef it to fix correctness issues on Tiger documented in <rdar://problem/5441823>.
2629 if (m_frame->view())
2630 m_frame->view()->setScrollbarsSuppressed(true);
2631 #endif
2632 m_client->transitionToCommittedForNewPage();
2633 break;
2634
2635 case FrameLoadTypeRedirectWithLockedBackForwardList:
2636 history()->updateForRedirectWithLockedBackForwardList();
2637 m_client->transitionToCommittedForNewPage();
2638 break;
2639
2640 // FIXME Remove this check when dummy ds is removed (whatever "dummy ds" is).
2641 // An exception should be thrown if we're in the FrameLoadTypeUninitialized state.
2642 default:
2643 ASSERT_NOT_REACHED();
2644 }
2645
2646 m_responseMIMEType = dl->responseMIMEType();
2647
2648 // Tell the client we've committed this URL.
2649 ASSERT(m_frame->view());
2650
2651 if (m_creatingInitialEmptyDocument)
2652 return;
2653
2654 m_committedFirstRealDocumentLoad = true;
2655
2656 if (!m_client->hasHTMLView())
2657 receivedFirstData();
2658 else if (cachedPage) {
2659 // For non-cached HTML pages, these methods are called in receivedFirstData().
2660 dispatchDidCommitLoad();
2661
2662 // If we have a title let the WebView know about it.
2663 if (!ptitle.isNull())
2664 m_client->dispatchDidReceiveTitle(ptitle);
2665 }
2666 }
2667
clientRedirectCancelledOrFinished(bool cancelWithLoadInProgress)2668 void FrameLoader::clientRedirectCancelledOrFinished(bool cancelWithLoadInProgress)
2669 {
2670 // Note that -webView:didCancelClientRedirectForFrame: is called on the frame load delegate even if
2671 // the redirect succeeded. We should either rename this API, or add a new method, like
2672 // -webView:didFinishClientRedirectForFrame:
2673 m_client->dispatchDidCancelClientRedirect();
2674
2675 if (!cancelWithLoadInProgress)
2676 m_quickRedirectComing = false;
2677
2678 m_sentRedirectNotification = false;
2679 }
2680
clientRedirected(const KURL & url,double seconds,double fireDate,bool lockBackForwardList)2681 void FrameLoader::clientRedirected(const KURL& url, double seconds, double fireDate, bool lockBackForwardList)
2682 {
2683 m_client->dispatchWillPerformClientRedirect(url, seconds, fireDate);
2684
2685 // Remember that we sent a redirect notification to the frame load delegate so that when we commit
2686 // the next provisional load, we can send a corresponding -webView:didCancelClientRedirectForFrame:
2687 m_sentRedirectNotification = true;
2688
2689 // If a "quick" redirect comes in, we set a special mode so we treat the next
2690 // load as part of the original navigation. If we don't have a document loader, we have
2691 // no "original" load on which to base a redirect, so we treat the redirect as a normal load.
2692 // Loads triggered by JavaScript form submissions never count as quick redirects.
2693 m_quickRedirectComing = lockBackForwardList && m_documentLoader && !m_isExecutingJavaScriptFormAction;
2694 }
2695
shouldReload(const KURL & currentURL,const KURL & destinationURL)2696 bool FrameLoader::shouldReload(const KURL& currentURL, const KURL& destinationURL)
2697 {
2698 #if ENABLE(WML)
2699 // All WML decks are supposed to be reloaded, even within the same URL fragment
2700 if (frameContainsWMLContent(m_frame))
2701 return true;
2702 #endif
2703
2704 // This function implements the rule: "Don't reload if navigating by fragment within
2705 // the same URL, but do reload if going to a new URL or to the same URL with no
2706 // fragment identifier at all."
2707 if (!destinationURL.hasFragmentIdentifier())
2708 return true;
2709 return !equalIgnoringFragmentIdentifier(currentURL, destinationURL);
2710 }
2711
closeOldDataSources()2712 void FrameLoader::closeOldDataSources()
2713 {
2714 // FIXME: Is it important for this traversal to be postorder instead of preorder?
2715 // If so, add helpers for postorder traversal, and use them. If not, then lets not
2716 // use a recursive algorithm here.
2717 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
2718 child->loader()->closeOldDataSources();
2719
2720 if (m_documentLoader)
2721 m_client->dispatchWillClose();
2722
2723 m_client->setMainFrameDocumentReady(false); // stop giving out the actual DOMDocument to observers
2724 }
2725
open(CachedPage & cachedPage)2726 void FrameLoader::open(CachedPage& cachedPage)
2727 {
2728 ASSERT(!m_frame->tree()->parent());
2729 ASSERT(m_frame->page());
2730 ASSERT(m_frame->page()->mainFrame() == m_frame);
2731
2732 m_frame->redirectScheduler()->cancel();
2733
2734 // We still have to close the previous part page.
2735 closeURL();
2736
2737 // Delete old status bar messages (if it _was_ activated on last URL).
2738 if (m_frame->script()->canExecuteScripts()) {
2739 m_frame->setJSStatusBarText(String());
2740 m_frame->setJSDefaultStatusBarText(String());
2741 }
2742
2743 cachedPage.restore(m_frame->page());
2744
2745 checkCompleted();
2746 }
2747
open(CachedFrameBase & cachedFrame)2748 void FrameLoader::open(CachedFrameBase& cachedFrame)
2749 {
2750 m_isComplete = false;
2751
2752 // Don't re-emit the load event.
2753 m_didCallImplicitClose = true;
2754
2755 KURL url = cachedFrame.url();
2756
2757 if (url.protocolInHTTPFamily() && !url.host().isEmpty() && url.path().isEmpty())
2758 url.setPath("/");
2759
2760 m_URL = url;
2761 m_workingURL = url;
2762
2763 started();
2764 clear(true, true, cachedFrame.isMainFrame());
2765
2766 Document* document = cachedFrame.document();
2767 ASSERT(document);
2768 document->setInPageCache(false);
2769
2770 m_needsClear = true;
2771 m_isComplete = false;
2772 m_didCallImplicitClose = false;
2773 m_outgoingReferrer = url.string();
2774
2775 FrameView* view = cachedFrame.view();
2776
2777 // When navigating to a CachedFrame its FrameView should never be null. If it is we'll crash in creative ways downstream.
2778 ASSERT(view);
2779 view->setWasScrolledByUser(false);
2780
2781 // Use the current ScrollView's frame rect.
2782 if (m_frame->view())
2783 view->setFrameRect(m_frame->view()->frameRect());
2784 m_frame->setView(view);
2785
2786 m_frame->setDocument(document);
2787 m_frame->setDOMWindow(cachedFrame.domWindow());
2788 m_frame->domWindow()->setURL(document->url());
2789 m_frame->domWindow()->setSecurityOrigin(document->securityOrigin());
2790
2791 m_decoder = document->decoder();
2792
2793 updateFirstPartyForCookies();
2794
2795 cachedFrame.restore();
2796 }
2797
isStopping() const2798 bool FrameLoader::isStopping() const
2799 {
2800 return activeDocumentLoader()->isStopping();
2801 }
2802
finishedLoading()2803 void FrameLoader::finishedLoading()
2804 {
2805 // Retain because the stop may release the last reference to it.
2806 RefPtr<Frame> protect(m_frame);
2807
2808 RefPtr<DocumentLoader> dl = activeDocumentLoader();
2809 dl->finishedLoading();
2810 if (!dl->mainDocumentError().isNull() || !dl->frameLoader())
2811 return;
2812 dl->setPrimaryLoadComplete(true);
2813 m_client->dispatchDidLoadMainResource(dl.get());
2814 checkLoadComplete();
2815 }
2816
isHostedByObjectElement() const2817 bool FrameLoader::isHostedByObjectElement() const
2818 {
2819 HTMLFrameOwnerElement* owner = m_frame->ownerElement();
2820 return owner && owner->hasTagName(objectTag);
2821 }
2822
isLoadingMainFrame() const2823 bool FrameLoader::isLoadingMainFrame() const
2824 {
2825 Page* page = m_frame->page();
2826 return page && m_frame == page->mainFrame();
2827 }
2828
canShowMIMEType(const String & MIMEType) const2829 bool FrameLoader::canShowMIMEType(const String& MIMEType) const
2830 {
2831 return m_client->canShowMIMEType(MIMEType);
2832 }
2833
representationExistsForURLScheme(const String & URLScheme)2834 bool FrameLoader::representationExistsForURLScheme(const String& URLScheme)
2835 {
2836 return m_client->representationExistsForURLScheme(URLScheme);
2837 }
2838
generatedMIMETypeForURLScheme(const String & URLScheme)2839 String FrameLoader::generatedMIMETypeForURLScheme(const String& URLScheme)
2840 {
2841 return m_client->generatedMIMETypeForURLScheme(URLScheme);
2842 }
2843
didReceiveServerRedirectForProvisionalLoadForFrame()2844 void FrameLoader::didReceiveServerRedirectForProvisionalLoadForFrame()
2845 {
2846 m_client->dispatchDidReceiveServerRedirectForProvisionalLoad();
2847 }
2848
finishedLoadingDocument(DocumentLoader * loader)2849 void FrameLoader::finishedLoadingDocument(DocumentLoader* loader)
2850 {
2851 // FIXME: Platforms shouldn't differ here!
2852 #if PLATFORM(WIN) || PLATFORM(CHROMIUM) || defined(ANDROID)
2853 if (m_creatingInitialEmptyDocument)
2854 return;
2855 #endif
2856
2857 #if ENABLE(ARCHIVE) // ANDROID extension: disabled to reduce code size
2858 // If loading a webarchive, run through webarchive machinery
2859 const String& responseMIMEType = loader->responseMIMEType();
2860
2861 // FIXME: Mac's FrameLoaderClient::finishedLoading() method does work that is required even with Archive loads
2862 // so we still need to call it. Other platforms should only call finishLoading for non-archive loads
2863 // That work should be factored out so this #ifdef can be removed
2864 #if PLATFORM(MAC)
2865 m_client->finishedLoading(loader);
2866 if (!ArchiveFactory::isArchiveMimeType(responseMIMEType))
2867 return;
2868 #else
2869 if (!ArchiveFactory::isArchiveMimeType(responseMIMEType)) {
2870 m_client->finishedLoading(loader);
2871 return;
2872 }
2873 #endif
2874
2875 RefPtr<Archive> archive(ArchiveFactory::create(loader->mainResourceData().get(), responseMIMEType));
2876 if (!archive)
2877 return;
2878
2879 loader->addAllArchiveResources(archive.get());
2880
2881 ArchiveResource* mainResource = archive->mainResource();
2882 loader->setParsedArchiveData(mainResource->data());
2883
2884 m_responseMIMEType = mainResource->mimeType();
2885
2886 closeURL();
2887 didOpenURL(mainResource->url());
2888
2889 String userChosenEncoding = documentLoader()->overrideEncoding();
2890 bool encodingIsUserChosen = !userChosenEncoding.isNull();
2891 setEncoding(encodingIsUserChosen ? userChosenEncoding : mainResource->textEncoding(), encodingIsUserChosen);
2892
2893 ASSERT(m_frame->document());
2894
2895 addData(mainResource->data()->data(), mainResource->data()->size());
2896 #else
2897 m_client->finishedLoading(loader);
2898 #endif // ARCHIVE
2899 }
2900
isReplacing() const2901 bool FrameLoader::isReplacing() const
2902 {
2903 return m_loadType == FrameLoadTypeReplace;
2904 }
2905
setReplacing()2906 void FrameLoader::setReplacing()
2907 {
2908 m_loadType = FrameLoadTypeReplace;
2909 }
2910
revertToProvisional(DocumentLoader * loader)2911 void FrameLoader::revertToProvisional(DocumentLoader* loader)
2912 {
2913 m_client->revertToProvisionalState(loader);
2914 }
2915
subframeIsLoading() const2916 bool FrameLoader::subframeIsLoading() const
2917 {
2918 // It's most likely that the last added frame is the last to load so we walk backwards.
2919 for (Frame* child = m_frame->tree()->lastChild(); child; child = child->tree()->previousSibling()) {
2920 FrameLoader* childLoader = child->loader();
2921 DocumentLoader* documentLoader = childLoader->documentLoader();
2922 if (documentLoader && documentLoader->isLoadingInAPISense())
2923 return true;
2924 documentLoader = childLoader->provisionalDocumentLoader();
2925 if (documentLoader && documentLoader->isLoadingInAPISense())
2926 return true;
2927 }
2928 return false;
2929 }
2930
willChangeTitle(DocumentLoader * loader)2931 void FrameLoader::willChangeTitle(DocumentLoader* loader)
2932 {
2933 m_client->willChangeTitle(loader);
2934 }
2935
loadType() const2936 FrameLoadType FrameLoader::loadType() const
2937 {
2938 return m_loadType;
2939 }
2940
subresourceCachePolicy() const2941 CachePolicy FrameLoader::subresourceCachePolicy() const
2942 {
2943 if (m_isComplete)
2944 return CachePolicyVerify;
2945
2946 if (m_loadType == FrameLoadTypeReloadFromOrigin)
2947 return CachePolicyReload;
2948
2949 if (Frame* parentFrame = m_frame->tree()->parent()) {
2950 CachePolicy parentCachePolicy = parentFrame->loader()->subresourceCachePolicy();
2951 if (parentCachePolicy != CachePolicyVerify)
2952 return parentCachePolicy;
2953 }
2954
2955 // FIXME: POST documents are always Reloads, but their subresources should still be Revalidate.
2956 // If we bring the CachePolicy.h and ResourceRequest cache policy enums in sync with each other and
2957 // remember "Revalidate" in ResourceRequests, we can remove this "POST" check and return either "Reload"
2958 // or "Revalidate" if the DocumentLoader was requested with either.
2959 const ResourceRequest& request(documentLoader()->request());
2960 if (request.cachePolicy() == ReloadIgnoringCacheData && !equalIgnoringCase(request.httpMethod(), "post"))
2961 return CachePolicyRevalidate;
2962
2963 if (m_loadType == FrameLoadTypeReload)
2964 return CachePolicyRevalidate;
2965
2966 if (request.cachePolicy() == ReturnCacheDataElseLoad)
2967 return CachePolicyAllowStale;
2968
2969 return CachePolicyVerify;
2970 }
2971
checkLoadCompleteForThisFrame()2972 void FrameLoader::checkLoadCompleteForThisFrame()
2973 {
2974 ASSERT(m_client->hasWebView());
2975
2976 switch (m_state) {
2977 case FrameStateProvisional: {
2978 if (m_delegateIsHandlingProvisionalLoadError)
2979 return;
2980
2981 RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader;
2982 if (!pdl)
2983 return;
2984
2985 // If we've received any errors we may be stuck in the provisional state and actually complete.
2986 const ResourceError& error = pdl->mainDocumentError();
2987 if (error.isNull())
2988 return;
2989
2990 // Check all children first.
2991 RefPtr<HistoryItem> item;
2992 if (Page* page = m_frame->page())
2993 if (isBackForwardLoadType(loadType()) && m_frame == page->mainFrame())
2994 item = history()->currentItem();
2995
2996 bool shouldReset = true;
2997 if (!(pdl->isLoadingInAPISense() && !pdl->isStopping())) {
2998 m_delegateIsHandlingProvisionalLoadError = true;
2999 m_client->dispatchDidFailProvisionalLoad(error);
3000 m_delegateIsHandlingProvisionalLoadError = false;
3001
3002 // FIXME: can stopping loading here possibly have any effect, if isLoading is false,
3003 // which it must be to be in this branch of the if? And is it OK to just do a full-on
3004 // stopAllLoaders instead of stopLoadingSubframes?
3005 stopLoadingSubframes();
3006 pdl->stopLoading();
3007
3008 // If we're in the middle of loading multipart data, we need to restore the document loader.
3009 if (isReplacing() && !m_documentLoader.get())
3010 setDocumentLoader(m_provisionalDocumentLoader.get());
3011
3012 // Finish resetting the load state, but only if another load hasn't been started by the
3013 // delegate callback.
3014 if (pdl == m_provisionalDocumentLoader)
3015 clearProvisionalLoad();
3016 else if (activeDocumentLoader()) {
3017 KURL unreachableURL = activeDocumentLoader()->unreachableURL();
3018 if (!unreachableURL.isEmpty() && unreachableURL == pdl->request().url())
3019 shouldReset = false;
3020 }
3021 }
3022 if (shouldReset && item)
3023 if (Page* page = m_frame->page()) {
3024 page->backForwardList()->goToItem(item.get());
3025 Settings* settings = m_frame->settings();
3026 page->setGlobalHistoryItem((!settings || settings->privateBrowsingEnabled()) ? 0 : item.get());
3027 }
3028 return;
3029 }
3030
3031 case FrameStateCommittedPage: {
3032 DocumentLoader* dl = m_documentLoader.get();
3033 if (!dl || (dl->isLoadingInAPISense() && !dl->isStopping()))
3034 return;
3035
3036 markLoadComplete();
3037
3038 // FIXME: Is this subsequent work important if we already navigated away?
3039 // Maybe there are bugs because of that, or extra work we can skip because
3040 // the new page is ready.
3041
3042 m_client->forceLayoutForNonHTML();
3043
3044 // If the user had a scroll point, scroll to it, overriding the anchor point if any.
3045 if (Page* page = m_frame->page())
3046 if ((isBackForwardLoadType(m_loadType) || m_loadType == FrameLoadTypeReload || m_loadType == FrameLoadTypeReloadFromOrigin) && page->backForwardList())
3047 history()->restoreScrollPositionAndViewState();
3048
3049 if (m_creatingInitialEmptyDocument || !m_committedFirstRealDocumentLoad)
3050 return;
3051
3052 const ResourceError& error = dl->mainDocumentError();
3053 #ifndef NDEBUG
3054 m_didDispatchDidCommitLoad = false;
3055 #endif
3056 if (!error.isNull())
3057 m_client->dispatchDidFailLoad(error);
3058 else
3059 m_client->dispatchDidFinishLoad();
3060
3061 if (Page* page = m_frame->page())
3062 page->progress()->progressCompleted(m_frame);
3063
3064 #ifdef ANDROID_INSTRUMENT
3065 if (!m_frame->tree()->parent() && m_frame->document()->renderArena())
3066 android::TimeCounter::report(m_URL, cache()->getLiveSize(), cache()->getDeadSize(),
3067 m_frame->document()->renderArena()->reportPoolSize());
3068 #endif
3069 return;
3070 }
3071
3072 case FrameStateComplete:
3073 frameLoadCompleted();
3074 return;
3075 }
3076
3077 ASSERT_NOT_REACHED();
3078 }
3079
continueLoadAfterWillSubmitForm()3080 void FrameLoader::continueLoadAfterWillSubmitForm()
3081 {
3082 if (!m_provisionalDocumentLoader)
3083 return;
3084
3085 // DocumentLoader calls back to our prepareForLoadStart
3086 m_provisionalDocumentLoader->prepareForLoadStart();
3087
3088 // The load might be cancelled inside of prepareForLoadStart(), nulling out the m_provisionalDocumentLoader,
3089 // so we need to null check it again.
3090 if (!m_provisionalDocumentLoader)
3091 return;
3092
3093 DocumentLoader* activeDocLoader = activeDocumentLoader();
3094 if (activeDocLoader && activeDocLoader->isLoadingMainResource())
3095 return;
3096
3097 m_loadingFromCachedPage = false;
3098
3099 unsigned long identifier = 0;
3100
3101 if (Page* page = m_frame->page()) {
3102 identifier = page->progress()->createUniqueIdentifier();
3103 notifier()->assignIdentifierToInitialRequest(identifier, m_provisionalDocumentLoader.get(), m_provisionalDocumentLoader->originalRequest());
3104 }
3105
3106 if (!m_provisionalDocumentLoader->startLoadingMainResource(identifier))
3107 m_provisionalDocumentLoader->updateLoading();
3108 }
3109
didFirstLayout()3110 void FrameLoader::didFirstLayout()
3111 {
3112 if (Page* page = m_frame->page())
3113 if (isBackForwardLoadType(m_loadType) && page->backForwardList())
3114 history()->restoreScrollPositionAndViewState();
3115
3116 m_firstLayoutDone = true;
3117 m_client->dispatchDidFirstLayout();
3118 }
3119
didFirstVisuallyNonEmptyLayout()3120 void FrameLoader::didFirstVisuallyNonEmptyLayout()
3121 {
3122 m_client->dispatchDidFirstVisuallyNonEmptyLayout();
3123 }
3124
frameLoadCompleted()3125 void FrameLoader::frameLoadCompleted()
3126 {
3127 // Note: Can be called multiple times.
3128
3129 m_client->frameLoadCompleted();
3130
3131 history()->updateForFrameLoadCompleted();
3132
3133 // After a canceled provisional load, firstLayoutDone is false.
3134 // Reset it to true if we're displaying a page.
3135 if (m_documentLoader)
3136 m_firstLayoutDone = true;
3137 }
3138
firstLayoutDone() const3139 bool FrameLoader::firstLayoutDone() const
3140 {
3141 return m_firstLayoutDone;
3142 }
3143
detachChildren()3144 void FrameLoader::detachChildren()
3145 {
3146 // FIXME: Is it really necessary to do this in reverse order?
3147 Frame* previous;
3148 for (Frame* child = m_frame->tree()->lastChild(); child; child = previous) {
3149 previous = child->tree()->previousSibling();
3150 child->loader()->detachFromParent();
3151 }
3152 }
3153
closeAndRemoveChild(Frame * child)3154 void FrameLoader::closeAndRemoveChild(Frame* child)
3155 {
3156 child->tree()->detachFromParent();
3157
3158 child->setView(0);
3159 if (child->ownerElement() && child->page())
3160 child->page()->decrementFrameCount();
3161 child->pageDestroyed();
3162
3163 m_frame->tree()->removeChild(child);
3164 }
3165
recursiveCheckLoadComplete()3166 void FrameLoader::recursiveCheckLoadComplete()
3167 {
3168 Vector<RefPtr<Frame>, 10> frames;
3169
3170 for (RefPtr<Frame> frame = m_frame->tree()->firstChild(); frame; frame = frame->tree()->nextSibling())
3171 frames.append(frame);
3172
3173 unsigned size = frames.size();
3174 for (unsigned i = 0; i < size; i++)
3175 frames[i]->loader()->recursiveCheckLoadComplete();
3176
3177 checkLoadCompleteForThisFrame();
3178 }
3179
3180 // Called every time a resource is completely loaded, or an error is received.
checkLoadComplete()3181 void FrameLoader::checkLoadComplete()
3182 {
3183 ASSERT(m_client->hasWebView());
3184
3185 m_shouldCallCheckLoadComplete = false;
3186
3187 // FIXME: Always traversing the entire frame tree is a bit inefficient, but
3188 // is currently needed in order to null out the previous history item for all frames.
3189 if (Page* page = m_frame->page())
3190 page->mainFrame()->loader()->recursiveCheckLoadComplete();
3191 }
3192
numPendingOrLoadingRequests(bool recurse) const3193 int FrameLoader::numPendingOrLoadingRequests(bool recurse) const
3194 {
3195 if (!recurse)
3196 return numRequests(m_frame->document());
3197
3198 int count = 0;
3199 for (Frame* frame = m_frame; frame; frame = frame->tree()->traverseNext(m_frame))
3200 count += numRequests(frame->document());
3201 return count;
3202 }
3203
userAgent(const KURL & url) const3204 String FrameLoader::userAgent(const KURL& url) const
3205 {
3206 return m_client->userAgent(url);
3207 }
3208
tokenizerProcessedData()3209 void FrameLoader::tokenizerProcessedData()
3210 {
3211 checkCompleted();
3212 }
3213
handledOnloadEvents()3214 void FrameLoader::handledOnloadEvents()
3215 {
3216 m_client->dispatchDidHandleOnloadEvents();
3217 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
3218 if (documentLoader())
3219 documentLoader()->applicationCacheHost()->stopDeferringEvents();
3220 #endif
3221 }
3222
frameDetached()3223 void FrameLoader::frameDetached()
3224 {
3225 stopAllLoaders();
3226 m_frame->document()->stopActiveDOMObjects();
3227 detachFromParent();
3228 }
3229
detachFromParent()3230 void FrameLoader::detachFromParent()
3231 {
3232 RefPtr<Frame> protect(m_frame);
3233
3234 closeURL();
3235 stopAllLoaders();
3236 history()->saveScrollPositionAndViewStateToItem(history()->currentItem());
3237 detachChildren();
3238
3239 #if ENABLE(INSPECTOR)
3240 if (Page* page = m_frame->page())
3241 page->inspectorController()->frameDetachedFromParent(m_frame);
3242 #endif
3243
3244 detachViewsAndDocumentLoader();
3245
3246 if (Frame* parent = m_frame->tree()->parent()) {
3247 parent->loader()->closeAndRemoveChild(m_frame);
3248 parent->loader()->scheduleCheckCompleted();
3249 } else {
3250 m_frame->setView(0);
3251 m_frame->pageDestroyed();
3252 }
3253 }
3254
detachViewsAndDocumentLoader()3255 void FrameLoader::detachViewsAndDocumentLoader()
3256 {
3257 m_client->detachedFromParent2();
3258 setDocumentLoader(0);
3259 m_client->detachedFromParent3();
3260 }
3261
addExtraFieldsToSubresourceRequest(ResourceRequest & request)3262 void FrameLoader::addExtraFieldsToSubresourceRequest(ResourceRequest& request)
3263 {
3264 addExtraFieldsToRequest(request, m_loadType, false, false);
3265 }
3266
addExtraFieldsToMainResourceRequest(ResourceRequest & request)3267 void FrameLoader::addExtraFieldsToMainResourceRequest(ResourceRequest& request)
3268 {
3269 addExtraFieldsToRequest(request, m_loadType, true, false);
3270 }
3271
addExtraFieldsToRequest(ResourceRequest & request,FrameLoadType loadType,bool mainResource,bool cookiePolicyURLFromRequest)3272 void FrameLoader::addExtraFieldsToRequest(ResourceRequest& request, FrameLoadType loadType, bool mainResource, bool cookiePolicyURLFromRequest)
3273 {
3274 // Don't set the cookie policy URL if it's already been set.
3275 // But make sure to set it on all requests, as it has significance beyond the cookie policy for all protocols (<rdar://problem/6616664>).
3276 if (request.firstPartyForCookies().isEmpty()) {
3277 if (mainResource && (isLoadingMainFrame() || cookiePolicyURLFromRequest))
3278 request.setFirstPartyForCookies(request.url());
3279 else if (Document* document = m_frame->document())
3280 request.setFirstPartyForCookies(document->firstPartyForCookies());
3281 }
3282
3283 // The remaining modifications are only necessary for HTTP and HTTPS.
3284 if (!request.url().isEmpty() && !request.url().protocolInHTTPFamily())
3285 return;
3286
3287 applyUserAgent(request);
3288
3289 if (loadType == FrameLoadTypeReload) {
3290 request.setCachePolicy(ReloadIgnoringCacheData);
3291 request.setHTTPHeaderField("Cache-Control", "max-age=0");
3292 } else if (loadType == FrameLoadTypeReloadFromOrigin) {
3293 request.setCachePolicy(ReloadIgnoringCacheData);
3294 request.setHTTPHeaderField("Cache-Control", "no-cache");
3295 request.setHTTPHeaderField("Pragma", "no-cache");
3296 } else if (isBackForwardLoadType(loadType) && !request.url().protocolIs("https"))
3297 request.setCachePolicy(ReturnCacheDataElseLoad);
3298
3299 if (mainResource)
3300 request.setHTTPAccept(defaultAcceptHeader);
3301
3302 // Make sure we send the Origin header.
3303 addHTTPOriginIfNeeded(request, String());
3304
3305 // Always try UTF-8. If that fails, try frame encoding (if any) and then the default.
3306 // For a newly opened frame with an empty URL, encoding() should not be used, because this methods asks decoder, which uses ISO-8859-1.
3307 Settings* settings = m_frame->settings();
3308 request.setResponseContentDispositionEncodingFallbackArray("UTF-8", m_URL.isEmpty() ? m_encoding : encoding(), settings ? settings->defaultTextEncodingName() : String());
3309 }
3310
addHTTPOriginIfNeeded(ResourceRequest & request,String origin)3311 void FrameLoader::addHTTPOriginIfNeeded(ResourceRequest& request, String origin)
3312 {
3313 if (!request.httpOrigin().isEmpty())
3314 return; // Request already has an Origin header.
3315
3316 // Don't send an Origin header for GET or HEAD to avoid privacy issues.
3317 // For example, if an intranet page has a hyperlink to an external web
3318 // site, we don't want to include the Origin of the request because it
3319 // will leak the internal host name. Similar privacy concerns have lead
3320 // to the widespread suppression of the Referer header at the network
3321 // layer.
3322 if (request.httpMethod() == "GET" || request.httpMethod() == "HEAD")
3323 return;
3324
3325 // For non-GET and non-HEAD methods, always send an Origin header so the
3326 // server knows we support this feature.
3327
3328 if (origin.isEmpty()) {
3329 // If we don't know what origin header to attach, we attach the value
3330 // for an empty origin.
3331 origin = SecurityOrigin::createEmpty()->toString();
3332 }
3333
3334 request.setHTTPOrigin(origin);
3335 }
3336
committedLoad(DocumentLoader * loader,const char * data,int length)3337 void FrameLoader::committedLoad(DocumentLoader* loader, const char* data, int length)
3338 {
3339 #if ENABLE(ARCHIVE) // ANDROID extension: disabled to reduce code size
3340 if (ArchiveFactory::isArchiveMimeType(loader->response().mimeType()))
3341 return;
3342 #endif
3343 m_client->committedLoad(loader, data, length);
3344 }
3345
3346 #ifdef ANDROID_USER_GESTURE
loadPostRequest(const ResourceRequest & inRequest,const String & referrer,const String & frameName,bool lockHistory,FrameLoadType loadType,PassRefPtr<Event> event,PassRefPtr<FormState> prpFormState,bool userGesture)3347 void FrameLoader::loadPostRequest(const ResourceRequest& inRequest, const String& referrer, const String& frameName, bool lockHistory, FrameLoadType loadType, PassRefPtr<Event> event, PassRefPtr<FormState> prpFormState, bool userGesture)
3348 #else
3349 void FrameLoader::loadPostRequest(const ResourceRequest& inRequest, const String& referrer, const String& frameName, bool lockHistory, FrameLoadType loadType, PassRefPtr<Event> event, PassRefPtr<FormState> prpFormState)
3350 #endif
3351 {
3352 RefPtr<FormState> formState = prpFormState;
3353
3354 // When posting, use the NSURLRequestReloadIgnoringCacheData load flag.
3355 // This prevents a potential bug which may cause a page with a form that uses itself
3356 // as an action to be returned from the cache without submitting.
3357
3358 // FIXME: Where's the code that implements what the comment above says?
3359
3360 // Previously when this method was reached, the original FrameLoadRequest had been deconstructed to build a
3361 // bunch of parameters that would come in here and then be built back up to a ResourceRequest. In case
3362 // any caller depends on the immutability of the original ResourceRequest, I'm rebuilding a ResourceRequest
3363 // from scratch as it did all along.
3364 const KURL& url = inRequest.url();
3365 RefPtr<FormData> formData = inRequest.httpBody();
3366 const String& contentType = inRequest.httpContentType();
3367 String origin = inRequest.httpOrigin();
3368
3369 ResourceRequest workingResourceRequest(url);
3370 #ifdef ANDROID_USER_GESTURE
3371 workingResourceRequest.setUserGesture(userGesture);
3372 #endif
3373
3374 if (!referrer.isEmpty())
3375 workingResourceRequest.setHTTPReferrer(referrer);
3376 workingResourceRequest.setHTTPOrigin(origin);
3377 workingResourceRequest.setHTTPMethod("POST");
3378 workingResourceRequest.setHTTPBody(formData);
3379 workingResourceRequest.setHTTPContentType(contentType);
3380 addExtraFieldsToRequest(workingResourceRequest, loadType, true, true);
3381
3382 NavigationAction action(url, loadType, true, event);
3383
3384 if (!frameName.isEmpty()) {
3385 // The search for a target frame is done earlier in the case of form submission.
3386 if (Frame* targetFrame = formState ? 0 : findFrameForNavigation(frameName))
3387 targetFrame->loader()->loadWithNavigationAction(workingResourceRequest, action, lockHistory, loadType, formState.release());
3388 else
3389 policyChecker()->checkNewWindowPolicy(action, FrameLoader::callContinueLoadAfterNewWindowPolicy, workingResourceRequest, formState.release(), frameName, this);
3390 } else
3391 loadWithNavigationAction(workingResourceRequest, action, lockHistory, loadType, formState.release());
3392 }
3393
loadResourceSynchronously(const ResourceRequest & request,StoredCredentials storedCredentials,ResourceError & error,ResourceResponse & response,Vector<char> & data)3394 unsigned long FrameLoader::loadResourceSynchronously(const ResourceRequest& request, StoredCredentials storedCredentials, ResourceError& error, ResourceResponse& response, Vector<char>& data)
3395 {
3396 String referrer = m_outgoingReferrer;
3397 if (SecurityOrigin::shouldHideReferrer(request.url(), referrer))
3398 referrer = String();
3399
3400 ResourceRequest initialRequest = request;
3401 initialRequest.setTimeoutInterval(10);
3402
3403 // Use the original request's cache policy for two reasons:
3404 // 1. For POST requests, we mutate the cache policy for the main resource,
3405 // but we do not want this to apply to subresources
3406 // 2. Delegates that modify the cache policy using willSendRequest: should
3407 // not affect any other resources. Such changes need to be done
3408 // per request.
3409 if (initialRequest.isConditional())
3410 initialRequest.setCachePolicy(ReloadIgnoringCacheData);
3411 else
3412 initialRequest.setCachePolicy(originalRequest().cachePolicy());
3413
3414 if (!referrer.isEmpty())
3415 initialRequest.setHTTPReferrer(referrer);
3416 addHTTPOriginIfNeeded(initialRequest, outgoingOrigin());
3417
3418 if (Page* page = m_frame->page())
3419 initialRequest.setFirstPartyForCookies(page->mainFrame()->loader()->documentLoader()->request().url());
3420 initialRequest.setHTTPUserAgent(client()->userAgent(request.url()));
3421
3422 unsigned long identifier = 0;
3423 ResourceRequest newRequest(initialRequest);
3424 requestFromDelegate(newRequest, identifier, error);
3425
3426 if (error.isNull()) {
3427 ASSERT(!newRequest.isNull());
3428
3429 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
3430 if (!documentLoader()->applicationCacheHost()->maybeLoadSynchronously(newRequest, error, response, data)) {
3431 #endif
3432 ResourceHandle::loadResourceSynchronously(newRequest, storedCredentials, error, response, data, m_frame);
3433 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
3434 documentLoader()->applicationCacheHost()->maybeLoadFallbackSynchronously(newRequest, error, response, data);
3435 }
3436 #endif
3437 }
3438
3439 notifier()->sendRemainingDelegateMessages(m_documentLoader.get(), identifier, response, data.size(), error);
3440 return identifier;
3441 }
3442
originalRequest() const3443 const ResourceRequest& FrameLoader::originalRequest() const
3444 {
3445 return activeDocumentLoader()->originalRequestCopy();
3446 }
3447
receivedMainResourceError(const ResourceError & error,bool isComplete)3448 void FrameLoader::receivedMainResourceError(const ResourceError& error, bool isComplete)
3449 {
3450 // Retain because the stop may release the last reference to it.
3451 RefPtr<Frame> protect(m_frame);
3452
3453 RefPtr<DocumentLoader> loader = activeDocumentLoader();
3454
3455 if (isComplete) {
3456 // FIXME: Don't want to do this if an entirely new load is going, so should check
3457 // that both data sources on the frame are either this or nil.
3458 stop();
3459 if (m_client->shouldFallBack(error))
3460 handleFallbackContent();
3461 }
3462
3463 if (m_state == FrameStateProvisional && m_provisionalDocumentLoader) {
3464 if (m_submittedFormURL == m_provisionalDocumentLoader->originalRequestCopy().url())
3465 m_submittedFormURL = KURL();
3466
3467 // We might have made a page cache item, but now we're bailing out due to an error before we ever
3468 // transitioned to the new page (before WebFrameState == commit). The goal here is to restore any state
3469 // so that the existing view (that wenever got far enough to replace) can continue being used.
3470 history()->invalidateCurrentItemCachedPage();
3471
3472 // Call clientRedirectCancelledOrFinished here so that the frame load delegate is notified that the redirect's
3473 // status has changed, if there was a redirect. The frame load delegate may have saved some state about
3474 // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are definitely
3475 // not going to use this provisional resource, as it was cancelled, notify the frame load delegate that the redirect
3476 // has ended.
3477 if (m_sentRedirectNotification)
3478 clientRedirectCancelledOrFinished(false);
3479 }
3480
3481 loader->mainReceivedError(error, isComplete);
3482 }
3483
callContinueFragmentScrollAfterNavigationPolicy(void * argument,const ResourceRequest & request,PassRefPtr<FormState>,bool shouldContinue)3484 void FrameLoader::callContinueFragmentScrollAfterNavigationPolicy(void* argument,
3485 const ResourceRequest& request, PassRefPtr<FormState>, bool shouldContinue)
3486 {
3487 FrameLoader* loader = static_cast<FrameLoader*>(argument);
3488 loader->continueFragmentScrollAfterNavigationPolicy(request, shouldContinue);
3489 }
3490
continueFragmentScrollAfterNavigationPolicy(const ResourceRequest & request,bool shouldContinue)3491 void FrameLoader::continueFragmentScrollAfterNavigationPolicy(const ResourceRequest& request, bool shouldContinue)
3492 {
3493 m_quickRedirectComing = false;
3494
3495 if (!shouldContinue)
3496 return;
3497
3498 bool isRedirect = m_quickRedirectComing || policyChecker()->loadType() == FrameLoadTypeRedirectWithLockedBackForwardList;
3499 loadInSameDocument(request.url(), 0, !isRedirect);
3500 }
3501
shouldScrollToAnchor(bool isFormSubmission,FrameLoadType loadType,const KURL & url)3502 bool FrameLoader::shouldScrollToAnchor(bool isFormSubmission, FrameLoadType loadType, const KURL& url)
3503 {
3504 // Should we do anchor navigation within the existing content?
3505
3506 // We don't do this if we are submitting a form, explicitly reloading,
3507 // currently displaying a frameset, or if the URL does not have a fragment.
3508 // These rules were originally based on what KHTML was doing in KHTMLPart::openURL.
3509
3510 // FIXME: What about load types other than Standard and Reload?
3511
3512 return !isFormSubmission
3513 && loadType != FrameLoadTypeReload
3514 && loadType != FrameLoadTypeReloadFromOrigin
3515 && loadType != FrameLoadTypeSame
3516 && !shouldReload(this->url(), url)
3517 // We don't want to just scroll if a link from within a
3518 // frameset is trying to reload the frameset into _top.
3519 && !m_frame->document()->isFrameSet();
3520 }
3521
callContinueLoadAfterNavigationPolicy(void * argument,const ResourceRequest & request,PassRefPtr<FormState> formState,bool shouldContinue)3522 void FrameLoader::callContinueLoadAfterNavigationPolicy(void* argument,
3523 const ResourceRequest& request, PassRefPtr<FormState> formState, bool shouldContinue)
3524 {
3525 FrameLoader* loader = static_cast<FrameLoader*>(argument);
3526 loader->continueLoadAfterNavigationPolicy(request, formState, shouldContinue);
3527 }
3528
continueLoadAfterNavigationPolicy(const ResourceRequest &,PassRefPtr<FormState> formState,bool shouldContinue)3529 void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest&, PassRefPtr<FormState> formState, bool shouldContinue)
3530 {
3531 // If we loaded an alternate page to replace an unreachableURL, we'll get in here with a
3532 // nil policyDataSource because loading the alternate page will have passed
3533 // through this method already, nested; otherwise, policyDataSource should still be set.
3534 ASSERT(m_policyDocumentLoader || !m_provisionalDocumentLoader->unreachableURL().isEmpty());
3535
3536 bool isTargetItem = history()->provisionalItem() ? history()->provisionalItem()->isTargetItem() : false;
3537
3538 // Two reasons we can't continue:
3539 // 1) Navigation policy delegate said we can't so request is nil. A primary case of this
3540 // is the user responding Cancel to the form repost nag sheet.
3541 // 2) User responded Cancel to an alert popped up by the before unload event handler.
3542 // The "before unload" event handler runs only for the main frame.
3543 bool canContinue = shouldContinue && (!isLoadingMainFrame() || m_frame->shouldClose());
3544
3545 if (!canContinue) {
3546 // If we were waiting for a quick redirect, but the policy delegate decided to ignore it, then we
3547 // need to report that the client redirect was cancelled.
3548 if (m_quickRedirectComing)
3549 clientRedirectCancelledOrFinished(false);
3550
3551 setPolicyDocumentLoader(0);
3552
3553 // If the navigation request came from the back/forward menu, and we punt on it, we have the
3554 // problem that we have optimistically moved the b/f cursor already, so move it back. For sanity,
3555 // we only do this when punting a navigation for the target frame or top-level frame.
3556 if ((isTargetItem || isLoadingMainFrame()) && isBackForwardLoadType(policyChecker()->loadType()))
3557 if (Page* page = m_frame->page()) {
3558 Frame* mainFrame = page->mainFrame();
3559 if (HistoryItem* resetItem = mainFrame->loader()->history()->currentItem()) {
3560 page->backForwardList()->goToItem(resetItem);
3561 Settings* settings = m_frame->settings();
3562 page->setGlobalHistoryItem((!settings || settings->privateBrowsingEnabled()) ? 0 : resetItem);
3563 }
3564 }
3565 return;
3566 }
3567
3568 FrameLoadType type = policyChecker()->loadType();
3569 stopAllLoaders();
3570
3571 // <rdar://problem/6250856> - In certain circumstances on pages with multiple frames, stopAllLoaders()
3572 // might detach the current FrameLoader, in which case we should bail on this newly defunct load.
3573 if (!m_frame->page())
3574 return;
3575
3576 #if ENABLE(JAVASCRIPT_DEBUGGER) && ENABLE(INSPECTOR) && USE(JSC)
3577 if (Page* page = m_frame->page()) {
3578 if (page->mainFrame() == m_frame)
3579 page->inspectorController()->resumeDebugger();
3580 }
3581 #endif
3582
3583 setProvisionalDocumentLoader(m_policyDocumentLoader.get());
3584 m_loadType = type;
3585 setState(FrameStateProvisional);
3586
3587 setPolicyDocumentLoader(0);
3588
3589 if (isBackForwardLoadType(type) && loadProvisionalItemFromCachedPage())
3590 return;
3591
3592 if (formState)
3593 m_client->dispatchWillSubmitForm(&PolicyChecker::continueLoadAfterWillSubmitForm, formState);
3594 else
3595 continueLoadAfterWillSubmitForm();
3596 }
3597
callContinueLoadAfterNewWindowPolicy(void * argument,const ResourceRequest & request,PassRefPtr<FormState> formState,const String & frameName,bool shouldContinue)3598 void FrameLoader::callContinueLoadAfterNewWindowPolicy(void* argument,
3599 const ResourceRequest& request, PassRefPtr<FormState> formState, const String& frameName, bool shouldContinue)
3600 {
3601 FrameLoader* loader = static_cast<FrameLoader*>(argument);
3602 loader->continueLoadAfterNewWindowPolicy(request, formState, frameName, shouldContinue);
3603 }
3604
continueLoadAfterNewWindowPolicy(const ResourceRequest & request,PassRefPtr<FormState> formState,const String & frameName,bool shouldContinue)3605 void FrameLoader::continueLoadAfterNewWindowPolicy(const ResourceRequest& request,
3606 PassRefPtr<FormState> formState, const String& frameName, bool shouldContinue)
3607 {
3608 if (!shouldContinue)
3609 return;
3610
3611 RefPtr<Frame> frame = m_frame;
3612 RefPtr<Frame> mainFrame = m_client->dispatchCreatePage();
3613 if (!mainFrame)
3614 return;
3615
3616 if (frameName != "_blank")
3617 mainFrame->tree()->setName(frameName);
3618
3619 mainFrame->page()->setOpenedByDOM();
3620 mainFrame->loader()->m_client->dispatchShow();
3621 if (!m_suppressOpenerInNewFrame)
3622 mainFrame->loader()->setOpener(frame.get());
3623 mainFrame->loader()->loadWithNavigationAction(request, NavigationAction(), false, FrameLoadTypeStandard, formState);
3624 }
3625
requestFromDelegate(ResourceRequest & request,unsigned long & identifier,ResourceError & error)3626 void FrameLoader::requestFromDelegate(ResourceRequest& request, unsigned long& identifier, ResourceError& error)
3627 {
3628 ASSERT(!request.isNull());
3629
3630 identifier = 0;
3631 if (Page* page = m_frame->page()) {
3632 identifier = page->progress()->createUniqueIdentifier();
3633 notifier()->assignIdentifierToInitialRequest(identifier, m_documentLoader.get(), request);
3634 }
3635
3636 ResourceRequest newRequest(request);
3637 notifier()->dispatchWillSendRequest(m_documentLoader.get(), identifier, newRequest, ResourceResponse());
3638
3639 if (newRequest.isNull())
3640 error = cancelledError(request);
3641 else
3642 error = ResourceError();
3643
3644 request = newRequest;
3645 }
3646
loadedResourceFromMemoryCache(const CachedResource * resource)3647 void FrameLoader::loadedResourceFromMemoryCache(const CachedResource* resource)
3648 {
3649 Page* page = m_frame->page();
3650 if (!page)
3651 return;
3652
3653 #if ENABLE(INSPECTOR)
3654 page->inspectorController()->didLoadResourceFromMemoryCache(m_documentLoader.get(), resource);
3655 #endif
3656
3657 if (!resource->sendResourceLoadCallbacks() || m_documentLoader->haveToldClientAboutLoad(resource->url()))
3658 return;
3659
3660 if (!page->areMemoryCacheClientCallsEnabled()) {
3661 m_documentLoader->recordMemoryCacheLoadForFutureClientNotification(resource->url());
3662 m_documentLoader->didTellClientAboutLoad(resource->url());
3663 return;
3664 }
3665
3666 ResourceRequest request(resource->url());
3667 if (m_client->dispatchDidLoadResourceFromMemoryCache(m_documentLoader.get(), request, resource->response(), resource->encodedSize())) {
3668 m_documentLoader->didTellClientAboutLoad(resource->url());
3669 return;
3670 }
3671
3672 unsigned long identifier;
3673 ResourceError error;
3674 requestFromDelegate(request, identifier, error);
3675 notifier()->sendRemainingDelegateMessages(m_documentLoader.get(), identifier, resource->response(), resource->encodedSize(), error);
3676 }
3677
applyUserAgent(ResourceRequest & request)3678 void FrameLoader::applyUserAgent(ResourceRequest& request)
3679 {
3680 String userAgent = client()->userAgent(request.url());
3681 ASSERT(!userAgent.isNull());
3682 request.setHTTPUserAgent(userAgent);
3683 }
3684
shouldInterruptLoadForXFrameOptions(const String & content,const KURL & url)3685 bool FrameLoader::shouldInterruptLoadForXFrameOptions(const String& content, const KURL& url)
3686 {
3687 Frame* topFrame = m_frame->tree()->top();
3688 if (m_frame == topFrame)
3689 return false;
3690
3691 if (equalIgnoringCase(content, "deny"))
3692 return true;
3693
3694 if (equalIgnoringCase(content, "sameorigin")) {
3695 RefPtr<SecurityOrigin> origin = SecurityOrigin::create(url);
3696 if (!origin->isSameSchemeHostPort(topFrame->document()->securityOrigin()))
3697 return true;
3698 }
3699
3700 return false;
3701 }
3702
loadProvisionalItemFromCachedPage()3703 bool FrameLoader::loadProvisionalItemFromCachedPage()
3704 {
3705 RefPtr<CachedPage> cachedPage = pageCache()->get(history()->provisionalItem());
3706 if (!cachedPage || !cachedPage->document())
3707 return false;
3708
3709 DocumentLoader *provisionalLoader = provisionalDocumentLoader();
3710 LOG(PageCache, "WebCorePageCache: FrameLoader %p loading provisional DocumentLoader %p with URL '%s' from CachedPage %p", this, provisionalLoader, provisionalLoader->url().string().utf8().data(), cachedPage.get());
3711
3712 provisionalLoader->prepareForLoadStart();
3713
3714 m_loadingFromCachedPage = true;
3715
3716 provisionalLoader->setCommitted(true);
3717 commitProvisionalLoad(cachedPage);
3718
3719 return true;
3720 }
3721
cachePageForHistoryItem(HistoryItem * item)3722 void FrameLoader::cachePageForHistoryItem(HistoryItem* item)
3723 {
3724 if (!canCachePage() || item->isInPageCache())
3725 return;
3726
3727 pageHidden();
3728
3729 if (Page* page = m_frame->page()) {
3730 RefPtr<CachedPage> cachedPage = CachedPage::create(page);
3731 pageCache()->add(item, cachedPage.release());
3732 }
3733 }
3734
pageHidden()3735 void FrameLoader::pageHidden()
3736 {
3737 m_unloadEventBeingDispatched = true;
3738 if (m_frame->domWindow())
3739 m_frame->domWindow()->dispatchEvent(PageTransitionEvent::create(eventNames().pagehideEvent, true), m_frame->document());
3740 m_unloadEventBeingDispatched = false;
3741
3742 // Send pagehide event for subframes as well
3743 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
3744 child->loader()->pageHidden();
3745 }
3746
shouldTreatURLAsSameAsCurrent(const KURL & url) const3747 bool FrameLoader::shouldTreatURLAsSameAsCurrent(const KURL& url) const
3748 {
3749 if (!history()->currentItem())
3750 return false;
3751 return url == history()->currentItem()->url() || url == history()->currentItem()->originalURL();
3752 }
3753
checkDidPerformFirstNavigation()3754 void FrameLoader::checkDidPerformFirstNavigation()
3755 {
3756 Page* page = m_frame->page();
3757 if (!page)
3758 return;
3759
3760 if (!m_didPerformFirstNavigation && page->backForwardList()->entries().size() == 1) {
3761 m_didPerformFirstNavigation = true;
3762 m_client->didPerformFirstNavigation();
3763 }
3764 }
3765
findFrameForNavigation(const AtomicString & name)3766 Frame* FrameLoader::findFrameForNavigation(const AtomicString& name)
3767 {
3768 Frame* frame = m_frame->tree()->find(name);
3769 if (!shouldAllowNavigation(frame))
3770 return 0;
3771 return frame;
3772 }
3773
navigateWithinDocument(HistoryItem * item)3774 void FrameLoader::navigateWithinDocument(HistoryItem* item)
3775 {
3776 ASSERT(item->documentSequenceNumber() == history()->currentItem()->documentSequenceNumber());
3777
3778 // Save user view state to the current history item here since we don't do a normal load.
3779 // FIXME: Does form state need to be saved here too?
3780 history()->saveScrollPositionAndViewStateToItem(history()->currentItem());
3781 if (FrameView* view = m_frame->view())
3782 view->setWasScrolledByUser(false);
3783
3784 history()->setCurrentItem(item);
3785
3786 // loadInSameDocument() actually changes the URL and notifies load delegates of a "fake" load
3787 loadInSameDocument(item->url(), item->stateObject(), false);
3788
3789 // Restore user view state from the current history item here since we don't do a normal load.
3790 history()->restoreScrollPositionAndViewState();
3791 }
3792
3793 // FIXME: This function should really be split into a couple pieces, some of
3794 // which should be methods of HistoryController and some of which should be
3795 // methods of FrameLoader.
navigateToDifferentDocument(HistoryItem * item,FrameLoadType loadType)3796 void FrameLoader::navigateToDifferentDocument(HistoryItem* item, FrameLoadType loadType)
3797 {
3798 // Remember this item so we can traverse any child items as child frames load
3799 history()->setProvisionalItem(item);
3800
3801 // Check if we'll be using the page cache. We only use the page cache
3802 // if one exists and it is less than _backForwardCacheExpirationInterval
3803 // seconds old. If the cache is expired it gets flushed here.
3804 if (RefPtr<CachedPage> cachedPage = pageCache()->get(item)) {
3805 // FIXME: 1800 should not be hardcoded, it should come from
3806 // WebKitBackForwardCacheExpirationIntervalKey in WebKit.
3807 // Or we should remove WebKitBackForwardCacheExpirationIntervalKey.
3808 if (currentTime() - cachedPage->timeStamp() <= 1800) {
3809 loadWithDocumentLoader(cachedPage->documentLoader(), loadType, 0);
3810 return;
3811 }
3812
3813 LOG(PageCache, "Not restoring page for %s from back/forward cache because cache entry has expired", history()->provisionalItem()->url().string().ascii().data());
3814 pageCache()->remove(item);
3815 }
3816
3817 KURL itemURL = item->url();
3818 KURL itemOriginalURL = item->originalURL();
3819 KURL currentURL;
3820 if (documentLoader())
3821 currentURL = documentLoader()->url();
3822 RefPtr<FormData> formData = item->formData();
3823
3824 bool addedExtraFields = false;
3825 ResourceRequest request(itemURL);
3826
3827 if (!item->referrer().isNull())
3828 request.setHTTPReferrer(item->referrer());
3829
3830 // If this was a repost that failed the page cache, we might try to repost the form.
3831 NavigationAction action;
3832 if (formData) {
3833 formData->generateFiles(m_frame->page()->chrome()->client());
3834
3835 request.setHTTPMethod("POST");
3836 request.setHTTPBody(formData);
3837 request.setHTTPContentType(item->formContentType());
3838 RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::createFromString(item->referrer());
3839 addHTTPOriginIfNeeded(request, securityOrigin->toString());
3840
3841 // Make sure to add extra fields to the request after the Origin header is added for the FormData case.
3842 // See https://bugs.webkit.org/show_bug.cgi?id=22194 for more discussion.
3843 addExtraFieldsToRequest(request, m_loadType, true, formData);
3844 addedExtraFields = true;
3845
3846 // FIXME: Slight hack to test if the NSURL cache contains the page we're going to.
3847 // We want to know this before talking to the policy delegate, since it affects whether
3848 // we show the DoYouReallyWantToRepost nag.
3849 //
3850 // This trick has a small bug (3123893) where we might find a cache hit, but then
3851 // have the item vanish when we try to use it in the ensuing nav. This should be
3852 // extremely rare, but in that case the user will get an error on the navigation.
3853
3854 if (ResourceHandle::willLoadFromCache(request, m_frame))
3855 action = NavigationAction(itemURL, loadType, false);
3856 else {
3857 request.setCachePolicy(ReloadIgnoringCacheData);
3858 action = NavigationAction(itemURL, NavigationTypeFormResubmitted);
3859 }
3860 } else {
3861 switch (loadType) {
3862 case FrameLoadTypeReload:
3863 case FrameLoadTypeReloadFromOrigin:
3864 request.setCachePolicy(ReloadIgnoringCacheData);
3865 break;
3866 case FrameLoadTypeBack:
3867 case FrameLoadTypeBackWMLDeckNotAccessible:
3868 case FrameLoadTypeForward:
3869 case FrameLoadTypeIndexedBackForward:
3870 if (!itemURL.protocolIs("https"))
3871 request.setCachePolicy(ReturnCacheDataElseLoad);
3872 break;
3873 case FrameLoadTypeStandard:
3874 case FrameLoadTypeRedirectWithLockedBackForwardList:
3875 break;
3876 case FrameLoadTypeSame:
3877 default:
3878 ASSERT_NOT_REACHED();
3879 }
3880
3881 action = NavigationAction(itemOriginalURL, loadType, false);
3882 }
3883
3884 if (!addedExtraFields)
3885 addExtraFieldsToRequest(request, m_loadType, true, formData);
3886
3887 loadWithNavigationAction(request, action, false, loadType, 0);
3888 }
3889
3890 // Loads content into this frame, as specified by history item
loadItem(HistoryItem * item,FrameLoadType loadType)3891 void FrameLoader::loadItem(HistoryItem* item, FrameLoadType loadType)
3892 {
3893 // We do same-document navigation in the following cases:
3894 // - The HistoryItem has a history state object
3895 // - Navigating to an anchor within the page, with no form data stored on the target item or the current history entry,
3896 // and the URLs in the frame tree match the history item for fragment scrolling.
3897 HistoryItem* currentItem = history()->currentItem();
3898 bool sameDocumentNavigation = (!item->formData() && !(currentItem && currentItem->formData()) && history()->urlsMatchItem(item))
3899 || (currentItem && item->documentSequenceNumber() == currentItem->documentSequenceNumber());
3900
3901 #if ENABLE(WML)
3902 // All WML decks should go through the real load mechanism, not the scroll-to-anchor code
3903 // FIXME: Why do WML decks have this different behavior?
3904 // Are WML decks incompatible with HTML5 pushState/replaceState which require inter-document history navigations?
3905 // Should this new API be disabled for WML pages, or does WML need to update their mechanism to act like normal loads?
3906 // If scroll-to-anchor navigations were broken for WML and required them to have different loading behavior, then
3907 // state object loads are certainly also broken for them.
3908 if (frameContainsWMLContent(m_frame))
3909 sameDocumentNavigation = false;
3910 #endif
3911
3912 if (sameDocumentNavigation)
3913 navigateWithinDocument(item);
3914 else
3915 navigateToDifferentDocument(item, loadType);
3916 }
3917
setMainDocumentError(DocumentLoader * loader,const ResourceError & error)3918 void FrameLoader::setMainDocumentError(DocumentLoader* loader, const ResourceError& error)
3919 {
3920 m_client->setMainDocumentError(loader, error);
3921 }
3922
mainReceivedCompleteError(DocumentLoader * loader,const ResourceError &)3923 void FrameLoader::mainReceivedCompleteError(DocumentLoader* loader, const ResourceError&)
3924 {
3925 loader->setPrimaryLoadComplete(true);
3926 m_client->dispatchDidLoadMainResource(activeDocumentLoader());
3927 checkCompleted();
3928 if (m_frame->page())
3929 checkLoadComplete();
3930 }
3931
mainReceivedError(const ResourceError & error,bool isComplete)3932 void FrameLoader::mainReceivedError(const ResourceError& error, bool isComplete)
3933 {
3934 activeDocumentLoader()->mainReceivedError(error, isComplete);
3935 }
3936
cancelledError(const ResourceRequest & request) const3937 ResourceError FrameLoader::cancelledError(const ResourceRequest& request) const
3938 {
3939 ResourceError error = m_client->cancelledError(request);
3940 error.setIsCancellation(true);
3941 return error;
3942 }
3943
blockedError(const ResourceRequest & request) const3944 ResourceError FrameLoader::blockedError(const ResourceRequest& request) const
3945 {
3946 return m_client->blockedError(request);
3947 }
3948
cannotShowURLError(const ResourceRequest & request) const3949 ResourceError FrameLoader::cannotShowURLError(const ResourceRequest& request) const
3950 {
3951 return m_client->cannotShowURLError(request);
3952 }
3953
fileDoesNotExistError(const ResourceResponse & response) const3954 ResourceError FrameLoader::fileDoesNotExistError(const ResourceResponse& response) const
3955 {
3956 return m_client->fileDoesNotExistError(response);
3957 }
3958
shouldUseCredentialStorage(ResourceLoader * loader)3959 bool FrameLoader::shouldUseCredentialStorage(ResourceLoader* loader)
3960 {
3961 return m_client->shouldUseCredentialStorage(loader->documentLoader(), loader->identifier());
3962 }
3963
setTitle(const String & title)3964 void FrameLoader::setTitle(const String& title)
3965 {
3966 documentLoader()->setTitle(title);
3967 }
3968
originalRequestURL() const3969 KURL FrameLoader::originalRequestURL() const
3970 {
3971 return activeDocumentLoader()->originalRequest().url();
3972 }
3973
referrer() const3974 String FrameLoader::referrer() const
3975 {
3976 return documentLoader()->request().httpReferrer();
3977 }
3978
dispatchDocumentElementAvailable()3979 void FrameLoader::dispatchDocumentElementAvailable()
3980 {
3981 m_frame->injectUserScripts(InjectAtDocumentStart);
3982 m_client->documentElementAvailable();
3983 }
3984
dispatchDidClearWindowObjectsInAllWorlds()3985 void FrameLoader::dispatchDidClearWindowObjectsInAllWorlds()
3986 {
3987 if (!m_frame->script()->canExecuteScripts())
3988 return;
3989
3990 Vector<DOMWrapperWorld*> worlds;
3991 ScriptController::getAllWorlds(worlds);
3992 for (size_t i = 0; i < worlds.size(); ++i)
3993 dispatchDidClearWindowObjectInWorld(worlds[i]);
3994 }
3995
dispatchDidClearWindowObjectInWorld(DOMWrapperWorld * world)3996 void FrameLoader::dispatchDidClearWindowObjectInWorld(DOMWrapperWorld* world)
3997 {
3998 if (!m_frame->script()->canExecuteScripts() || !m_frame->script()->existingWindowShell(world))
3999 return;
4000
4001 m_client->dispatchDidClearWindowObjectInWorld(world);
4002
4003 #if ENABLE(INSPECTOR)
4004 if (world != mainThreadNormalWorld())
4005 return;
4006
4007 if (Page* page = m_frame->page()) {
4008 if (InspectorController* inspector = page->inspectorController())
4009 inspector->inspectedWindowScriptObjectCleared(m_frame);
4010 if (InspectorController* inspector = page->parentInspectorController())
4011 inspector->windowScriptObjectAvailable();
4012 }
4013 #endif
4014 }
4015
updateSandboxFlags()4016 void FrameLoader::updateSandboxFlags()
4017 {
4018 SandboxFlags flags = SandboxNone;
4019 if (Frame* parentFrame = m_frame->tree()->parent())
4020 flags |= parentFrame->loader()->sandboxFlags();
4021 if (HTMLFrameOwnerElement* ownerElement = m_frame->ownerElement())
4022 flags |= ownerElement->sandboxFlags();
4023
4024 if (m_sandboxFlags == flags)
4025 return;
4026
4027 m_sandboxFlags = flags;
4028
4029 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
4030 child->loader()->updateSandboxFlags();
4031 }
4032
isDocumentSandboxed(SandboxFlags mask) const4033 bool FrameLoader::isDocumentSandboxed(SandboxFlags mask) const
4034 {
4035 return m_frame->document() && m_frame->document()->securityOrigin()->isSandboxed(mask);
4036 }
4037
createJavaAppletWidget(const IntSize & size,HTMLAppletElement * element,const HashMap<String,String> & args)4038 PassRefPtr<Widget> FrameLoader::createJavaAppletWidget(const IntSize& size, HTMLAppletElement* element, const HashMap<String, String>& args)
4039 {
4040 String baseURLString;
4041 String codeBaseURLString;
4042 Vector<String> paramNames;
4043 Vector<String> paramValues;
4044 HashMap<String, String>::const_iterator end = args.end();
4045 for (HashMap<String, String>::const_iterator it = args.begin(); it != end; ++it) {
4046 if (equalIgnoringCase(it->first, "baseurl"))
4047 baseURLString = it->second;
4048 else if (equalIgnoringCase(it->first, "codebase"))
4049 codeBaseURLString = it->second;
4050 paramNames.append(it->first);
4051 paramValues.append(it->second);
4052 }
4053
4054 if (!codeBaseURLString.isEmpty()) {
4055 KURL codeBaseURL = completeURL(codeBaseURLString);
4056 if (!SecurityOrigin::canLoad(codeBaseURL, String(), element->document())) {
4057 FrameLoader::reportLocalLoadFailed(m_frame, codeBaseURL.string());
4058 return 0;
4059 }
4060 }
4061
4062 if (baseURLString.isEmpty())
4063 baseURLString = m_frame->document()->baseURL().string();
4064 KURL baseURL = completeURL(baseURLString);
4065
4066 RefPtr<Widget> widget = m_client->createJavaAppletWidget(size, element, baseURL, paramNames, paramValues);
4067 if (!widget)
4068 return 0;
4069
4070 m_containsPlugIns = true;
4071 return widget;
4072 }
4073
didChangeTitle(DocumentLoader * loader)4074 void FrameLoader::didChangeTitle(DocumentLoader* loader)
4075 {
4076 m_client->didChangeTitle(loader);
4077
4078 if (loader == m_documentLoader) {
4079 // Must update the entries in the back-forward list too.
4080 history()->setCurrentItemTitle(loader->title());
4081 // This must go through the WebFrame because it has the right notion of the current b/f item.
4082 m_client->setTitle(loader->title(), loader->urlForHistory());
4083 m_client->setMainFrameDocumentReady(true); // update observers with new DOMDocument
4084 m_client->dispatchDidReceiveTitle(loader->title());
4085 }
4086 }
4087
dispatchDidCommitLoad()4088 void FrameLoader::dispatchDidCommitLoad()
4089 {
4090 if (m_creatingInitialEmptyDocument)
4091 return;
4092
4093 #ifndef NDEBUG
4094 m_didDispatchDidCommitLoad = true;
4095 #endif
4096
4097 m_client->dispatchDidCommitLoad();
4098
4099 #if ENABLE(INSPECTOR)
4100 if (Page* page = m_frame->page())
4101 page->inspectorController()->didCommitLoad(m_documentLoader.get());
4102 #endif
4103 }
4104
tellClientAboutPastMemoryCacheLoads()4105 void FrameLoader::tellClientAboutPastMemoryCacheLoads()
4106 {
4107 ASSERT(m_frame->page());
4108 ASSERT(m_frame->page()->areMemoryCacheClientCallsEnabled());
4109
4110 if (!m_documentLoader)
4111 return;
4112
4113 Vector<String> pastLoads;
4114 m_documentLoader->takeMemoryCacheLoadsForClientNotification(pastLoads);
4115
4116 size_t size = pastLoads.size();
4117 for (size_t i = 0; i < size; ++i) {
4118 CachedResource* resource = cache()->resourceForURL(pastLoads[i]);
4119
4120 // FIXME: These loads, loaded from cache, but now gone from the cache by the time
4121 // Page::setMemoryCacheClientCallsEnabled(true) is called, will not be seen by the client.
4122 // Consider if there's some efficient way of remembering enough to deliver this client call.
4123 // We have the URL, but not the rest of the response or the length.
4124 if (!resource)
4125 continue;
4126
4127 ResourceRequest request(resource->url());
4128 m_client->dispatchDidLoadResourceFromMemoryCache(m_documentLoader.get(), request, resource->response(), resource->encodedSize());
4129 }
4130 }
4131
hasHTMLView() const4132 bool FrameLoaderClient::hasHTMLView() const
4133 {
4134 return true;
4135 }
4136
4137 } // namespace WebCore
4138