af3f8662b7ee2625d6b0b9f1716312dd2c3fb205
[WebKit-https.git] / Source / WebCore / bindings / js / JSLocationCustom.cpp
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
33 static JSValue nonCachingStaticReplaceFunctionGetter(ExecState* exec, JSValue, PropertyName propertyName)
34 {
35     return JSFunction::create(exec, exec->lexicalGlobalObject(), 1, propertyName.impl(), jsLocationPrototypeFunctionReplace);
36 }
37
38 static JSValue nonCachingStaticReloadFunctionGetter(ExecState* exec, JSValue, PropertyName propertyName)
39 {
40     return JSFunction::create(exec, exec->lexicalGlobalObject(), 0, propertyName.impl(), jsLocationPrototypeFunctionReload);
41 }
42
43 static JSValue nonCachingStaticAssignFunctionGetter(ExecState* exec, JSValue, PropertyName propertyName)
44 {
45     return JSFunction::create(exec, exec->lexicalGlobalObject(), 1, propertyName.impl(), jsLocationPrototypeFunctionAssign);
46 }
47
48 bool JSLocation::getOwnPropertySlotDelegate(ExecState* exec, PropertyName 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 (shouldAllowAccessToFrame(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() & JSC::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, PropertyName 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 (!shouldAllowAccessToFrame(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() & JSC::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, PropertyName 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 = shouldAllowAccessToFrame(exec, frame);
138
139     const HashEntry* entry = JSLocation::s_info.propHashTable(exec)->entry(exec, propertyName);
140     if (!entry) {
141         if (sameDomainAccess)
142             JSObject::put(this, 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(JSCell* cell, ExecState* exec, PropertyName propertyName)
156 {
157     JSLocation* thisObject = jsCast<JSLocation*>(cell);
158     // Only allow deleting by frames in the same origin.
159     if (!shouldAllowAccessToFrame(exec, thisObject->impl()->frame()))
160         return false;
161     return Base::deleteProperty(thisObject, exec, propertyName);
162 }
163
164 void JSLocation::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
165 {
166     JSLocation* thisObject = jsCast<JSLocation*>(object);
167     // Only allow the location object to enumerated by frames in the same origin.
168     if (!shouldAllowAccessToFrame(exec, thisObject->impl()->frame()))
169         return;
170     Base::getOwnPropertyNames(thisObject, exec, propertyNames, mode);
171 }
172
173 bool JSLocation::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor, bool throwException)
174 {
175     if (descriptor.isAccessorDescriptor() && (propertyName == exec->propertyNames().toString || propertyName == exec->propertyNames().valueOf))
176         return false;
177     return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
178 }
179
180 void JSLocation::setHref(ExecState* exec, JSValue value)
181 {
182     UString href = value.toString(exec)->value(exec);
183     if (exec->hadException())
184         return;
185     impl()->setHref(ustringToString(href), activeDOMWindow(exec), firstDOMWindow(exec));
186 }
187
188 void JSLocation::setProtocol(ExecState* exec, JSValue value)
189 {
190     UString protocol = value.toString(exec)->value(exec);
191     if (exec->hadException())
192         return;
193     ExceptionCode ec = 0;
194     impl()->setProtocol(ustringToString(protocol), activeDOMWindow(exec), firstDOMWindow(exec), ec);
195     setDOMException(exec, ec);
196 }
197
198 void JSLocation::setHost(ExecState* exec, JSValue value)
199 {
200     UString host = value.toString(exec)->value(exec);
201     if (exec->hadException())
202         return;
203     impl()->setHost(ustringToString(host), activeDOMWindow(exec), firstDOMWindow(exec));
204 }
205
206 void JSLocation::setHostname(ExecState* exec, JSValue value)
207 {
208     UString hostname = value.toString(exec)->value(exec);
209     if (exec->hadException())
210         return;
211     impl()->setHostname(ustringToString(hostname), activeDOMWindow(exec), firstDOMWindow(exec));
212 }
213
214 void JSLocation::setPort(ExecState* exec, JSValue value)
215 {
216     UString port = value.toString(exec)->value(exec);
217     if (exec->hadException())
218         return;
219     impl()->setPort(ustringToString(port), activeDOMWindow(exec), firstDOMWindow(exec));
220 }
221
222 void JSLocation::setPathname(ExecState* exec, JSValue value)
223 {
224     UString pathname = value.toString(exec)->value(exec);
225     if (exec->hadException())
226         return;
227     impl()->setPathname(ustringToString(pathname), activeDOMWindow(exec), firstDOMWindow(exec));
228 }
229
230 void JSLocation::setSearch(ExecState* exec, JSValue value)
231 {
232     UString pathname = value.toString(exec)->value(exec);
233     if (exec->hadException())
234         return;
235     impl()->setSearch(ustringToString(pathname), activeDOMWindow(exec), firstDOMWindow(exec));
236 }
237
238 void JSLocation::setHash(ExecState* exec, JSValue value)
239 {
240     UString hash = value.toString(exec)->value(exec);
241     if (exec->hadException())
242         return;
243     impl()->setHash(ustringToString(hash), activeDOMWindow(exec), firstDOMWindow(exec));
244 }
245
246 JSValue JSLocation::replace(ExecState* exec)
247 {
248     UString urlString = exec->argument(0).toString(exec)->value(exec);
249     if (exec->hadException())
250         return jsUndefined();
251     impl()->replace(ustringToString(urlString), activeDOMWindow(exec), firstDOMWindow(exec));
252     return jsUndefined();
253 }
254
255 JSValue JSLocation::reload(ExecState* exec)
256 {
257     impl()->reload(activeDOMWindow(exec));
258     return jsUndefined();
259 }
260
261 JSValue JSLocation::assign(ExecState* exec)
262 {
263     UString urlString = exec->argument(0).toString(exec)->value(exec);
264     if (exec->hadException())
265         return jsUndefined();
266     impl()->assign(ustringToString(urlString), activeDOMWindow(exec), firstDOMWindow(exec));
267     return jsUndefined();
268 }
269
270 JSValue JSLocation::toStringFunction(ExecState* exec)
271 {
272     Frame* frame = impl()->frame();
273     if (!frame || !shouldAllowAccessToFrame(exec, frame))
274         return jsUndefined();
275
276     return jsString(exec, impl()->toString());
277 }
278
279 bool JSLocationPrototype::putDelegate(ExecState* exec, PropertyName propertyName, JSValue, PutPropertySlot&)
280 {
281     return (propertyName == exec->propertyNames().toString || propertyName == exec->propertyNames().valueOf);
282 }
283
284 bool JSLocationPrototype::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor, bool throwException)
285 {
286     if (descriptor.isAccessorDescriptor() && (propertyName == exec->propertyNames().toString || propertyName == exec->propertyNames().valueOf))
287         return false;
288     return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
289 }
290
291 } // namespace WebCore