1 /*
2 * Copyright (C) 2000 Harri Porten (porten@kde.org)
3 * Copyright (C) 2006 Jon Shier (jshier@iastate.edu)
4 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2010 Apple Inc. All rights reseved.
5 * Copyright (C) 2006 Alexey Proskuryakov (ap@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
nonCachingStaticReplaceFunctionGetter(ExecState * exec,JSValue,const Identifier & propertyName)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
nonCachingStaticReloadFunctionGetter(ExecState * exec,JSValue,const Identifier & propertyName)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
nonCachingStaticAssignFunctionGetter(ExecState * exec,JSValue,const Identifier & propertyName)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
getOwnPropertySlotDelegate(ExecState * exec,const Identifier & propertyName,PropertySlot & slot)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
getOwnPropertyDescriptorDelegate(ExecState * exec,const Identifier & propertyName,PropertyDescriptor & descriptor)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
putDelegate(ExecState * exec,const Identifier & propertyName,JSValue value,PutPropertySlot & slot)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
deleteProperty(ExecState * exec,const Identifier & propertyName)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
getOwnPropertyNames(ExecState * exec,PropertyNameArray & propertyNames,EnumerationMode mode)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
defineGetter(ExecState * exec,const Identifier & propertyName,JSObject * getterFunction,unsigned attributes)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
setHref(ExecState * exec,JSValue value)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
setProtocol(ExecState * exec,JSValue value)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
setHost(ExecState * exec,JSValue value)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
setHostname(ExecState * exec,JSValue value)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
setPort(ExecState * exec,JSValue value)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
setPathname(ExecState * exec,JSValue value)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
setSearch(ExecState * exec,JSValue value)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
setHash(ExecState * exec,JSValue value)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
replace(ExecState * exec)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
reload(ExecState * exec)253 JSValue JSLocation::reload(ExecState* exec)
254 {
255 impl()->reload(activeDOMWindow(exec));
256 return jsUndefined();
257 }
258
assign(ExecState * exec)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
toStringFunction(ExecState * exec)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
putDelegate(ExecState * exec,const Identifier & propertyName,JSValue,PutPropertySlot &)277 bool JSLocationPrototype::putDelegate(ExecState* exec, const Identifier& propertyName, JSValue, PutPropertySlot&)
278 {
279 return (propertyName == exec->propertyNames().toString || propertyName == exec->propertyNames().valueOf);
280 }
281
defineGetter(ExecState * exec,const Identifier & propertyName,JSObject * getterFunction,unsigned attributes)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