5d3a5282551e9e7e4ee6bbd6ef96b2228c655e54
[WebKit-https.git] / WebCore / bindings / js / JSXMLHttpRequestCustom.cpp
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 Computer, 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 "JSXMLHttpRequest.h"
31
32 #include "DOMWindow.h"
33 #include "Document.h"
34 #include "Event.h"
35 #include "File.h"
36 #include "Frame.h"
37 #include "FrameLoader.h"
38 #include "HTMLDocument.h"
39 #include "JSDOMWindowCustom.h"
40 #include "JSDocument.h"
41 #include "JSEvent.h"
42 #include "JSEventListener.h"
43 #include "JSFile.h"
44 #include "XMLHttpRequest.h"
45 #include <kjs/Error.h>
46
47 using namespace KJS;
48
49 namespace WebCore {
50
51 void JSXMLHttpRequest::mark()
52 {
53     Base::mark();
54
55     if (JSUnprotectedEventListener* onReadyStateChangeListener = static_cast<JSUnprotectedEventListener*>(m_impl->onReadyStateChangeListener()))
56         onReadyStateChangeListener->mark();
57
58     if (JSUnprotectedEventListener* onAbortListener = static_cast<JSUnprotectedEventListener*>(m_impl->onAbortListener()))
59         onAbortListener->mark();
60
61     if (JSUnprotectedEventListener* onErrorListener = static_cast<JSUnprotectedEventListener*>(m_impl->onErrorListener()))
62         onErrorListener->mark();
63
64     if (JSUnprotectedEventListener* onLoadListener = static_cast<JSUnprotectedEventListener*>(m_impl->onLoadListener()))
65         onLoadListener->mark();
66
67     if (JSUnprotectedEventListener* onLoadStartListener = static_cast<JSUnprotectedEventListener*>(m_impl->onLoadStartListener()))
68         onLoadStartListener->mark();
69     
70     if (JSUnprotectedEventListener* onProgressListener = static_cast<JSUnprotectedEventListener*>(m_impl->onProgressListener()))
71         onProgressListener->mark();
72     
73     typedef XMLHttpRequest::EventListenersMap EventListenersMap;
74     typedef XMLHttpRequest::ListenerVector ListenerVector;
75     EventListenersMap& eventListeners = m_impl->eventListeners();
76     for (EventListenersMap::iterator mapIter = eventListeners.begin(); mapIter != eventListeners.end(); ++mapIter) {
77         for (ListenerVector::iterator vecIter = mapIter->second.begin(); vecIter != mapIter->second.end(); ++vecIter) {
78             JSUnprotectedEventListener* listener = static_cast<JSUnprotectedEventListener*>(vecIter->get());
79             listener->mark();
80         }
81     }
82 }
83
84 JSValue* JSXMLHttpRequest::onreadystatechange(ExecState*) const
85 {
86     if (JSUnprotectedEventListener* listener = static_cast<JSUnprotectedEventListener*>(impl()->onReadyStateChangeListener())) {
87         if (JSObject* listenerObj = listener->listenerObj())
88             return listenerObj;
89     }
90     return jsNull();
91 }
92
93 void JSXMLHttpRequest::setOnreadystatechange(ExecState* exec, JSValue* value)
94 {
95     if (Document* document = impl()->document()) {
96         if (Frame* frame = document->frame())
97             impl()->setOnReadyStateChangeListener(toJSDOMWindow(frame)->findOrCreateJSUnprotectedEventListener(exec, value, true));
98     }   
99 }
100
101
102 JSValue* JSXMLHttpRequest::onabort(ExecState*) const
103 {
104     if (JSUnprotectedEventListener* listener = static_cast<JSUnprotectedEventListener*>(impl()->onAbortListener())) {
105         if (JSObject* listenerObj = listener->listenerObj())
106             return listenerObj;
107     }
108     return jsNull();
109 }
110
111 void JSXMLHttpRequest::setOnabort(ExecState* exec, JSValue* value)
112 {
113     if (Document* document = impl()->document()) {
114         if (Frame* frame = document->frame())
115             impl()->setOnAbortListener(toJSDOMWindow(frame)->findOrCreateJSUnprotectedEventListener(exec, value, true));
116     }
117 }
118
119 JSValue* JSXMLHttpRequest::onerror(ExecState*) const
120 {
121     if (JSUnprotectedEventListener* listener = static_cast<JSUnprotectedEventListener*>(impl()->onErrorListener())) {
122         if (JSObject* listenerObj = listener->listenerObj())
123             return listenerObj;
124     }
125     return jsNull();
126 }
127
128 void JSXMLHttpRequest::setOnerror(ExecState* exec, JSValue* value)
129 {
130     if (Document* document = impl()->document()) {
131         if (Frame* frame = document->frame())
132             impl()->setOnErrorListener(toJSDOMWindow(frame)->findOrCreateJSUnprotectedEventListener(exec, value, true));
133     }
134 }
135
136 JSValue* JSXMLHttpRequest::onload(ExecState*) const
137 {
138     if (JSUnprotectedEventListener* listener = static_cast<JSUnprotectedEventListener*>(impl()->onLoadListener())) {
139         if (JSObject* listenerObj = listener->listenerObj())
140             return listenerObj;
141     }
142     return jsNull();
143 }
144
145 void JSXMLHttpRequest::setOnload(ExecState* exec, JSValue* value)
146 {
147     if (Document* document = impl()->document()) {
148         if (Frame* frame = document->frame())
149             impl()->setOnLoadListener(toJSDOMWindow(frame)->findOrCreateJSUnprotectedEventListener(exec, value, true));
150     }
151 }
152
153 JSValue* JSXMLHttpRequest::onloadstart(ExecState*) const
154 {
155     if (JSUnprotectedEventListener* listener = static_cast<JSUnprotectedEventListener*>(impl()->onLoadStartListener())) {
156         if (JSObject* listenerObj = listener->listenerObj())
157             return listenerObj;
158     }
159     return jsNull();
160 }
161
162 void JSXMLHttpRequest::setOnloadstart(ExecState* exec, JSValue* value)
163 {
164     if (Document* document = impl()->document()) {
165         if (Frame* frame = document->frame())
166             impl()->setOnLoadStartListener(toJSDOMWindow(frame)->findOrCreateJSUnprotectedEventListener(exec, value, true));
167     }
168 }
169
170 JSValue* JSXMLHttpRequest::onprogress(ExecState*) const
171 {
172     if (JSUnprotectedEventListener* listener = static_cast<JSUnprotectedEventListener*>(impl()->onProgressListener())) {
173         if (JSObject* listenerObj = listener->listenerObj())
174             return listenerObj;
175     }
176     return jsNull();
177 }
178
179 void JSXMLHttpRequest::setOnprogress(ExecState* exec, JSValue* value)
180 {
181     if (Document* document = impl()->document()) {
182         if (Frame* frame = document->frame())
183             impl()->setOnProgressListener(toJSDOMWindow(frame)->findOrCreateJSUnprotectedEventListener(exec, value, true));
184     }
185 }
186
187 // Custom functions
188 JSValue* JSXMLHttpRequest::open(ExecState* exec, const ArgList& args)
189 {
190     if (args.size() < 2)
191         return throwError(exec, SyntaxError, "Not enough arguments");
192
193     Frame* frame = asJSDOMWindow(exec->dynamicGlobalObject())->impl()->frame();
194     if (!frame)
195         return jsUndefined();
196     const KURL& url = frame->loader()->completeURL(args[1]->toString(exec));
197
198     ExceptionCode ec = 0;
199
200     String method = args[0]->toString(exec);
201     bool async = true;
202     if (args.size() >= 3)
203         async = args[2]->toBoolean(exec);
204
205     if (args.size() >= 4 && !args[3]->isUndefined()) {
206         String user = valueToStringWithNullCheck(exec, args[3]);
207
208         if (args.size() >= 5 && !args[4]->isUndefined()) {
209             String password = valueToStringWithNullCheck(exec, args[4]);
210             impl()->open(method, url, async, user, password, ec);
211         } else
212             impl()->open(method, url, async, user, ec);
213     } else
214         impl()->open(method, url, async, ec);
215
216     setDOMException(exec, ec);
217     return jsUndefined();
218 }
219
220 JSValue* JSXMLHttpRequest::setRequestHeader(ExecState* exec, const ArgList& args)
221 {
222     if (args.size() < 2)
223         return throwError(exec, SyntaxError, "Not enough arguments");
224
225     ExceptionCode ec = 0;
226     impl()->setRequestHeader(args[0]->toString(exec), args[1]->toString(exec), ec);
227     setDOMException(exec, ec);
228     return jsUndefined();
229 }
230
231 JSValue* JSXMLHttpRequest::send(ExecState* exec, const ArgList& args)
232 {
233     ExceptionCode ec = 0;
234     if (args.isEmpty())
235         impl()->send(ec);
236     else {
237         JSValue* val = args[0];
238         if (val->isUndefinedOrNull())
239             impl()->send(ec);
240         else if (val->isObject(&JSDocument::s_info))
241             impl()->send(toDocument(val), ec);
242         else if (val->isObject(&JSFile::s_info))
243             impl()->send(toFile(val), ec);
244         else
245             impl()->send(val->toString(exec), ec);
246     }
247
248     setDOMException(exec, ec);
249     return jsUndefined();
250 }
251
252 JSValue* JSXMLHttpRequest::getResponseHeader(ExecState* exec, const ArgList& args)
253 {
254     if (args.size() < 1)
255         return throwError(exec, SyntaxError, "Not enough arguments");
256
257     ExceptionCode ec = 0;
258     JSValue* header = jsStringOrNull(exec, impl()->getResponseHeader(args[0]->toString(exec), ec));
259     setDOMException(exec, ec);
260     return header;
261 }
262
263 JSValue* JSXMLHttpRequest::overrideMimeType(ExecState* exec, const ArgList& args)
264 {
265     if (args.size() < 1)
266         return throwError(exec, SyntaxError, "Not enough arguments");
267
268     impl()->overrideMimeType(args[0]->toString(exec));
269     return jsUndefined();
270 }
271
272 JSValue* JSXMLHttpRequest::addEventListener(ExecState* exec, const ArgList& args)
273 {
274     Document* document = impl()->document();
275     if (!document)
276         return jsUndefined();
277     Frame* frame = document->frame();
278     if (!frame)
279         return jsUndefined();
280     RefPtr<JSUnprotectedEventListener> listener = toJSDOMWindow(frame)->findOrCreateJSUnprotectedEventListener(exec, args[1], true);
281     if (!listener)
282         return jsUndefined();
283     impl()->addEventListener(args[0]->toString(exec), listener.release(), args[2]->toBoolean(exec));
284     return jsUndefined();
285 }
286
287 JSValue* JSXMLHttpRequest::removeEventListener(ExecState* exec, const ArgList& args)
288 {
289     Document* document = impl()->document();
290     if (!document)
291         return jsUndefined();
292     Frame* frame = document->frame();
293     if (!frame)
294         return jsUndefined();
295     JSUnprotectedEventListener* listener = toJSDOMWindow(frame)->findJSUnprotectedEventListener(exec, args[1], true);
296     if (!listener)
297         return jsUndefined();
298     impl()->removeEventListener(args[0]->toString(exec), listener, args[2]->toBoolean(exec));
299     return jsUndefined();
300 }
301
302 JSValue* JSXMLHttpRequest::dispatchEvent(ExecState* exec, const ArgList& args)
303 {
304     ExceptionCode ec = 0;
305     bool result = impl()->dispatchEvent(toEvent(args[0]), ec);
306     setDOMException(exec, ec);
307     return jsBoolean(result);    
308 }
309
310 } // namespace WebCore