1/* 2 * Copyright (C) 2008 Apple 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 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of Apple Inc. ("Apple") nor the names of 14 * its contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include "config.h" 30#include "JSHistory.h" 31 32#include "Frame.h" 33#include "JSDOMBinding.h" 34#include "SerializedScriptValue.h" 35#include <runtime/JSFunction.h> 36 37using namespace JSC; 38 39namespace WebCore { 40 41bool JSHistory::getOwnPropertySlotDelegate(ExecState* exec, PropertyName propertyName, PropertySlot& slot) 42{ 43 // When accessing History cross-domain, functions are always the native built-in ones. 44 // See JSDOMWindow::getOwnPropertySlotDelegate for additional details. 45 46 // Our custom code is only needed to implement the Window cross-domain scheme, so if access is 47 // allowed, return false so the normal lookup will take place. 48 String message; 49 if (shouldAllowAccessToFrame(exec, impl().frame(), message)) 50 return false; 51 52 // Check for the few functions that we allow, even when called cross-domain. 53 // Make these read-only / non-configurable to prevent writes via defineProperty. 54 if (propertyName == exec->propertyNames().back) { 55 slot.setCustom(this, ReadOnly | DontDelete | DontEnum, nonCachingStaticFunctionGetter<jsHistoryPrototypeFunctionBack, 0>); 56 return true; 57 } 58 if (propertyName == exec->propertyNames().forward) { 59 slot.setCustom(this, ReadOnly | DontDelete | DontEnum, nonCachingStaticFunctionGetter<jsHistoryPrototypeFunctionForward, 0>); 60 return true; 61 } 62 if (propertyName == exec->propertyNames().go) { 63 slot.setCustom(this, ReadOnly | DontDelete | DontEnum, nonCachingStaticFunctionGetter<jsHistoryPrototypeFunctionGo, 1>); 64 return true; 65 } 66 // Allow access to toString() cross-domain, but always Object.toString. 67 if (propertyName == exec->propertyNames().toString) { 68 slot.setCustom(this, ReadOnly | DontDelete | DontEnum, objectToStringFunctionGetter); 69 return true; 70 } 71 72 printErrorMessageForFrame(impl().frame(), message); 73 slot.setUndefined(); 74 return true; 75} 76 77bool JSHistory::putDelegate(ExecState* exec, PropertyName, JSValue, PutPropertySlot&) 78{ 79 // Only allow putting by frames in the same origin. 80 if (!shouldAllowAccessToFrame(exec, impl().frame())) 81 return true; 82 return false; 83} 84 85bool JSHistory::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName) 86{ 87 JSHistory* thisObject = jsCast<JSHistory*>(cell); 88 // Only allow deleting by frames in the same origin. 89 if (!shouldAllowAccessToFrame(exec, thisObject->impl().frame())) 90 return false; 91 return Base::deleteProperty(thisObject, exec, propertyName); 92} 93 94bool JSHistory::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned propertyName) 95{ 96 JSHistory* thisObject = jsCast<JSHistory*>(cell); 97 // Only allow deleting by frames in the same origin. 98 if (!shouldAllowAccessToFrame(exec, thisObject->impl().frame())) 99 return false; 100 return Base::deletePropertyByIndex(thisObject, exec, propertyName); 101} 102 103void JSHistory::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) 104{ 105 JSHistory* thisObject = jsCast<JSHistory*>(object); 106 // Only allow the history object to enumerated by frames in the same origin. 107 if (!shouldAllowAccessToFrame(exec, thisObject->impl().frame())) 108 return; 109 Base::getOwnPropertyNames(thisObject, exec, propertyNames, mode); 110} 111 112JSValue JSHistory::state(ExecState *exec) const 113{ 114 History& history = impl(); 115 116 JSValue cachedValue = m_state.get(); 117 if (!cachedValue.isEmpty() && !history.stateChanged()) 118 return cachedValue; 119 120 RefPtr<SerializedScriptValue> serialized = history.state(); 121 JSValue result = serialized ? serialized->deserialize(exec, globalObject(), 0) : jsNull(); 122 const_cast<JSHistory*>(this)->m_state.set(exec->vm(), this, result); 123 return result; 124} 125 126JSValue JSHistory::pushState(ExecState* exec) 127{ 128 RefPtr<SerializedScriptValue> historyState = SerializedScriptValue::create(exec, exec->argument(0), 0, 0); 129 if (exec->hadException()) 130 return jsUndefined(); 131 132 String title = valueToStringWithUndefinedOrNullCheck(exec, exec->argument(1)); 133 if (exec->hadException()) 134 return jsUndefined(); 135 136 String url; 137 if (exec->argumentCount() > 2) { 138 url = valueToStringWithUndefinedOrNullCheck(exec, exec->argument(2)); 139 if (exec->hadException()) 140 return jsUndefined(); 141 } 142 143 ExceptionCode ec = 0; 144 impl().stateObjectAdded(historyState.release(), title, url, History::StateObjectType::Push, ec); 145 setDOMException(exec, ec); 146 147 m_state.clear(); 148 149 return jsUndefined(); 150} 151 152JSValue JSHistory::replaceState(ExecState* exec) 153{ 154 RefPtr<SerializedScriptValue> historyState = SerializedScriptValue::create(exec, exec->argument(0), 0, 0); 155 if (exec->hadException()) 156 return jsUndefined(); 157 158 String title = valueToStringWithUndefinedOrNullCheck(exec, exec->argument(1)); 159 if (exec->hadException()) 160 return jsUndefined(); 161 162 String url; 163 if (exec->argumentCount() > 2) { 164 url = valueToStringWithUndefinedOrNullCheck(exec, exec->argument(2)); 165 if (exec->hadException()) 166 return jsUndefined(); 167 } 168 169 ExceptionCode ec = 0; 170 impl().stateObjectAdded(historyState.release(), title, url, History::StateObjectType::Replace, ec); 171 setDOMException(exec, ec); 172 173 m_state.clear(); 174 175 return jsUndefined(); 176} 177 178} // namespace WebCore 179