1 /* 2 * Copyright (C) 2000 Harri Porten (porten (at) kde.org) 3 * Copyright (C) 2006 Jon Shier (jshier (at) iastate.edu) 4 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2010 Apple Inc. All rights reseved. 5 * Copyright (C) 2006 Alexey Proskuryakov (ap (at) webkit.org) 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 20 * USA 21 */ 22 23 #include "config.h" 24 #include "JSLocationCustom.h" 25 26 #include "Location.h" 27 #include <runtime/JSFunction.h> 28 29 using namespace JSC; 30 31 namespace WebCore { 32 33 static JSValue nonCachingStaticReplaceFunctionGetter(ExecState* exec, JSValue, const Identifier& propertyName) 34 { 35 return new (exec) JSFunction(exec, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->functionStructure(), 1, propertyName, jsLocationPrototypeFunctionReplace); 36 } 37 38 static JSValue nonCachingStaticReloadFunctionGetter(ExecState* exec, JSValue, const Identifier& propertyName) 39 { 40 return new (exec) JSFunction(exec, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->functionStructure(), 0, propertyName, jsLocationPrototypeFunctionReload); 41 } 42 43 static JSValue nonCachingStaticAssignFunctionGetter(ExecState* exec, JSValue, const Identifier& propertyName) 44 { 45 return new (exec) JSFunction(exec, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->functionStructure(), 1, propertyName, jsLocationPrototypeFunctionAssign); 46 } 47 48 bool JSLocation::getOwnPropertySlotDelegate(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) 49 { 50 Frame* frame = impl()->frame(); 51 if (!frame) { 52 slot.setUndefined(); 53 return true; 54 } 55 56 // When accessing Location cross-domain, functions are always the native built-in ones. 57 // See JSDOMWindow::getOwnPropertySlotDelegate for additional details. 58 59 // Our custom code is only needed to implement the Window cross-domain scheme, so if access is 60 // allowed, return false so the normal lookup will take place. 61 String message; 62 if (allowsAccessFromFrame(exec, frame, message)) 63 return false; 64 65 // Check for the few functions that we allow, even when called cross-domain. 66 const HashEntry* entry = JSLocationPrototype::s_info.propHashTable(exec)->entry(exec, propertyName); 67 if (entry && (entry->attributes() & Function)) { 68 if (entry->function() == jsLocationPrototypeFunctionReplace) { 69 slot.setCustom(this, nonCachingStaticReplaceFunctionGetter); 70 return true; 71 } else if (entry->function() == jsLocationPrototypeFunctionReload) { 72 slot.setCustom(this, nonCachingStaticReloadFunctionGetter); 73 return true; 74 } else if (entry->function() == jsLocationPrototypeFunctionAssign) { 75 slot.setCustom(this, nonCachingStaticAssignFunctionGetter); 76 return true; 77 } 78 } 79 80 // FIXME: Other implementers of the Window cross-domain scheme (Window, History) allow toString, 81 // but for now we have decided not to, partly because it seems silly to return "[Object Location]" in 82 // such cases when normally the string form of Location would be the URL. 83 84 printErrorMessageForFrame(frame, message); 85 slot.setUndefined(); 86 return true; 87 } 88 89 bool JSLocation::getOwnPropertyDescriptorDelegate(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) 90 { 91 Frame* frame = impl()->frame(); 92 if (!frame) { 93 descriptor.setUndefined(); 94 return true; 95 } 96 97 // throw out all cross domain access 98 if (!allowsAccessFromFrame(exec, frame)) 99 return true; 100 101 // Check for the few functions that we allow, even when called cross-domain. 102 const HashEntry* entry = JSLocationPrototype::s_info.propHashTable(exec)->entry(exec, propertyName); 103 PropertySlot slot; 104 if (entry && (entry->attributes() & Function)) { 105 if (entry->function() == jsLocationPrototypeFunctionReplace) { 106 slot.setCustom(this, nonCachingStaticReplaceFunctionGetter); 107 descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes()); 108 return true; 109 } else if (entry->function() == jsLocationPrototypeFunctionReload) { 110 slot.setCustom(this, nonCachingStaticReloadFunctionGetter); 111 descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes()); 112 return true; 113 } else if (entry->function() == jsLocationPrototypeFunctionAssign) { 114 slot.setCustom(this, nonCachingStaticAssignFunctionGetter); 115 descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes()); 116 return true; 117 } 118 } 119 120 // FIXME: Other implementers of the Window cross-domain scheme (Window, History) allow toString, 121 // but for now we have decided not to, partly because it seems silly to return "[Object Location]" in 122 // such cases when normally the string form of Location would be the URL. 123 124 descriptor.setUndefined(); 125 return true; 126 } 127 128 bool JSLocation::putDelegate(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) 129 { 130 Frame* frame = impl()->frame(); 131 if (!frame) 132 return true; 133 134 if (propertyName == exec->propertyNames().toString || propertyName == exec->propertyNames().valueOf) 135 return true; 136 137 bool sameDomainAccess = allowsAccessFromFrame(exec, frame); 138 139 const HashEntry* entry = JSLocation::s_info.propHashTable(exec)->entry(exec, propertyName); 140 if (!entry) { 141 if (sameDomainAccess) 142 JSObject::put(exec, propertyName, value, slot); 143 return true; 144 } 145 146 // Cross-domain access to the location is allowed when assigning the whole location, 147 // but not when assigning the individual pieces, since that might inadvertently 148 // disclose other parts of the original location. 149 if (entry->propertyPutter() != setJSLocationHref && !sameDomainAccess) 150 return true; 151 152 return false; 153 } 154 155 bool JSLocation::deleteProperty(ExecState* exec, const Identifier& propertyName) 156 { 157 // Only allow deleting by frames in the same origin. 158 if (!allowsAccessFromFrame(exec, impl()->frame())) 159 return false; 160 return Base::deleteProperty(exec, propertyName); 161 } 162 163 void JSLocation::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) 164 { 165 // Only allow the location object to enumerated by frames in the same origin. 166 if (!allowsAccessFromFrame(exec, impl()->frame())) 167 return; 168 Base::getOwnPropertyNames(exec, propertyNames, mode); 169 } 170 171 void JSLocation::defineGetter(ExecState* exec, const Identifier& propertyName, JSObject* getterFunction, unsigned attributes) 172 { 173 if (propertyName == exec->propertyNames().toString || propertyName == exec->propertyNames().valueOf) 174 return; 175 Base::defineGetter(exec, propertyName, getterFunction, attributes); 176 } 177 178 void JSLocation::setHref(ExecState* exec, JSValue value) 179 { 180 UString href = value.toString(exec); 181 if (exec->hadException()) 182 return; 183 impl()->setHref(ustringToString(href), activeDOMWindow(exec), firstDOMWindow(exec)); 184 } 185 186 void JSLocation::setProtocol(ExecState* exec, JSValue value) 187 { 188 UString protocol = value.toString(exec); 189 if (exec->hadException()) 190 return; 191 ExceptionCode ec = 0; 192 impl()->setProtocol(ustringToString(protocol), activeDOMWindow(exec), firstDOMWindow(exec), ec); 193 setDOMException(exec, ec); 194 } 195 196 void JSLocation::setHost(ExecState* exec, JSValue value) 197 { 198 UString host = value.toString(exec); 199 if (exec->hadException()) 200 return; 201 impl()->setHost(ustringToString(host), activeDOMWindow(exec), firstDOMWindow(exec)); 202 } 203 204 void JSLocation::setHostname(ExecState* exec, JSValue value) 205 { 206 UString hostname = value.toString(exec); 207 if (exec->hadException()) 208 return; 209 impl()->setHostname(ustringToString(hostname), activeDOMWindow(exec), firstDOMWindow(exec)); 210 } 211 212 void JSLocation::setPort(ExecState* exec, JSValue value) 213 { 214 UString port = value.toString(exec); 215 if (exec->hadException()) 216 return; 217 impl()->setPort(ustringToString(port), activeDOMWindow(exec), firstDOMWindow(exec)); 218 } 219 220 void JSLocation::setPathname(ExecState* exec, JSValue value) 221 { 222 UString pathname = value.toString(exec); 223 if (exec->hadException()) 224 return; 225 impl()->setPathname(ustringToString(pathname), activeDOMWindow(exec), firstDOMWindow(exec)); 226 } 227 228 void JSLocation::setSearch(ExecState* exec, JSValue value) 229 { 230 UString pathname = value.toString(exec); 231 if (exec->hadException()) 232 return; 233 impl()->setSearch(ustringToString(pathname), activeDOMWindow(exec), firstDOMWindow(exec)); 234 } 235 236 void JSLocation::setHash(ExecState* exec, JSValue value) 237 { 238 UString hash = value.toString(exec); 239 if (exec->hadException()) 240 return; 241 impl()->setHash(ustringToString(hash), activeDOMWindow(exec), firstDOMWindow(exec)); 242 } 243 244 JSValue JSLocation::replace(ExecState* exec) 245 { 246 UString urlString = exec->argument(0).toString(exec); 247 if (exec->hadException()) 248 return jsUndefined(); 249 impl()->replace(ustringToString(urlString), activeDOMWindow(exec), firstDOMWindow(exec)); 250 return jsUndefined(); 251 } 252 253 JSValue JSLocation::reload(ExecState* exec) 254 { 255 impl()->reload(activeDOMWindow(exec)); 256 return jsUndefined(); 257 } 258 259 JSValue JSLocation::assign(ExecState* exec) 260 { 261 UString urlString = exec->argument(0).toString(exec); 262 if (exec->hadException()) 263 return jsUndefined(); 264 impl()->assign(ustringToString(urlString), activeDOMWindow(exec), firstDOMWindow(exec)); 265 return jsUndefined(); 266 } 267 268 JSValue JSLocation::toStringFunction(ExecState* exec) 269 { 270 Frame* frame = impl()->frame(); 271 if (!frame || !allowsAccessFromFrame(exec, frame)) 272 return jsUndefined(); 273 274 return jsString(exec, impl()->toString()); 275 } 276 277 bool JSLocationPrototype::putDelegate(ExecState* exec, const Identifier& propertyName, JSValue, PutPropertySlot&) 278 { 279 return (propertyName == exec->propertyNames().toString || propertyName == exec->propertyNames().valueOf); 280 } 281 282 void JSLocationPrototype::defineGetter(ExecState* exec, const Identifier& propertyName, JSObject* getterFunction, unsigned attributes) 283 { 284 if (propertyName == exec->propertyNames().toString || propertyName == exec->propertyNames().valueOf) 285 return; 286 Base::defineGetter(exec, propertyName, getterFunction, attributes); 287 } 288 289 } // namespace WebCore 290