1 /* 2 * Copyright (C) 2006, 2007, 2008, 2010 Apple Inc. All rights reserved. 3 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include "config.h" 28 #include "core/page/CreateWindow.h" 29 30 #include "core/dom/Document.h" 31 #include "core/frame/FrameHost.h" 32 #include "core/frame/LocalFrame.h" 33 #include "core/frame/Settings.h" 34 #include "core/loader/FrameLoadRequest.h" 35 #include "core/page/Chrome.h" 36 #include "core/page/ChromeClient.h" 37 #include "core/page/FocusController.h" 38 #include "core/page/Page.h" 39 #include "core/page/WindowFeatures.h" 40 #include "platform/network/ResourceRequest.h" 41 #include "platform/weborigin/KURL.h" 42 #include "platform/weborigin/SecurityOrigin.h" 43 #include "platform/weborigin/SecurityPolicy.h" 44 45 namespace WebCore { 46 47 static LocalFrame* createWindow(LocalFrame& openerFrame, LocalFrame& lookupFrame, const FrameLoadRequest& request, const WindowFeatures& features, NavigationPolicy policy, ShouldSendReferrer shouldSendReferrer, bool& created) 48 { 49 ASSERT(!features.dialog || request.frameName().isEmpty()); 50 51 if (!request.frameName().isEmpty() && request.frameName() != "_blank" && policy == NavigationPolicyIgnore) { 52 if (LocalFrame* frame = lookupFrame.loader().findFrameForNavigation(request.frameName(), openerFrame.document())) { 53 if (request.frameName() != "_self") 54 frame->page()->focusController().setFocusedFrame(frame); 55 created = false; 56 return frame; 57 } 58 } 59 60 // Sandboxed frames cannot open new auxiliary browsing contexts. 61 if (openerFrame.document()->isSandboxed(SandboxPopups)) { 62 // FIXME: This message should be moved off the console once a solution to https://bugs.webkit.org/show_bug.cgi?id=103274 exists. 63 openerFrame.document()->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, "Blocked opening '" + request.resourceRequest().url().elidedString() + "' in a new window because the request was made in a sandboxed frame whose 'allow-popups' permission is not set."); 64 return 0; 65 } 66 67 if (openerFrame.settings() && !openerFrame.settings()->supportsMultipleWindows()) { 68 created = false; 69 if (!openerFrame.tree().top()->isLocalFrame()) 70 return 0; 71 return toLocalFrame(openerFrame.tree().top()); 72 } 73 74 Page* oldPage = openerFrame.page(); 75 if (!oldPage) 76 return 0; 77 78 Page* page = oldPage->chrome().client().createWindow(&openerFrame, request, features, policy, shouldSendReferrer); 79 if (!page || !page->mainFrame()->isLocalFrame()) 80 return 0; 81 FrameHost* host = &page->frameHost(); 82 83 ASSERT(page->mainFrame()); 84 LocalFrame& frame = *page->deprecatedLocalMainFrame(); 85 86 if (request.frameName() != "_blank") 87 frame.tree().setName(request.frameName()); 88 89 host->chrome().setWindowFeatures(features); 90 91 // 'x' and 'y' specify the location of the window, while 'width' and 'height' 92 // specify the size of the viewport. We can only resize the window, so adjust 93 // for the difference between the window size and the viewport size. 94 95 FloatRect windowRect = host->chrome().windowRect(); 96 FloatSize viewportSize = host->chrome().pageRect().size(); 97 98 if (features.xSet) 99 windowRect.setX(features.x); 100 if (features.ySet) 101 windowRect.setY(features.y); 102 if (features.widthSet) 103 windowRect.setWidth(features.width + (windowRect.width() - viewportSize.width())); 104 if (features.heightSet) 105 windowRect.setHeight(features.height + (windowRect.height() - viewportSize.height())); 106 107 // Ensure non-NaN values, minimum size as well as being within valid screen area. 108 FloatRect newWindowRect = LocalDOMWindow::adjustWindowRect(frame, windowRect); 109 110 host->chrome().setWindowRect(newWindowRect); 111 host->chrome().show(policy); 112 113 created = true; 114 return &frame; 115 } 116 117 LocalFrame* createWindow(const String& urlString, const AtomicString& frameName, const WindowFeatures& windowFeatures, 118 LocalDOMWindow& callingWindow, LocalFrame& firstFrame, LocalFrame& openerFrame, LocalDOMWindow::PrepareDialogFunction function, void* functionContext) 119 { 120 LocalFrame* activeFrame = callingWindow.frame(); 121 ASSERT(activeFrame); 122 123 KURL completedURL = urlString.isEmpty() ? KURL(ParsedURLString, emptyString()) : firstFrame.document()->completeURL(urlString); 124 if (!completedURL.isEmpty() && !completedURL.isValid()) { 125 // Don't expose client code to invalid URLs. 126 callingWindow.printErrorMessage("Unable to open a window with invalid URL '" + completedURL.string() + "'.\n"); 127 return 0; 128 } 129 130 // For whatever reason, Firefox uses the first frame to determine the outgoingReferrer. We replicate that behavior here. 131 Referrer referrer(SecurityPolicy::generateReferrerHeader(firstFrame.document()->referrerPolicy(), completedURL, firstFrame.document()->outgoingReferrer()), firstFrame.document()->referrerPolicy()); 132 133 ResourceRequest request(completedURL, referrer); 134 FrameLoader::addHTTPOriginIfNeeded(request, AtomicString(firstFrame.document()->outgoingOrigin())); 135 FrameLoadRequest frameRequest(callingWindow.document(), request, frameName); 136 137 // We pass the opener frame for the lookupFrame in case the active frame is different from 138 // the opener frame, and the name references a frame relative to the opener frame. 139 bool created; 140 LocalFrame* newFrame = createWindow(*activeFrame, openerFrame, frameRequest, windowFeatures, NavigationPolicyIgnore, MaybeSendReferrer, created); 141 if (!newFrame) 142 return 0; 143 144 if (newFrame != &openerFrame && newFrame != openerFrame.tree().top()) 145 newFrame->loader().forceSandboxFlags(openerFrame.document()->sandboxFlags()); 146 147 newFrame->loader().setOpener(&openerFrame); 148 149 if (newFrame->domWindow()->isInsecureScriptAccess(callingWindow, completedURL)) 150 return newFrame; 151 152 if (function) 153 function(newFrame->domWindow(), functionContext); 154 155 if (created) { 156 FrameLoadRequest request(callingWindow.document(), ResourceRequest(completedURL, referrer)); 157 newFrame->loader().load(request); 158 } else if (!urlString.isEmpty()) { 159 newFrame->navigationScheduler().scheduleLocationChange(callingWindow.document(), completedURL.string(), referrer, false); 160 } 161 return newFrame; 162 } 163 164 void createWindowForRequest(const FrameLoadRequest& request, LocalFrame& openerFrame, NavigationPolicy policy, ShouldSendReferrer shouldSendReferrer) 165 { 166 if (openerFrame.document()->pageDismissalEventBeingDispatched() != Document::NoDismissal) 167 return; 168 169 if (openerFrame.document() && openerFrame.document()->isSandboxed(SandboxPopups)) 170 return; 171 172 if (!LocalDOMWindow::allowPopUp(openerFrame)) 173 return; 174 175 if (policy == NavigationPolicyCurrentTab) 176 policy = NavigationPolicyNewForegroundTab; 177 178 WindowFeatures features; 179 bool created; 180 LocalFrame* newFrame = createWindow(openerFrame, openerFrame, request, features, policy, shouldSendReferrer, created); 181 if (!newFrame) 182 return; 183 if (shouldSendReferrer == MaybeSendReferrer) { 184 newFrame->loader().setOpener(&openerFrame); 185 newFrame->document()->setReferrerPolicy(openerFrame.document()->referrerPolicy()); 186 } 187 FrameLoadRequest newRequest(0, request.resourceRequest()); 188 newRequest.setFormState(request.formState()); 189 newFrame->loader().load(newRequest); 190 } 191 192 } // namespace WebCore 193