1/* 2 * Copyright (C) 2009 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31#include "config.h" 32#include "V8Location.h" 33 34#include "CSSHelper.h" 35#include "Document.h" 36#include "Frame.h" 37#include "FrameLoader.h" 38#include "KURL.h" 39#include "Location.h" 40#include "PlatformString.h" 41#include "ScriptController.h" 42#include "V8Binding.h" 43#include "V8BindingState.h" 44#include "V8CustomEventListener.h" 45#include "V8DOMWindow.h" 46#include "V8Location.h" 47#include "V8Utilities.h" 48#include "V8Proxy.h" 49 50namespace WebCore { 51 52// Notes about V8/JSC porting of this file. 53// This class is not very JS-engine specific. If we can move a couple of 54// methods to the scriptController, we should be able to unify the code 55// between JSC and V8: 56// toCallingFrame() - in JSC, this needs an ExecState. 57// isSafeScript() 58// Since JSC and V8 have different mechanisms for getting at the calling frame, 59// we're just making all these custom for now. The functionality is simple 60// and mirrors JSLocationCustom.cpp. 61 62void V8Location::hashAccessorSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info) 63{ 64 INC_STATS("DOM.Location.hash._set"); 65 v8::Handle<v8::Object> holder = info.Holder(); 66 Location* imp = V8Location::toNative(holder); 67 String hash = toWebCoreString(value); 68 69 Frame* frame = imp->frame(); 70 if (!frame) 71 return; 72 73 KURL url = frame->loader()->url(); 74 String oldRef = url.fragmentIdentifier(); 75 76 if (hash.startsWith("#")) 77 hash = hash.substring(1); 78 if (oldRef == hash || (oldRef.isNull() && hash.isEmpty())) 79 return; 80 url.setFragmentIdentifier(hash); 81 82 navigateIfAllowed(frame, url, false, false); 83} 84 85void V8Location::hostAccessorSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info) 86{ 87 INC_STATS("DOM.Location.host._set"); 88 v8::Handle<v8::Object> holder = info.Holder(); 89 Location* imp = V8Location::toNative(holder); 90 String host = toWebCoreString(value); 91 92 Frame* frame = imp->frame(); 93 if (!frame) 94 return; 95 96 KURL url = frame->loader()->url(); 97 String newHost = host.left(host.find(":")); 98 String newPort = host.substring(host.find(":") + 1); 99 url.setHost(newHost); 100 url.setPort(newPort.toUInt()); 101 102 navigateIfAllowed(frame, url, false, false); 103} 104 105void V8Location::hostnameAccessorSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info) 106{ 107 INC_STATS("DOM.Location.hostname._set"); 108 v8::Handle<v8::Object> holder = info.Holder(); 109 Location* imp = V8Location::toNative(holder); 110 String hostname = toWebCoreString(value); 111 112 Frame* frame = imp->frame(); 113 if (!frame) 114 return; 115 116 KURL url = frame->loader()->url(); 117 url.setHost(hostname); 118 119 navigateIfAllowed(frame, url, false, false); 120} 121 122void V8Location::hrefAccessorSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info) 123{ 124 INC_STATS("DOM.Location.href._set"); 125 v8::Handle<v8::Object> holder = info.Holder(); 126 Location* imp = V8Location::toNative(holder); 127 128 Frame* frame = imp->frame(); 129 if (!frame) 130 return; 131 132 KURL url = completeURL(toWebCoreString(value)); 133 if (url.isNull()) 134 return; 135 136 if (!shouldAllowNavigation(frame)) 137 return; 138 139 navigateIfAllowed(frame, url, false, false); 140} 141 142void V8Location::pathnameAccessorSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info) 143{ 144 INC_STATS("DOM.Location.pathname._set"); 145 v8::Handle<v8::Object> holder = info.Holder(); 146 Location* imp = V8Location::toNative(holder); 147 String pathname = toWebCoreString(value); 148 149 Frame* frame = imp->frame(); 150 if (!frame) 151 return; 152 153 KURL url = frame->loader()->url(); 154 url.setPath(pathname); 155 156 navigateIfAllowed(frame, url, false, false); 157} 158 159void V8Location::portAccessorSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info) 160{ 161 INC_STATS("DOM.Location.port._set"); 162 v8::Handle<v8::Object> holder = info.Holder(); 163 Location* imp = V8Location::toNative(holder); 164 String port = toWebCoreString(value); 165 166 Frame* frame = imp->frame(); 167 if (!frame) 168 return; 169 170 KURL url = frame->loader()->url(); 171 url.setPort(port.toUInt()); 172 173 navigateIfAllowed(frame, url, false, false); 174} 175 176void V8Location::protocolAccessorSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info) 177{ 178 INC_STATS("DOM.Location.protocol._set"); 179 v8::Handle<v8::Object> holder = info.Holder(); 180 Location* imp = V8Location::toNative(holder); 181 String protocol = toWebCoreString(value); 182 183 Frame* frame = imp->frame(); 184 if (!frame) 185 return; 186 187 KURL url = frame->loader()->url(); 188 url.setProtocol(protocol); 189 190 navigateIfAllowed(frame, url, false, false); 191} 192 193void V8Location::searchAccessorSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info) 194{ 195 INC_STATS("DOM.Location.search._set"); 196 v8::Handle<v8::Object> holder = info.Holder(); 197 Location* imp = V8Location::toNative(holder); 198 String query = toWebCoreString(value); 199 200 Frame* frame = imp->frame(); 201 if (!frame) 202 return; 203 204 KURL url = frame->loader()->url(); 205 url.setQuery(query); 206 207 navigateIfAllowed(frame, url, false, false); 208} 209 210v8::Handle<v8::Value> V8Location::reloadAccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info) 211{ 212 INC_STATS("DOM.Location.reload._get"); 213 static v8::Persistent<v8::FunctionTemplate> privateTemplate = v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New(V8Location::reloadCallback, v8::Handle<v8::Value>(), v8::Signature::New(V8Location::GetRawTemplate()))); 214 v8::Handle<v8::Object> holder = V8DOMWrapper::lookupDOMWrapper(V8Location::GetTemplate(), info.This()); 215 if (holder.IsEmpty()) { 216 // can only reach here by 'object.__proto__.func', and it should passed 217 // domain security check already 218 return privateTemplate->GetFunction(); 219 } 220 Location* imp = V8Location::toNative(holder); 221 if (!V8BindingSecurity::canAccessFrame(V8BindingState::Only(), imp->frame(), false)) { 222 static v8::Persistent<v8::FunctionTemplate> sharedTemplate = v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New(V8Location::reloadCallback, v8::Handle<v8::Value>(), v8::Signature::New(V8Location::GetRawTemplate()))); 223 return sharedTemplate->GetFunction(); 224 } 225 return privateTemplate->GetFunction(); 226} 227 228v8::Handle<v8::Value> V8Location::replaceAccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info) 229{ 230 INC_STATS("DOM.Location.replace._get"); 231 static v8::Persistent<v8::FunctionTemplate> privateTemplate = v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New(V8Location::replaceCallback, v8::Handle<v8::Value>(), v8::Signature::New(V8Location::GetRawTemplate()))); 232 v8::Handle<v8::Object> holder = V8DOMWrapper::lookupDOMWrapper(V8Location::GetTemplate(), info.This()); 233 if (holder.IsEmpty()) { 234 // can only reach here by 'object.__proto__.func', and it should passed 235 // domain security check already 236 return privateTemplate->GetFunction(); 237 } 238 Location* imp = V8Location::toNative(holder); 239 if (!V8BindingSecurity::canAccessFrame(V8BindingState::Only(), imp->frame(), false)) { 240 static v8::Persistent<v8::FunctionTemplate> sharedTemplate = v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New(V8Location::replaceCallback, v8::Handle<v8::Value>(), v8::Signature::New(V8Location::GetRawTemplate()))); 241 return sharedTemplate->GetFunction(); 242 } 243 return privateTemplate->GetFunction(); 244} 245 246v8::Handle<v8::Value> V8Location::assignAccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info) 247{ 248 INC_STATS("DOM.Location.assign._get"); 249 static v8::Persistent<v8::FunctionTemplate> privateTemplate = 250 v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New(V8Location::assignCallback, v8::Handle<v8::Value>(), v8::Signature::New(V8Location::GetRawTemplate()))); 251 v8::Handle<v8::Object> holder = V8DOMWrapper::lookupDOMWrapper(V8Location::GetTemplate(), info.This()); 252 if (holder.IsEmpty()) { 253 // can only reach here by 'object.__proto__.func', and it should passed 254 // domain security check already 255 return privateTemplate->GetFunction(); 256 } 257 Location* imp = V8Location::toNative(holder); 258 if (!V8BindingSecurity::canAccessFrame(V8BindingState::Only(), imp->frame(), false)) { 259 static v8::Persistent<v8::FunctionTemplate> sharedTemplate = v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New(V8Location::assignCallback, v8::Handle<v8::Value>(), v8::Signature::New(V8Location::GetRawTemplate()))); 260 return sharedTemplate->GetFunction(); 261 } 262 return privateTemplate->GetFunction(); 263} 264 265v8::Handle<v8::Value> V8Location::reloadCallback(const v8::Arguments& args) 266{ 267 // FIXME: we ignore the "forceget" parameter. 268 269 INC_STATS("DOM.Location.reload"); 270 v8::Handle<v8::Object> holder = args.Holder(); 271 Location* imp = V8Location::toNative(holder); 272 273 Frame* frame = imp->frame(); 274 if (!frame || !ScriptController::isSafeScript(frame)) 275 return v8::Undefined(); 276 277 if (!protocolIsJavaScript(frame->loader()->url())) 278 frame->redirectScheduler()->scheduleRefresh(processingUserGesture()); 279 return v8::Undefined(); 280} 281 282v8::Handle<v8::Value> V8Location::replaceCallback(const v8::Arguments& args) 283{ 284 INC_STATS("DOM.Location.replace"); 285 v8::Handle<v8::Object> holder = args.Holder(); 286 Location* imp = V8Location::toNative(holder); 287 288 Frame* frame = imp->frame(); 289 if (!frame) 290 return v8::Undefined(); 291 292 KURL url = completeURL(toWebCoreString(args[0])); 293 if (url.isNull()) 294 return v8::Undefined(); 295 296 if (!shouldAllowNavigation(frame)) 297 return v8::Undefined(); 298 299 navigateIfAllowed(frame, url, true, true); 300 return v8::Undefined(); 301} 302 303v8::Handle<v8::Value> V8Location::assignCallback(const v8::Arguments& args) 304{ 305 INC_STATS("DOM.Location.assign"); 306 v8::Handle<v8::Object> holder = args.Holder(); 307 Location* imp = V8Location::toNative(holder); 308 309 Frame* frame = imp->frame(); 310 if (!frame) 311 return v8::Undefined(); 312 313 KURL url = completeURL(toWebCoreString(args[0])); 314 if (url.isNull()) 315 return v8::Undefined(); 316 317 if (!shouldAllowNavigation(frame)) 318 return v8::Undefined(); 319 320 navigateIfAllowed(frame, url, false, false); 321 return v8::Undefined(); 322} 323 324v8::Handle<v8::Value> V8Location::valueOfCallback(const v8::Arguments& args) 325{ 326 // Just return the this object the way the normal valueOf function 327 // on the Object prototype would. The valueOf function is only 328 // added to make sure that it cannot be overwritten on location 329 // objects, since that would provide a hook to change the string 330 // conversion behavior of location objects. 331 return args.This(); 332} 333 334v8::Handle<v8::Value> V8Location::toStringCallback(const v8::Arguments& args) 335{ 336 INC_STATS("DOM.Location.toString"); 337 v8::Handle<v8::Object> holder = args.Holder(); 338 Location* imp = V8Location::toNative(holder); 339 if (!V8BindingSecurity::canAccessFrame(V8BindingState::Only(), imp->frame(), true)) 340 return v8::Undefined(); 341 String result = imp->href(); 342 return v8String(result); 343} 344 345bool V8Location::indexedSecurityCheck(v8::Local<v8::Object> host, uint32_t index, v8::AccessType type, v8::Local<v8::Value> data) 346{ 347 ASSERT(V8ClassIndex::FromInt(data->Int32Value()) == V8ClassIndex::LOCATION); 348 // Only allow same origin access 349 Location* imp = V8Location::toNative(host); 350 return V8BindingSecurity::canAccessFrame(V8BindingState::Only(), imp->frame(), false); 351} 352 353bool V8Location::namedSecurityCheck(v8::Local<v8::Object> host, v8::Local<v8::Value> key, v8::AccessType type, v8::Local<v8::Value> data) 354{ 355 ASSERT(V8ClassIndex::FromInt(data->Int32Value()) == V8ClassIndex::LOCATION); 356 // Only allow same origin access 357 Location* imp = V8Location::toNative(host); 358 return V8BindingSecurity::canAccessFrame(V8BindingState::Only(), imp->frame(), false); 359} 360 361v8::Handle<v8::Value> toV8(Location* impl) 362{ 363 if (!impl) 364 return v8::Null(); 365 v8::Handle<v8::Object> wrapper = getDOMObjectMap().get(impl); 366 if (wrapper.IsEmpty()) { 367 wrapper = V8Location::wrap(impl); 368 if (!wrapper.IsEmpty()) 369 V8DOMWrapper::setHiddenWindowReference(impl->frame(), V8DOMWindow::locationIndex, wrapper); 370 } 371 return wrapper; 372} 373 374} // namespace WebCore 375 376