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/loader/FrameLoadRequest.h" 32 #include "core/loader/NavigationAction.h" 33 #include "core/page/Chrome.h" 34 #include "core/page/ChromeClient.h" 35 #include "core/page/Frame.h" 36 #include "core/page/Page.h" 37 #include "core/page/Settings.h" 38 #include "core/page/WindowFeatures.h" 39 #include "core/platform/network/ResourceRequest.h" 40 #include "weborigin/KURL.h" 41 #include "weborigin/SecurityOrigin.h" 42 #include "weborigin/SecurityPolicy.h" 43 44 namespace WebCore { 45 46 static Frame* createWindow(Frame* openerFrame, Frame* lookupFrame, const FrameLoadRequest& request, const WindowFeatures& features, bool& created) 47 { 48 ASSERT(!features.dialog || request.frameName().isEmpty()); 49 50 if (!request.frameName().isEmpty() && request.frameName() != "_blank") { 51 if (Frame* frame = lookupFrame->loader()->findFrameForNavigation(request.frameName(), openerFrame->document())) { 52 if (request.frameName() != "_self") { 53 if (Page* page = frame->page()) 54 page->chrome().focus(); 55 } 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(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 // FIXME: Setting the referrer should be the caller's responsibility. 69 FrameLoadRequest requestWithReferrer = request; 70 String referrer = SecurityPolicy::generateReferrerHeader(openerFrame->document()->referrerPolicy(), request.resourceRequest().url(), openerFrame->loader()->outgoingReferrer()); 71 if (!referrer.isEmpty()) 72 requestWithReferrer.resourceRequest().setHTTPReferrer(referrer); 73 FrameLoader::addHTTPOriginIfNeeded(requestWithReferrer.resourceRequest(), openerFrame->loader()->outgoingOrigin()); 74 75 if (openerFrame->settings() && !openerFrame->settings()->supportsMultipleWindows()) { 76 created = false; 77 return openerFrame->tree()->top(); 78 } 79 80 Page* oldPage = openerFrame->page(); 81 if (!oldPage) 82 return 0; 83 84 NavigationAction action(requestWithReferrer.resourceRequest()); 85 Page* page = oldPage->chrome().client()->createWindow(openerFrame, requestWithReferrer, features, action); 86 if (!page) 87 return 0; 88 89 Frame* frame = page->mainFrame(); 90 91 frame->loader()->forceSandboxFlags(openerFrame->document()->sandboxFlags()); 92 93 if (request.frameName() != "_blank") 94 frame->tree()->setName(request.frameName()); 95 96 page->chrome().setWindowFeatures(features); 97 98 // 'x' and 'y' specify the location of the window, while 'width' and 'height' 99 // specify the size of the viewport. We can only resize the window, so adjust 100 // for the difference between the window size and the viewport size. 101 102 FloatRect windowRect = page->chrome().windowRect(); 103 FloatSize viewportSize = page->chrome().pageRect().size(); 104 105 if (features.xSet) 106 windowRect.setX(features.x); 107 if (features.ySet) 108 windowRect.setY(features.y); 109 if (features.widthSet) 110 windowRect.setWidth(features.width + (windowRect.width() - viewportSize.width())); 111 if (features.heightSet) 112 windowRect.setHeight(features.height + (windowRect.height() - viewportSize.height())); 113 114 // Ensure non-NaN values, minimum size as well as being within valid screen area. 115 FloatRect newWindowRect = DOMWindow::adjustWindowRect(page, windowRect); 116 117 page->chrome().setWindowRect(newWindowRect); 118 page->chrome().show(); 119 120 created = true; 121 return frame; 122 } 123 124 Frame* createWindow(const String& urlString, const AtomicString& frameName, const WindowFeatures& windowFeatures, 125 DOMWindow* activeWindow, Frame* firstFrame, Frame* openerFrame, DOMWindow::PrepareDialogFunction function, void* functionContext) 126 { 127 Frame* activeFrame = activeWindow->frame(); 128 129 KURL completedURL = urlString.isEmpty() ? KURL(ParsedURLString, emptyString()) : firstFrame->document()->completeURL(urlString); 130 if (!completedURL.isEmpty() && !completedURL.isValid()) { 131 // Don't expose client code to invalid URLs. 132 activeWindow->printErrorMessage("Unable to open a window with invalid URL '" + completedURL.string() + "'.\n"); 133 return 0; 134 } 135 136 // For whatever reason, Firefox uses the first frame to determine the outgoingReferrer. We replicate that behavior here. 137 String referrer = SecurityPolicy::generateReferrerHeader(firstFrame->document()->referrerPolicy(), completedURL, firstFrame->loader()->outgoingReferrer()); 138 139 ResourceRequest request(completedURL, referrer); 140 FrameLoader::addHTTPOriginIfNeeded(request, firstFrame->loader()->outgoingOrigin()); 141 FrameLoadRequest frameRequest(activeWindow->document()->securityOrigin(), request, frameName); 142 143 // We pass the opener frame for the lookupFrame in case the active frame is different from 144 // the opener frame, and the name references a frame relative to the opener frame. 145 bool created; 146 Frame* newFrame = createWindow(activeFrame, openerFrame, frameRequest, windowFeatures, created); 147 if (!newFrame) 148 return 0; 149 150 newFrame->loader()->setOpener(openerFrame); 151 newFrame->page()->setOpenedByDOM(); 152 153 if (newFrame->domWindow()->isInsecureScriptAccess(activeWindow, completedURL)) 154 return newFrame; 155 156 if (function) 157 function(newFrame->domWindow(), functionContext); 158 159 if (created) { 160 FrameLoadRequest request(activeWindow->document()->securityOrigin(), ResourceRequest(completedURL, referrer)); 161 newFrame->loader()->load(request); 162 } else if (!urlString.isEmpty()) { 163 newFrame->navigationScheduler()->scheduleLocationChange(activeWindow->document()->securityOrigin(), completedURL.string(), referrer, false); 164 } 165 return newFrame; 166 } 167 168 } // namespace WebCore 169