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 "Location.h"
33
34 #include "V8Binding.h"
35 #include "V8CustomBinding.h"
36 #include "V8CustomEventListener.h"
37 #include "V8Location.h"
38 #include "V8Utilities.h"
39 #include "V8Proxy.h"
40
41 #include "PlatformString.h"
42 #include "KURL.h"
43 #include "Document.h"
44 #include "FrameLoader.h"
45 #include "ScriptController.h"
46 #include "CSSHelper.h"
47 #include "Frame.h"
48
49 namespace WebCore {
50
51 // Notes about V8/JSC porting of this file.
52 // This class is not very JS-engine specific. If we can move a couple of
53 // methods to the scriptController, we should be able to unify the code
54 // between JSC and V8:
55 // toCallingFrame() - in JSC, this needs an ExecState.
56 // isSafeScript()
57 // Since JSC and V8 have different mechanisms for getting at the calling frame,
58 // we're just making all these custom for now. The functionality is simple
59 // and mirrors JSLocationCustom.cpp.
60
ACCESSOR_SETTER(LocationHash)61 ACCESSOR_SETTER(LocationHash)
62 {
63 INC_STATS("DOM.Location.hash._set");
64 v8::Handle<v8::Object> holder = info.Holder();
65 Location* imp = V8DOMWrapper::convertToNativeObject<Location>(V8ClassIndex::LOCATION, holder);
66 String hash = toWebCoreString(value);
67
68 Frame* frame = imp->frame();
69 if (!frame)
70 return;
71
72 KURL url = frame->loader()->url();
73 String oldRef = url.fragmentIdentifier();
74
75 if (hash.startsWith("#"))
76 hash = hash.substring(1);
77 if (oldRef == hash || (oldRef.isNull() && hash.isEmpty()))
78 return;
79 url.setFragmentIdentifier(hash);
80
81 navigateIfAllowed(frame, url, false, false);
82 }
83
ACCESSOR_SETTER(LocationHost)84 ACCESSOR_SETTER(LocationHost)
85 {
86 INC_STATS("DOM.Location.host._set");
87 v8::Handle<v8::Object> holder = info.Holder();
88 Location* imp = V8DOMWrapper::convertToNativeObject<Location>(V8ClassIndex::LOCATION, holder);
89 String host = toWebCoreString(value);
90
91 Frame* frame = imp->frame();
92 if (!frame)
93 return;
94
95 KURL url = frame->loader()->url();
96 String newHost = host.left(host.find(":"));
97 String newPort = host.substring(host.find(":") + 1);
98 url.setHost(newHost);
99 url.setPort(newPort.toUInt());
100
101 navigateIfAllowed(frame, url, false, false);
102 }
103
ACCESSOR_SETTER(LocationHostname)104 ACCESSOR_SETTER(LocationHostname)
105 {
106 INC_STATS("DOM.Location.hostname._set");
107 v8::Handle<v8::Object> holder = info.Holder();
108 Location* imp = V8DOMWrapper::convertToNativeObject<Location>(V8ClassIndex::LOCATION, holder);
109 String hostname = toWebCoreString(value);
110
111 Frame* frame = imp->frame();
112 if (!frame)
113 return;
114
115 KURL url = frame->loader()->url();
116 url.setHost(hostname);
117
118 navigateIfAllowed(frame, url, false, false);
119 }
120
ACCESSOR_SETTER(LocationHref)121 ACCESSOR_SETTER(LocationHref)
122 {
123 INC_STATS("DOM.Location.href._set");
124 v8::Handle<v8::Object> holder = info.Holder();
125 Location* imp = V8DOMWrapper::convertToNativeObject<Location>(V8ClassIndex::LOCATION, holder);
126
127 Frame* frame = imp->frame();
128 if (!frame)
129 return;
130
131 if (!shouldAllowNavigation(frame))
132 return;
133
134 KURL url = completeURL(toWebCoreString(value));
135 if (url.isNull())
136 return;
137
138 navigateIfAllowed(frame, url, false, false);
139 }
140
ACCESSOR_SETTER(LocationPathname)141 ACCESSOR_SETTER(LocationPathname)
142 {
143 INC_STATS("DOM.Location.pathname._set");
144 v8::Handle<v8::Object> holder = info.Holder();
145 Location* imp = V8DOMWrapper::convertToNativeObject<Location>(V8ClassIndex::LOCATION, holder);
146 String pathname = toWebCoreString(value);
147
148 Frame* frame = imp->frame();
149 if (!frame)
150 return;
151
152 KURL url = frame->loader()->url();
153 url.setPath(pathname);
154
155 navigateIfAllowed(frame, url, false, false);
156 }
157
ACCESSOR_SETTER(LocationPort)158 ACCESSOR_SETTER(LocationPort)
159 {
160 INC_STATS("DOM.Location.port._set");
161 v8::Handle<v8::Object> holder = info.Holder();
162 Location* imp = V8DOMWrapper::convertToNativeObject<Location>(V8ClassIndex::LOCATION, holder);
163 String port = toWebCoreString(value);
164
165 Frame* frame = imp->frame();
166 if (!frame)
167 return;
168
169 KURL url = frame->loader()->url();
170 url.setPort(port.toUInt());
171
172 navigateIfAllowed(frame, url, false, false);
173 }
174
ACCESSOR_SETTER(LocationProtocol)175 ACCESSOR_SETTER(LocationProtocol)
176 {
177 INC_STATS("DOM.Location.protocol._set");
178 v8::Handle<v8::Object> holder = info.Holder();
179 Location* imp = V8DOMWrapper::convertToNativeObject<Location>(V8ClassIndex::LOCATION, holder);
180 String protocol = toWebCoreString(value);
181
182 Frame* frame = imp->frame();
183 if (!frame)
184 return;
185
186 KURL url = frame->loader()->url();
187 url.setProtocol(protocol);
188
189 navigateIfAllowed(frame, url, false, false);
190 }
191
ACCESSOR_SETTER(LocationSearch)192 ACCESSOR_SETTER(LocationSearch)
193 {
194 INC_STATS("DOM.Location.search._set");
195 v8::Handle<v8::Object> holder = info.Holder();
196 Location* imp = V8DOMWrapper::convertToNativeObject<Location>(V8ClassIndex::LOCATION, holder);
197 String query = toWebCoreString(value);
198
199 Frame* frame = imp->frame();
200 if (!frame)
201 return;
202
203 KURL url = frame->loader()->url();
204 url.setQuery(query);
205
206 navigateIfAllowed(frame, url, false, false);
207 }
208
ACCESSOR_GETTER(LocationReload)209 ACCESSOR_GETTER(LocationReload)
210 {
211 INC_STATS("DOM.Location.reload._get");
212 static v8::Persistent<v8::FunctionTemplate> privateTemplate = v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New(v8LocationReloadCallback, v8::Handle<v8::Value>(), v8::Signature::New(V8Location::GetRawTemplate())));
213 v8::Handle<v8::Object> holder = V8DOMWrapper::lookupDOMWrapper(V8ClassIndex::LOCATION, info.This());
214 if (holder.IsEmpty()) {
215 // can only reach here by 'object.__proto__.func', and it should passed
216 // domain security check already
217 return privateTemplate->GetFunction();
218 }
219 Location* imp = V8DOMWrapper::convertToNativeObject<Location>(V8ClassIndex::LOCATION, holder);
220 if (!V8Proxy::canAccessFrame(imp->frame(), false)) {
221 static v8::Persistent<v8::FunctionTemplate> sharedTemplate = v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New(v8LocationReloadCallback, v8::Handle<v8::Value>(), v8::Signature::New(V8Location::GetRawTemplate())));
222 return sharedTemplate->GetFunction();
223 } else
224 return privateTemplate->GetFunction();
225 }
226
ACCESSOR_GETTER(LocationReplace)227 ACCESSOR_GETTER(LocationReplace)
228 {
229 INC_STATS("DOM.Location.replace._get");
230 static v8::Persistent<v8::FunctionTemplate> privateTemplate = v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New(v8LocationReplaceCallback, v8::Handle<v8::Value>(), v8::Signature::New(V8Location::GetRawTemplate())));
231 v8::Handle<v8::Object> holder = V8DOMWrapper::lookupDOMWrapper(V8ClassIndex::LOCATION, info.This());
232 if (holder.IsEmpty()) {
233 // can only reach here by 'object.__proto__.func', and it should passed
234 // domain security check already
235 return privateTemplate->GetFunction();
236 }
237 Location* imp = V8DOMWrapper::convertToNativeObject<Location>(V8ClassIndex::LOCATION, holder);
238 if (!V8Proxy::canAccessFrame(imp->frame(), false)) {
239 static v8::Persistent<v8::FunctionTemplate> sharedTemplate = v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New(v8LocationReplaceCallback, v8::Handle<v8::Value>(), v8::Signature::New(V8Location::GetRawTemplate())));
240 return sharedTemplate->GetFunction();
241 } else
242 return privateTemplate->GetFunction();
243 }
244
ACCESSOR_GETTER(LocationAssign)245 ACCESSOR_GETTER(LocationAssign)
246 {
247 INC_STATS("DOM.Location.assign._get");
248 static v8::Persistent<v8::FunctionTemplate> privateTemplate =
249 v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New(v8LocationAssignCallback, v8::Handle<v8::Value>(), v8::Signature::New(V8Location::GetRawTemplate())));
250 v8::Handle<v8::Object> holder = V8DOMWrapper::lookupDOMWrapper(V8ClassIndex::LOCATION, info.This());
251 if (holder.IsEmpty()) {
252 // can only reach here by 'object.__proto__.func', and it should passed
253 // domain security check already
254 return privateTemplate->GetFunction();
255 }
256 Location* imp = V8DOMWrapper::convertToNativeObject<Location>(V8ClassIndex::LOCATION, holder);
257 if (!V8Proxy::canAccessFrame(imp->frame(), false)) {
258 static v8::Persistent<v8::FunctionTemplate> sharedTemplate = v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New(v8LocationAssignCallback, v8::Handle<v8::Value>(), v8::Signature::New(V8Location::GetRawTemplate())));
259 return sharedTemplate->GetFunction();
260 } else
261 return privateTemplate->GetFunction();
262 }
263
CALLBACK_FUNC_DECL(LocationReload)264 CALLBACK_FUNC_DECL(LocationReload)
265 {
266 // FIXME: we ignore the "forceget" parameter.
267
268 INC_STATS("DOM.Location.reload");
269 v8::Handle<v8::Object> holder = args.Holder();
270 Location* imp = V8DOMWrapper::convertToNativeObject<Location>(V8ClassIndex::LOCATION, holder);
271
272 Frame* frame = imp->frame();
273 if (!frame || !ScriptController::isSafeScript(frame))
274 return v8::Undefined();
275
276 if (!protocolIsJavaScript(frame->loader()->url()))
277 frame->loader()->scheduleRefresh(processingUserGesture());
278 return v8::Undefined();
279 }
280
CALLBACK_FUNC_DECL(LocationReplace)281 CALLBACK_FUNC_DECL(LocationReplace)
282 {
283 INC_STATS("DOM.Location.replace");
284 v8::Handle<v8::Object> holder = args.Holder();
285 Location* imp = V8DOMWrapper::convertToNativeObject<Location>(V8ClassIndex::LOCATION, holder);
286
287 Frame* frame = imp->frame();
288 if (!frame)
289 return v8::Undefined();
290
291 if (!shouldAllowNavigation(frame))
292 return v8::Undefined();
293
294 KURL url = completeURL(toWebCoreString(args[0]));
295 if (url.isNull())
296 return v8::Undefined();
297
298 navigateIfAllowed(frame, url, true, true);
299 return v8::Undefined();
300 }
301
CALLBACK_FUNC_DECL(LocationAssign)302 CALLBACK_FUNC_DECL(LocationAssign)
303 {
304 INC_STATS("DOM.Location.assign");
305 v8::Handle<v8::Object> holder = args.Holder();
306 Location* imp = V8DOMWrapper::convertToNativeObject<Location>(V8ClassIndex::LOCATION, holder);
307
308 Frame* frame = imp->frame();
309 if (!frame)
310 return v8::Undefined();
311
312 if (!shouldAllowNavigation(frame))
313 return v8::Undefined();
314
315 KURL url = completeURL(toWebCoreString(args[0]));
316 if (url.isNull())
317 return v8::Undefined();
318
319 navigateIfAllowed(frame, url, false, false);
320 return v8::Undefined();
321 }
322
CALLBACK_FUNC_DECL(LocationValueOf)323 CALLBACK_FUNC_DECL(LocationValueOf)
324 {
325 // Just return the this object the way the normal valueOf function
326 // on the Object prototype would. The valueOf function is only
327 // added to make sure that it cannot be overwritten on location
328 // objects, since that would provide a hook to change the string
329 // conversion behavior of location objects.
330 return args.This();
331 }
332
CALLBACK_FUNC_DECL(LocationToString)333 CALLBACK_FUNC_DECL(LocationToString)
334 {
335 INC_STATS("DOM.Location.toString");
336 v8::Handle<v8::Object> holder = args.Holder();
337 Location* imp = V8DOMWrapper::convertToNativeObject<Location>(V8ClassIndex::LOCATION, holder);
338 if (!V8Proxy::canAccessFrame(imp->frame(), true))
339 return v8::Undefined();
340 String result = imp->href();
341 return v8String(result);
342 }
343
INDEXED_ACCESS_CHECK(Location)344 INDEXED_ACCESS_CHECK(Location)
345 {
346 ASSERT(V8ClassIndex::FromInt(data->Int32Value()) == V8ClassIndex::LOCATION);
347 // Only allow same origin access
348 Location* imp = V8DOMWrapper::convertToNativeObject<Location>(V8ClassIndex::LOCATION, host);
349 return V8Proxy::canAccessFrame(imp->frame(), false);
350 }
351
NAMED_ACCESS_CHECK(Location)352 NAMED_ACCESS_CHECK(Location)
353 {
354 ASSERT(V8ClassIndex::FromInt(data->Int32Value()) == V8ClassIndex::LOCATION);
355 // Only allow same origin access
356 Location* imp = V8DOMWrapper::convertToNativeObject<Location>(V8ClassIndex::LOCATION, host);
357 return V8Proxy::canAccessFrame(imp->frame(), false);
358 }
359
360 } // namespace WebCore
361
362