1 /* 2 * Copyright (C) 2008, 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 "bindings/v8/V8Utilities.h" 33 34 #include "V8MessagePort.h" 35 #include "bindings/v8/ExceptionMessages.h" 36 #include "bindings/v8/ScriptState.h" 37 #include "bindings/v8/V8AbstractEventListener.h" 38 #include "bindings/v8/V8Binding.h" 39 #include "bindings/v8/custom/V8ArrayBufferCustom.h" 40 #include "core/dom/Document.h" 41 #include "core/dom/ExceptionCode.h" 42 #include "core/dom/ExecutionContext.h" 43 #include "core/dom/MessagePort.h" 44 #include "core/frame/Frame.h" 45 #include "core/workers/WorkerGlobalScope.h" 46 #include "wtf/ArrayBuffer.h" 47 #include "wtf/text/WTFString.h" 48 #include <v8.h> 49 50 51 namespace WebCore { 52 53 // Use an array to hold dependents. It works like a ref-counted scheme. 54 // A value can be added more than once to the DOM object. 55 void createHiddenDependency(v8::Handle<v8::Object> object, v8::Local<v8::Value> value, int cacheIndex, v8::Isolate* isolate) 56 { 57 v8::Local<v8::Value> cache = object->GetInternalField(cacheIndex); 58 if (cache->IsNull() || cache->IsUndefined()) { 59 cache = v8::Array::New(isolate); 60 object->SetInternalField(cacheIndex, cache); 61 } 62 63 v8::Local<v8::Array> cacheArray = v8::Local<v8::Array>::Cast(cache); 64 cacheArray->Set(v8::Integer::New(cacheArray->Length(), isolate), value); 65 } 66 67 bool extractTransferables(v8::Local<v8::Value> value, MessagePortArray& ports, ArrayBufferArray& arrayBuffers, bool& notASequence, v8::Isolate* isolate) 68 { 69 if (isUndefinedOrNull(value)) { 70 ports.resize(0); 71 arrayBuffers.resize(0); 72 return true; 73 } 74 75 uint32_t length = 0; 76 if (value->IsArray()) { 77 v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(value); 78 length = array->Length(); 79 } else if (toV8Sequence(value, length, isolate).IsEmpty()) { 80 notASequence = true; 81 return false; 82 } 83 84 v8::Local<v8::Object> transferrables = v8::Local<v8::Object>::Cast(value); 85 86 // Validate the passed array of transferrables. 87 for (unsigned int i = 0; i < length; ++i) { 88 v8::Local<v8::Value> transferrable = transferrables->Get(i); 89 // Validation of non-null objects, per HTML5 spec 10.3.3. 90 if (isUndefinedOrNull(transferrable)) { 91 setDOMException(DataCloneError, isolate); 92 return false; 93 } 94 // Validation of Objects implementing an interface, per WebIDL spec 4.1.15. 95 if (V8MessagePort::hasInstance(transferrable, isolate, worldType(isolate))) { 96 RefPtr<MessagePort> port = V8MessagePort::toNative(v8::Handle<v8::Object>::Cast(transferrable)); 97 // Check for duplicate MessagePorts. 98 if (ports.contains(port)) { 99 setDOMException(DataCloneError, isolate); 100 return false; 101 } 102 ports.append(port.release()); 103 } else if (V8ArrayBuffer::hasInstance(transferrable, isolate, worldType(isolate))) 104 arrayBuffers.append(V8ArrayBuffer::toNative(v8::Handle<v8::Object>::Cast(transferrable))); 105 else { 106 setDOMException(DataCloneError, isolate); 107 return false; 108 } 109 } 110 return true; 111 } 112 113 bool getMessagePortArray(v8::Local<v8::Value> value, const String& propertyName, MessagePortArray& ports, v8::Isolate* isolate) 114 { 115 if (isUndefinedOrNull(value)) { 116 ports.resize(0); 117 return true; 118 } 119 if (!value->IsArray()) { 120 throwTypeError(ExceptionMessages::notASequenceTypeProperty(propertyName), isolate); 121 return false; 122 } 123 bool success = false; 124 ports = toRefPtrNativeArray<MessagePort, V8MessagePort>(value, propertyName, isolate, &success); 125 return success; 126 } 127 128 bool getMessagePortArray(v8::Local<v8::Value> value, int argumentIndex, MessagePortArray& ports, v8::Isolate* isolate) 129 { 130 if (isUndefinedOrNull(value)) { 131 ports.resize(0); 132 return true; 133 } 134 if (!value->IsArray()) { 135 throwTypeError(ExceptionMessages::notAnArrayTypeArgumentOrValue(argumentIndex), isolate); 136 return false; 137 } 138 bool success = false; 139 ports = toRefPtrNativeArray<MessagePort, V8MessagePort>(value, argumentIndex, isolate, &success); 140 return success; 141 } 142 143 void removeHiddenDependency(v8::Handle<v8::Object> object, v8::Local<v8::Value> value, int cacheIndex, v8::Isolate* isolate) 144 { 145 v8::Local<v8::Value> cache = object->GetInternalField(cacheIndex); 146 if (!cache->IsArray()) 147 return; 148 v8::Local<v8::Array> cacheArray = v8::Local<v8::Array>::Cast(cache); 149 for (int i = cacheArray->Length() - 1; i >= 0; --i) { 150 v8::Local<v8::Value> cached = cacheArray->Get(v8::Integer::New(i, isolate)); 151 if (cached->StrictEquals(value)) { 152 cacheArray->Delete(i); 153 return; 154 } 155 } 156 } 157 158 void transferHiddenDependency(v8::Handle<v8::Object> object, EventListener* oldValue, v8::Local<v8::Value> newValue, int cacheIndex, v8::Isolate* isolate) 159 { 160 if (oldValue) { 161 V8AbstractEventListener* oldListener = V8AbstractEventListener::cast(oldValue); 162 if (oldListener) { 163 v8::Local<v8::Object> oldListenerObject = oldListener->getExistingListenerObject(); 164 if (!oldListenerObject.IsEmpty()) 165 removeHiddenDependency(object, oldListenerObject, cacheIndex, isolate); 166 } 167 } 168 // Non-callable input is treated as null and ignored 169 if (newValue->IsFunction()) 170 createHiddenDependency(object, newValue, cacheIndex, isolate); 171 } 172 173 ExecutionContext* getExecutionContext() 174 { 175 if (WorkerScriptController* controller = WorkerScriptController::controllerForContext()) 176 return &controller->workerGlobalScope(); 177 178 return currentDocument(); 179 } 180 181 } // namespace WebCore 182