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