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/inspector/ConsoleMessage.h" 35 #include "core/loader/FrameLoadRequest.h" 36 #include "core/page/Chrome.h" 37 #include "core/page/ChromeClient.h" 38 #include "core/page/FocusController.h" 39 #include "core/page/Page.h" 40 #include "core/page/WindowFeatures.h" 41 #include "platform/network/ResourceRequest.h" 42 #include "platform/weborigin/KURL.h" 43 #include "platform/weborigin/SecurityOrigin.h" 44 #include "platform/weborigin/SecurityPolicy.h" 45 46 namespace blink { 47 48 static LocalFrame* createWindow(LocalFrame& openerFrame, LocalFrame& lookupFrame, const FrameLoadRequest& request, const WindowFeatures& features, NavigationPolicy policy, ShouldSendReferrer shouldSendReferrer, bool& created) 49 { 50 ASSERT(!features.dialog || request.frameName().isEmpty()); 51 52 if (!request.frameName().isEmpty() && request.frameName() != "_blank" && policy == NavigationPolicyIgnore) { 53 if (LocalFrame* frame = lookupFrame.loader().findFrameForNavigation(request.frameName(), openerFrame.document())) { 54 if (request.frameName() != "_self") 55 frame->page()->focusController().setFocusedFrame(frame); 56 created = false; 57 return frame; 58 } 59 } 60 61 // Sandboxed frames cannot open new auxiliary browsing contexts. 62 if (openerFrame.document()->isSandboxed(SandboxPopups)) { 63 // FIXME: This message should be moved off the console once a solution to https://bugs.webkit.org/show_bug.cgi?id=103274 exists. 64 openerFrame.document()->addConsoleMessage(ConsoleMessage::create(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.")); 65 return 0; 66 } 67 68 if (openerFrame.settings() && !openerFrame.settings()->supportsMultipleWindows()) { 69 created = false; 70 if (!openerFrame.tree().top()->isLocalFrame()) 71 return 0; 72 return toLocalFrame(openerFrame.tree().top()); 73 } 74 75 Page* oldPage = openerFrame.page(); 76 if (!oldPage) 77 return 0; 78 79 Page* page = oldPage->chrome().client().createWindow(&openerFrame, request, features, policy, shouldSendReferrer); 80 if (!page || !page->mainFrame()->isLocalFrame()) 81 return 0; 82 FrameHost* host = &page->frameHost(); 83 84 ASSERT(page->mainFrame()); 85 LocalFrame& frame = *page->deprecatedLocalMainFrame(); 86 87 if (request.frameName() != "_blank") 88 frame.tree().setName(request.frameName()); 89 90 host->chrome().setWindowFeatures(features); 91 92 // 'x' and 'y' specify the location of the window, while 'width' and 'height' 93 // specify the size of the viewport. We can only resize the window, so adjust 94 // for the difference between the window size and the viewport size. 95 96 FloatRect windowRect = host->chrome().windowRect(); 97 FloatSize viewportSize = host->chrome().pageRect().size(); 98 99 if (features.xSet) 100 windowRect.setX(features.x); 101 if (features.ySet) 102 windowRect.setY(features.y); 103 if (features.widthSet) 104 windowRect.setWidth(features.width + (windowRect.width() - viewportSize.width())); 105 if (features.heightSet) 106 windowRect.setHeight(features.height + (windowRect.height() - viewportSize.height())); 107 108 // Ensure non-NaN values, minimum size as well as being within valid screen area. 109 FloatRect newWindowRect = LocalDOMWindow::adjustWindowRect(frame, windowRect); 110 111 host->chrome().setWindowRect(newWindowRect); 112 host->chrome().show(policy); 113 114 created = true; 115 return &frame; 116 } 117 118 LocalFrame* createWindow(const String& urlString, const AtomicString& frameName, const WindowFeatures& windowFeatures, 119 LocalDOMWindow& callingWindow, LocalFrame& firstFrame, LocalFrame& openerFrame, LocalDOMWindow::PrepareDialogFunction function, void* functionContext) 120 { 121 LocalFrame* activeFrame = callingWindow.frame(); 122 ASSERT(activeFrame); 123 124 KURL completedURL = urlString.isEmpty() ? KURL(ParsedURLString, emptyString()) : firstFrame.document()->completeURL(urlString); 125 if (!completedURL.isEmpty() && !completedURL.isValid()) { 126 // Don't expose client code to invalid URLs. 127 callingWindow.printErrorMessage("Unable to open a window with invalid URL '" + completedURL.string() + "'.\n"); 128 return 0; 129 } 130 131 // For whatever reason, Firefox uses the first frame to determine the outgoingReferrer. We replicate that behavior here. 132 Referrer referrer(SecurityPolicy::generateReferrerHeader(firstFrame.document()->referrerPolicy(), completedURL, firstFrame.document()->outgoingReferrer()), firstFrame.document()->referrerPolicy()); 133 134 ResourceRequest request(completedURL, referrer); 135 request.addHTTPOriginIfNeeded(AtomicString(firstFrame.document()->outgoingOrigin())); 136 FrameLoadRequest frameRequest(callingWindow.document(), request, frameName); 137 138 // We pass the opener frame for the lookupFrame in case the active frame is different from 139 // the opener frame, and the name references a frame relative to the opener frame. 140 bool created; 141 LocalFrame* newFrame = createWindow(*activeFrame, openerFrame, frameRequest, windowFeatures, NavigationPolicyIgnore, MaybeSendReferrer, created); 142 if (!newFrame) 143 return 0; 144 145 if (newFrame != &openerFrame && newFrame != openerFrame.tree().top()) 146 newFrame->loader().forceSandboxFlags(openerFrame.document()->sandboxFlags()); 147 148 newFrame->loader().setOpener(&openerFrame); 149 150 if (newFrame->domWindow()->isInsecureScriptAccess(callingWindow, completedURL)) 151 return newFrame; 152 153 if (function) 154 function(newFrame->domWindow(), functionContext); 155 156 if (created) { 157 FrameLoadRequest request(callingWindow.document(), ResourceRequest(completedURL, referrer)); 158 newFrame->loader().load(request); 159 } else if (!urlString.isEmpty()) { 160 newFrame->navigationScheduler().scheduleLocationChange(callingWindow.document(), completedURL.string(), referrer, false); 161 } 162 return newFrame; 163 } 164 165 void createWindowForRequest(const FrameLoadRequest& request, LocalFrame& openerFrame, NavigationPolicy policy, ShouldSendReferrer shouldSendReferrer) 166 { 167 if (openerFrame.document()->pageDismissalEventBeingDispatched() != Document::NoDismissal) 168 return; 169 170 if (openerFrame.document() && openerFrame.document()->isSandboxed(SandboxPopups)) 171 return; 172 173 if (!LocalDOMWindow::allowPopUp(openerFrame)) 174 return; 175 176 if (policy == NavigationPolicyCurrentTab) 177 policy = NavigationPolicyNewForegroundTab; 178 179 WindowFeatures features; 180 bool created; 181 LocalFrame* newFrame = createWindow(openerFrame, openerFrame, request, features, policy, shouldSendReferrer, created); 182 if (!newFrame) 183 return; 184 if (shouldSendReferrer == MaybeSendReferrer) { 185 newFrame->loader().setOpener(&openerFrame); 186 newFrame->document()->setReferrerPolicy(openerFrame.document()->referrerPolicy()); 187 } 188 FrameLoadRequest newRequest(0, request.resourceRequest()); 189 newRequest.setFormState(request.formState()); 190 newFrame->loader().load(newRequest); 191 } 192 193 } // namespace blink 194