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