Source/WebCore: https://bugs.webkit.org/show_bug.cgi?id=73054
[WebKit-https.git] / Source / WebCore / bindings / v8 / V8Utilities.cpp
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 "V8Utilities.h"
33
34 #include "ArrayBuffer.h"
35 #include "Document.h"
36 #include "ExceptionCode.h"
37 #include "Frame.h"
38 #include "MessagePort.h"
39 #include "ScriptExecutionContext.h"
40 #include "ScriptState.h"
41 #include "V8ArrayBuffer.h"
42 #include "V8Binding.h"
43 #include "V8BindingState.h"
44 #include "V8MessagePort.h"
45 #include "V8Proxy.h"
46 #include "WorkerContext.h"
47 #include "WorkerContextExecutionProxy.h"
48
49 #include <wtf/Assertions.h>
50 #include "Frame.h"
51
52 #include <v8.h>
53
54 namespace WebCore {
55
56 V8LocalContext::V8LocalContext()
57     : m_context(v8::Context::New())
58 {
59     V8BindingPerIsolateData::ensureInitialized(v8::Isolate::GetCurrent());
60     m_context->Enter();
61 }
62
63
64 V8LocalContext::~V8LocalContext()
65 {
66     m_context->Exit();
67     m_context.Dispose();
68 }
69
70 // Use an array to hold dependents. It works like a ref-counted scheme.
71 // A value can be added more than once to the DOM object.
72 void createHiddenDependency(v8::Handle<v8::Object> object, v8::Local<v8::Value> value, int cacheIndex)
73 {
74     v8::Local<v8::Value> cache = object->GetInternalField(cacheIndex);
75     if (cache->IsNull() || cache->IsUndefined()) {
76         cache = v8::Array::New();
77         object->SetInternalField(cacheIndex, cache);
78     }
79
80     v8::Local<v8::Array> cacheArray = v8::Local<v8::Array>::Cast(cache);
81     cacheArray->Set(v8::Integer::New(cacheArray->Length()), value);
82 }
83
84 bool extractTransferables(v8::Local<v8::Value> value, MessagePortArray& ports, ArrayBufferArray& arrayBuffers)
85 {
86     if (isUndefinedOrNull(value)) {
87         ports.resize(0);
88         arrayBuffers.resize(0);
89         return true;
90     }
91
92     if (!value->IsObject()) {
93         throwError("TransferArray argument must be an object");
94         return false;
95     }
96     uint32_t length = 0;
97     v8::Local<v8::Object> transferrables = v8::Local<v8::Object>::Cast(value);
98
99     if (value->IsArray()) {
100         v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(value);
101         length = array->Length();
102     } else {
103         // Sequence-type object - get the length attribute
104         v8::Local<v8::Value> sequenceLength = transferrables->Get(v8::String::New("length"));
105         if (!sequenceLength->IsNumber()) {
106             throwError("TransferArray argument has no length attribute");
107             return false;
108         }
109         length = sequenceLength->Uint32Value();
110     }
111
112     // Validate the passed array of transferrables.
113     for (unsigned int i = 0; i < length; ++i) {
114         v8::Local<v8::Value> transferrable = transferrables->Get(i);
115         // Validation of non-null objects, per HTML5 spec 10.3.3.
116         if (isUndefinedOrNull(transferrable)) {
117             throwError(DATA_CLONE_ERR);
118             return false;
119         }
120         // Validation of Objects implementing an interface, per WebIDL spec 4.1.15.
121         if (V8MessagePort::HasInstance(transferrable))
122             ports.append(V8MessagePort::toNative(v8::Handle<v8::Object>::Cast(transferrable)));
123         else if (V8ArrayBuffer::HasInstance(transferrable))
124             arrayBuffers.append(V8ArrayBuffer::toNative(v8::Handle<v8::Object>::Cast(transferrable)));
125         else {
126             throwError("TransferArray argument must contain only Transferables");
127             return false;
128         }
129     }
130     return true;
131 }
132
133 bool getMessagePortArray(v8::Local<v8::Value> value, MessagePortArray& ports)
134 {
135     ArrayBufferArray arrayBuffers;
136     bool result = extractTransferables(value, ports, arrayBuffers);
137     if (!result)
138         return false;
139     if (arrayBuffers.size() > 0) {
140         throwError("MessagePortArray argument must contain only MessagePorts");
141         return false;
142     }
143     return true;
144 }
145
146 void removeHiddenDependency(v8::Handle<v8::Object> object, v8::Local<v8::Value> value, int cacheIndex)
147 {
148     v8::Local<v8::Value> cache = object->GetInternalField(cacheIndex);
149     if (!cache->IsArray())
150         return;
151     v8::Local<v8::Array> cacheArray = v8::Local<v8::Array>::Cast(cache);
152     for (int i = cacheArray->Length() - 1; i >= 0; --i) {
153         v8::Local<v8::Value> cached = cacheArray->Get(v8::Integer::New(i));
154         if (cached->StrictEquals(value)) {
155             cacheArray->Delete(i);
156             return;
157         }
158     }
159 }
160     
161 void transferHiddenDependency(v8::Handle<v8::Object> object,
162                               EventListener* oldValue, 
163                               v8::Local<v8::Value> newValue, 
164                               int cacheIndex)
165 {
166     if (oldValue) {
167         V8AbstractEventListener* oldListener = V8AbstractEventListener::cast(oldValue);
168         if (oldListener) {
169             v8::Local<v8::Object> oldListenerObject = oldListener->getExistingListenerObject();
170             if (!oldListenerObject.IsEmpty())
171                 removeHiddenDependency(object, oldListenerObject, cacheIndex);
172         }
173     }
174     if (!newValue->IsNull() && !newValue->IsUndefined())
175         createHiddenDependency(object, newValue, cacheIndex);
176 }
177
178 Frame* callingOrEnteredFrame()
179 {
180     return V8BindingState::Only()->activeFrame();
181 }
182
183 bool shouldAllowNavigation(Frame* frame)
184 {
185     return V8BindingSecurity::shouldAllowNavigation(V8BindingState::Only(), frame);
186 }
187
188 KURL completeURL(const String& relativeURL)
189 {
190     return completeURL(V8BindingState::Only(), relativeURL);
191 }
192
193 ScriptExecutionContext* getScriptExecutionContext()
194 {
195 #if ENABLE(WORKERS)
196     if (WorkerScriptController* controller = WorkerScriptController::controllerForContext())
197         return controller->workerContext();
198 #endif
199
200     if (Frame* frame = V8Proxy::retrieveFrameForCurrentContext())
201         return frame->document()->scriptExecutionContext();
202
203     return 0;
204 }
205
206 void throwTypeMismatchException()
207 {
208     V8Proxy::throwError(V8Proxy::GeneralError, "TYPE_MISMATCH_ERR: DOM Exception 17");
209 }
210
211 } // namespace WebCore