• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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