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 50 namespace 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 62 void 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 85 void 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 105 void 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 122 void 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 142 void 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 159 void 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 176 void 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 193 void 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 210 v8::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 228 v8::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 246 v8::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 265 v8::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 282 v8::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 303 v8::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 324 v8::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 334 v8::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 345 bool 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 353 bool 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 361 v8::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