• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "XMLHttpRequest.h"
33 
34 #include "Frame.h"
35 #include "V8Binding.h"
36 #include "V8Document.h"
37 #include "V8CustomBinding.h"
38 #include "V8HTMLDocument.h"
39 #include "V8ObjectEventListener.h"
40 #include "V8Proxy.h"
41 #include "V8Utilities.h"
42 #include "WorkerContext.h"
43 #include "WorkerContextExecutionProxy.h"
44 
45 namespace WebCore {
46 
getEventListener(XMLHttpRequest * xmlHttpRequest,v8::Local<v8::Value> value,bool findOnly)47 static PassRefPtr<EventListener> getEventListener(XMLHttpRequest* xmlHttpRequest, v8::Local<v8::Value> value, bool findOnly)
48 {
49 #if ENABLE(WORKERS)
50     WorkerContextExecutionProxy* workerContextProxy = WorkerContextExecutionProxy::retrieve();
51     if (workerContextProxy)
52         return workerContextProxy->findOrCreateObjectEventListener(value, false, findOnly);
53 #endif
54 
55     V8Proxy* proxy = V8Proxy::retrieve(xmlHttpRequest->scriptExecutionContext());
56     if (proxy) {
57         V8EventListenerList* list = proxy->objectListeners();
58         return findOnly ? list->findWrapper(value, false) : list->findOrCreateWrapper<V8ObjectEventListener>(proxy->frame(), value, false);
59     }
60 
61     return PassRefPtr<EventListener>();
62 }
63 
ACCESSOR_GETTER(XMLHttpRequestOnabort)64 ACCESSOR_GETTER(XMLHttpRequestOnabort)
65 {
66     INC_STATS("DOM.XMLHttpRequest.onabort._get");
67     XMLHttpRequest* xmlHttpRequest = V8DOMWrapper::convertToNativeObject<XMLHttpRequest>(V8ClassIndex::XMLHTTPREQUEST, info.Holder());
68     if (xmlHttpRequest->onabort()) {
69         V8ObjectEventListener* listener = static_cast<V8ObjectEventListener*>(xmlHttpRequest->onabort());
70         v8::Local<v8::Object> v8Listener = listener->getListenerObject();
71         return v8Listener;
72     }
73     return v8::Null();
74 }
75 
ACCESSOR_SETTER(XMLHttpRequestOnabort)76 ACCESSOR_SETTER(XMLHttpRequestOnabort)
77 {
78     INC_STATS("DOM.XMLHttpRequest.onabort._set");
79     XMLHttpRequest* xmlHttpRequest = V8DOMWrapper::convertToNativeObject<XMLHttpRequest>(V8ClassIndex::XMLHTTPREQUEST, info.Holder());
80     if (value->IsNull()) {
81         if (xmlHttpRequest->onabort()) {
82             V8ObjectEventListener* listener = static_cast<V8ObjectEventListener*>(xmlHttpRequest->onabort());
83             v8::Local<v8::Object> v8Listener = listener->getListenerObject();
84             removeHiddenDependency(info.Holder(), v8Listener, V8Custom::kXMLHttpRequestCacheIndex);
85         }
86 
87         // Clear the listener.
88         xmlHttpRequest->setOnabort(0);
89     } else {
90         RefPtr<EventListener> listener = getEventListener(xmlHttpRequest, value, false);
91         if (listener) {
92             xmlHttpRequest->setOnabort(listener);
93             createHiddenDependency(info.Holder(), value, V8Custom::kXMLHttpRequestCacheIndex);
94         }
95     }
96 }
97 
ACCESSOR_GETTER(XMLHttpRequestOnerror)98 ACCESSOR_GETTER(XMLHttpRequestOnerror)
99 {
100     INC_STATS("DOM.XMLHttpRequest.onerror._get");
101     XMLHttpRequest* xmlHttpRequest = V8DOMWrapper::convertToNativeObject<XMLHttpRequest>(V8ClassIndex::XMLHTTPREQUEST, info.Holder());
102     if (xmlHttpRequest->onerror()) {
103         RefPtr<V8ObjectEventListener> listener = static_cast<V8ObjectEventListener*>(xmlHttpRequest->onerror());
104         v8::Local<v8::Object> v8Listener = listener->getListenerObject();
105         return v8Listener;
106     }
107     return v8::Null();
108 }
109 
ACCESSOR_SETTER(XMLHttpRequestOnerror)110 ACCESSOR_SETTER(XMLHttpRequestOnerror)
111 {
112     INC_STATS("DOM.XMLHttpRequest.onerror._set");
113     XMLHttpRequest* xmlHttpRequest = V8DOMWrapper::convertToNativeObject<XMLHttpRequest>(V8ClassIndex::XMLHTTPREQUEST, info.Holder());
114     if (value->IsNull()) {
115         if (xmlHttpRequest->onerror()) {
116             V8ObjectEventListener* listener = static_cast<V8ObjectEventListener*>(xmlHttpRequest->onerror());
117             v8::Local<v8::Object> v8Listener = listener->getListenerObject();
118             removeHiddenDependency(info.Holder(), v8Listener, V8Custom::kXMLHttpRequestCacheIndex);
119         }
120 
121         // Clear the listener.
122         xmlHttpRequest->setOnerror(0);
123     } else {
124         RefPtr<EventListener> listener = getEventListener(xmlHttpRequest, value, false);
125         if (listener) {
126             xmlHttpRequest->setOnerror(listener);
127             createHiddenDependency(info.Holder(), value, V8Custom::kXMLHttpRequestCacheIndex);
128         }
129     }
130 }
131 
ACCESSOR_GETTER(XMLHttpRequestOnload)132 ACCESSOR_GETTER(XMLHttpRequestOnload)
133 {
134     INC_STATS("DOM.XMLHttpRequest.onload._get");
135     XMLHttpRequest* xmlHttpRequest = V8DOMWrapper::convertToNativeObject<XMLHttpRequest>(V8ClassIndex::XMLHTTPREQUEST, info.Holder());
136     if (xmlHttpRequest->onload()) {
137         V8ObjectEventListener* listener = static_cast<V8ObjectEventListener*>(xmlHttpRequest->onload());
138         v8::Local<v8::Object> v8Listener = listener->getListenerObject();
139         return v8Listener;
140     }
141     return v8::Null();
142 }
143 
ACCESSOR_SETTER(XMLHttpRequestOnload)144 ACCESSOR_SETTER(XMLHttpRequestOnload)
145 {
146     INC_STATS("DOM.XMLHttpRequest.onload._set");
147     XMLHttpRequest* xmlHttpRequest = V8DOMWrapper::convertToNativeObject<XMLHttpRequest>(V8ClassIndex::XMLHTTPREQUEST, info.Holder());
148     if (value->IsNull()) {
149         if (xmlHttpRequest->onload()) {
150             V8ObjectEventListener* listener = static_cast<V8ObjectEventListener*>(xmlHttpRequest->onload());
151             v8::Local<v8::Object> v8Listener = listener->getListenerObject();
152             removeHiddenDependency(info.Holder(), v8Listener, V8Custom::kXMLHttpRequestCacheIndex);
153         }
154 
155         xmlHttpRequest->setOnload(0);
156 
157     } else {
158         RefPtr<EventListener> listener = getEventListener(xmlHttpRequest, value, false);
159         if (listener) {
160             xmlHttpRequest->setOnload(listener.get());
161             createHiddenDependency(info.Holder(), value, V8Custom::kXMLHttpRequestCacheIndex);
162         }
163     }
164 }
165 
ACCESSOR_GETTER(XMLHttpRequestOnloadstart)166 ACCESSOR_GETTER(XMLHttpRequestOnloadstart)
167 {
168     INC_STATS("DOM.XMLHttpRequest.onloadstart._get");
169     XMLHttpRequest* xmlHttpRequest = V8DOMWrapper::convertToNativeObject<XMLHttpRequest>(V8ClassIndex::XMLHTTPREQUEST, info.Holder());
170     if (xmlHttpRequest->onloadstart()) {
171         V8ObjectEventListener* listener = static_cast<V8ObjectEventListener*>(xmlHttpRequest->onloadstart());
172         v8::Local<v8::Object> v8Listener = listener->getListenerObject();
173         return v8Listener;
174     }
175     return v8::Null();
176 }
177 
ACCESSOR_SETTER(XMLHttpRequestOnloadstart)178 ACCESSOR_SETTER(XMLHttpRequestOnloadstart)
179 {
180     INC_STATS("DOM.XMLHttpRequest.onloadstart._set");
181     XMLHttpRequest* xmlHttpRequest = V8DOMWrapper::convertToNativeObject<XMLHttpRequest>(V8ClassIndex::XMLHTTPREQUEST, info.Holder());
182     if (value->IsNull()) {
183         if (xmlHttpRequest->onloadstart()) {
184             V8ObjectEventListener* listener = static_cast<V8ObjectEventListener*>(xmlHttpRequest->onloadstart());
185             v8::Local<v8::Object> v8Listener = listener->getListenerObject();
186             removeHiddenDependency(info.Holder(), v8Listener, V8Custom::kXMLHttpRequestCacheIndex);
187         }
188 
189         // Clear the listener.
190         xmlHttpRequest->setOnloadstart(0);
191     } else {
192         RefPtr<EventListener> listener = getEventListener(xmlHttpRequest, value, false);
193         if (listener) {
194             xmlHttpRequest->setOnloadstart(listener);
195             createHiddenDependency(info.Holder(), value, V8Custom::kXMLHttpRequestCacheIndex);
196         }
197     }
198 }
199 
ACCESSOR_GETTER(XMLHttpRequestOnprogress)200 ACCESSOR_GETTER(XMLHttpRequestOnprogress)
201 {
202     INC_STATS("DOM.XMLHttpRequest.onprogress._get");
203     XMLHttpRequest* xmlHttpRequest = V8DOMWrapper::convertToNativeObject<XMLHttpRequest>(V8ClassIndex::XMLHTTPREQUEST, info.Holder());
204     if (xmlHttpRequest->onprogress()) {
205         V8ObjectEventListener* listener = static_cast<V8ObjectEventListener*>(xmlHttpRequest->onprogress());
206         v8::Local<v8::Object> v8Listener = listener->getListenerObject();
207         return v8Listener;
208     }
209     return v8::Null();
210 }
211 
ACCESSOR_SETTER(XMLHttpRequestOnprogress)212 ACCESSOR_SETTER(XMLHttpRequestOnprogress)
213 {
214     INC_STATS("DOM.XMLHttpRequest.onprogress._set");
215     XMLHttpRequest* xmlHttpRequest = V8DOMWrapper::convertToNativeObject<XMLHttpRequest>(V8ClassIndex::XMLHTTPREQUEST, info.Holder());
216     if (value->IsNull()) {
217         if (xmlHttpRequest->onprogress()) {
218             V8ObjectEventListener* listener = static_cast<V8ObjectEventListener*>(xmlHttpRequest->onprogress());
219             v8::Local<v8::Object> v8Listener = listener->getListenerObject();
220             removeHiddenDependency(info.Holder(), v8Listener, V8Custom::kXMLHttpRequestCacheIndex);
221         }
222 
223         // Clear the listener.
224         xmlHttpRequest->setOnprogress(0);
225     } else {
226         RefPtr<EventListener> listener = getEventListener(xmlHttpRequest, value, false);
227         if (listener) {
228             xmlHttpRequest->setOnprogress(listener);
229             createHiddenDependency(info.Holder(), value, V8Custom::kXMLHttpRequestCacheIndex);
230         }
231     }
232 }
233 
ACCESSOR_GETTER(XMLHttpRequestOnreadystatechange)234 ACCESSOR_GETTER(XMLHttpRequestOnreadystatechange)
235 {
236     INC_STATS("DOM.XMLHttpRequest.onreadystatechange._get");
237     XMLHttpRequest* xmlHttpRequest = V8DOMWrapper::convertToNativeObject<XMLHttpRequest>(V8ClassIndex::XMLHTTPREQUEST, info.Holder());
238     if (xmlHttpRequest->onreadystatechange()) {
239         V8ObjectEventListener* listener = static_cast<V8ObjectEventListener*>(xmlHttpRequest->onreadystatechange());
240         v8::Local<v8::Object> v8Listener = listener->getListenerObject();
241         return v8Listener;
242     }
243     return v8::Null();
244 }
245 
ACCESSOR_SETTER(XMLHttpRequestOnreadystatechange)246 ACCESSOR_SETTER(XMLHttpRequestOnreadystatechange)
247 {
248     INC_STATS("DOM.XMLHttpRequest.onreadystatechange._set");
249     XMLHttpRequest* xmlHttpRequest = V8DOMWrapper::convertToNativeObject<XMLHttpRequest>(V8ClassIndex::XMLHTTPREQUEST, info.Holder());
250     if (value->IsNull()) {
251         if (xmlHttpRequest->onreadystatechange()) {
252             V8ObjectEventListener* listener = static_cast<V8ObjectEventListener*>(xmlHttpRequest->onreadystatechange());
253             v8::Local<v8::Object> v8Listener = listener->getListenerObject();
254             removeHiddenDependency(info.Holder(), v8Listener, V8Custom::kXMLHttpRequestCacheIndex);
255         }
256 
257         // Clear the listener.
258         xmlHttpRequest->setOnreadystatechange(0);
259     } else {
260         RefPtr<EventListener> listener = getEventListener(xmlHttpRequest, value, false);
261         if (listener) {
262             xmlHttpRequest->setOnreadystatechange(listener.get());
263             createHiddenDependency(info.Holder(), value, V8Custom::kXMLHttpRequestCacheIndex);
264         }
265     }
266 }
267 
ACCESSOR_GETTER(XMLHttpRequestResponseText)268 ACCESSOR_GETTER(XMLHttpRequestResponseText)
269 {
270     // FIXME: This is only needed because webkit set this getter as custom.
271     // So we need a custom method to avoid forking the IDL file.
272     INC_STATS("DOM.XMLHttpRequest.responsetext._get");
273     XMLHttpRequest* xmlHttpRequest = V8DOMWrapper::convertToNativeObject<XMLHttpRequest>(V8ClassIndex::XMLHTTPREQUEST, info.Holder());
274     return v8StringOrNull(xmlHttpRequest->responseText());
275 }
276 
CALLBACK_FUNC_DECL(XMLHttpRequestAddEventListener)277 CALLBACK_FUNC_DECL(XMLHttpRequestAddEventListener)
278 {
279     INC_STATS("DOM.XMLHttpRequest.addEventListener()");
280     XMLHttpRequest* xmlHttpRequest = V8DOMWrapper::convertToNativeObject<XMLHttpRequest>(V8ClassIndex::XMLHTTPREQUEST, args.Holder());
281 
282     RefPtr<EventListener> listener = getEventListener(xmlHttpRequest, args[1], false);
283     if (listener) {
284         String type = toWebCoreString(args[0]);
285         bool useCapture = args[2]->BooleanValue();
286         xmlHttpRequest->addEventListener(type, listener, useCapture);
287 
288         createHiddenDependency(args.Holder(), args[1], V8Custom::kXMLHttpRequestCacheIndex);
289     }
290     return v8::Undefined();
291 }
292 
CALLBACK_FUNC_DECL(XMLHttpRequestRemoveEventListener)293 CALLBACK_FUNC_DECL(XMLHttpRequestRemoveEventListener)
294 {
295     INC_STATS("DOM.XMLHttpRequest.removeEventListener()");
296     XMLHttpRequest* xmlHttpRequest = V8DOMWrapper::convertToNativeObject<XMLHttpRequest>(V8ClassIndex::XMLHTTPREQUEST, args.Holder());
297 
298     RefPtr<EventListener> listener = getEventListener(xmlHttpRequest, args[1], true);
299     if (listener) {
300         String type = toWebCoreString(args[0]);
301         bool useCapture = args[2]->BooleanValue();
302         xmlHttpRequest->removeEventListener(type, listener.get(), useCapture);
303 
304         removeHiddenDependency(args.Holder(), args[1], V8Custom::kXMLHttpRequestCacheIndex);
305     }
306 
307     return v8::Undefined();
308 }
309 
CALLBACK_FUNC_DECL(XMLHttpRequestOpen)310 CALLBACK_FUNC_DECL(XMLHttpRequestOpen)
311 {
312     INC_STATS("DOM.XMLHttpRequest.open()");
313     // Four cases:
314     // open(method, url)
315     // open(method, url, async)
316     // open(method, url, async, user)
317     // open(method, url, async, user, passwd)
318 
319     if (args.Length() < 2)
320         return throwError("Not enough arguments", V8Proxy::SyntaxError);
321 
322     XMLHttpRequest* xmlHttpRequest = V8DOMWrapper::convertToNativeObject<XMLHttpRequest>(V8ClassIndex::XMLHTTPREQUEST, args.Holder());
323 
324     String method = toWebCoreString(args[0]);
325     String urlstring = toWebCoreString(args[1]);
326     ScriptExecutionContext* context = 0;
327 #if ENABLE(WORKERS)
328     WorkerContextExecutionProxy* workerContextProxy = WorkerContextExecutionProxy::retrieve();
329     if (workerContextProxy) {
330         context = workerContextProxy->workerContext();
331         ASSERT(context);
332     }
333 #endif
334 
335     if (!context) {
336         V8Proxy* proxy = V8Proxy::retrieve();
337         if (!proxy)
338             return v8::Undefined();
339         context = proxy->frame()->document();
340         ASSERT(context);
341     }
342 
343     KURL url = context->completeURL(urlstring);
344 
345     bool async = (args.Length() < 3) ? true : args[2]->BooleanValue();
346 
347     ExceptionCode ec = 0;
348     String user, passwd;
349     if (args.Length() >= 4 && !args[3]->IsUndefined()) {
350         user = toWebCoreStringWithNullCheck(args[3]);
351 
352         if (args.Length() >= 5 && !args[4]->IsUndefined()) {
353             passwd = toWebCoreStringWithNullCheck(args[4]);
354             xmlHttpRequest->open(method, url, async, user, passwd, ec);
355         } else
356             xmlHttpRequest->open(method, url, async, user, ec);
357     } else
358         xmlHttpRequest->open(method, url, async, ec);
359 
360     if (ec)
361         return throwError(ec);
362 
363     return v8::Undefined();
364 }
365 
IsDocumentType(v8::Handle<v8::Value> value)366 static bool IsDocumentType(v8::Handle<v8::Value> value)
367 {
368     // FIXME: add other document types.
369     return V8Document::HasInstance(value) || V8HTMLDocument::HasInstance(value);
370 }
371 
CALLBACK_FUNC_DECL(XMLHttpRequestSend)372 CALLBACK_FUNC_DECL(XMLHttpRequestSend)
373 {
374     INC_STATS("DOM.XMLHttpRequest.send()");
375     XMLHttpRequest* xmlHttpRequest = V8DOMWrapper::convertToNativeObject<XMLHttpRequest>(V8ClassIndex::XMLHTTPREQUEST, args.Holder());
376 
377     ExceptionCode ec = 0;
378     if (args.Length() < 1)
379         xmlHttpRequest->send(ec);
380     else {
381         v8::Handle<v8::Value> arg = args[0];
382         // FIXME: upstream handles "File" objects too.
383         if (IsDocumentType(arg)) {
384             v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(arg);
385             Document* document = V8DOMWrapper::convertDOMWrapperToNode<Document>(object);
386             ASSERT(document);
387             xmlHttpRequest->send(document, ec);
388         } else
389             xmlHttpRequest->send(toWebCoreStringWithNullCheck(arg), ec);
390     }
391 
392     if (ec)
393         return throwError(ec);
394 
395     return v8::Undefined();
396 }
397 
CALLBACK_FUNC_DECL(XMLHttpRequestSetRequestHeader)398 CALLBACK_FUNC_DECL(XMLHttpRequestSetRequestHeader) {
399     INC_STATS("DOM.XMLHttpRequest.setRequestHeader()");
400     if (args.Length() < 2)
401         return throwError("Not enough arguments", V8Proxy::SyntaxError);
402 
403     XMLHttpRequest* xmlHttpRequest = V8DOMWrapper::convertToNativeObject<XMLHttpRequest>(V8ClassIndex::XMLHTTPREQUEST, args.Holder());
404     ExceptionCode ec = 0;
405     String header = toWebCoreString(args[0]);
406     String value = toWebCoreString(args[1]);
407     xmlHttpRequest->setRequestHeader(header, value, ec);
408     if (ec)
409         return throwError(ec);
410     return v8::Undefined();
411 }
412 
CALLBACK_FUNC_DECL(XMLHttpRequestGetResponseHeader)413 CALLBACK_FUNC_DECL(XMLHttpRequestGetResponseHeader)
414 {
415     INC_STATS("DOM.XMLHttpRequest.getResponseHeader()");
416     if (args.Length() < 1)
417         return throwError("Not enough arguments", V8Proxy::SyntaxError);
418 
419     XMLHttpRequest* xmlHttpRequest = V8DOMWrapper::convertToNativeObject<XMLHttpRequest>(V8ClassIndex::XMLHTTPREQUEST, args.Holder());
420     ExceptionCode ec = 0;
421     String header = toWebCoreString(args[0]);
422     String result = xmlHttpRequest->getResponseHeader(header, ec);
423     if (ec)
424         return throwError(ec);
425     return v8StringOrNull(result);
426 }
427 
CALLBACK_FUNC_DECL(XMLHttpRequestOverrideMimeType)428 CALLBACK_FUNC_DECL(XMLHttpRequestOverrideMimeType)
429 {
430     INC_STATS("DOM.XMLHttpRequest.overrideMimeType()");
431     if (args.Length() < 1)
432         return throwError("Not enough arguments", V8Proxy::SyntaxError);
433 
434     XMLHttpRequest* xmlHttpRequest = V8DOMWrapper::convertToNativeObject<XMLHttpRequest>(V8ClassIndex::XMLHTTPREQUEST, args.Holder());
435     String value = toWebCoreString(args[0]);
436     xmlHttpRequest->overrideMimeType(value);
437     return v8::Undefined();
438 }
439 
CALLBACK_FUNC_DECL(XMLHttpRequestDispatchEvent)440 CALLBACK_FUNC_DECL(XMLHttpRequestDispatchEvent)
441 {
442     INC_STATS("DOM.XMLHttpRequest.dispatchEvent()");
443     return v8::Undefined();
444 }
445 
446 } // namespace WebCore
447