c9edcfa8b4d1c23743782061f727f1c23d5d2c11
[WebKit.git] / Source / WebCore / bindings / js / JSXMLHttpRequestCustom.cpp
1 /*
2  * Copyright (C) 2008, 2009 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 "JSXMLHttpRequest.h"
31
32 #include "Blob.h"
33 #include "DOMFormData.h"
34 #include "DOMWindow.h"
35 #include "Document.h"
36 #include "Event.h"
37 #include "Frame.h"
38 #include "FrameLoader.h"
39 #include "HTMLDocument.h"
40 #include "InspectorInstrumentation.h"
41 #include "JSBlob.h"
42 #include "JSDOMFormData.h"
43 #include "JSDOMWindowCustom.h"
44 #include "JSDocument.h"
45 #include "JSEvent.h"
46 #include "JSEventListener.h"
47 #include "XMLHttpRequest.h"
48 #include <interpreter/StackVisitor.h>
49 #include <runtime/ArrayBuffer.h>
50 #include <runtime/Error.h>
51 #include <runtime/JSArrayBuffer.h>
52 #include <runtime/JSArrayBufferView.h>
53 #include <runtime/JSONObject.h>
54
55 using namespace JSC;
56
57 namespace WebCore {
58
59 void JSXMLHttpRequest::visitAdditionalChildren(SlotVisitor& visitor)
60 {
61     if (XMLHttpRequestUpload* upload = impl().optionalUpload())
62         visitor.addOpaqueRoot(upload);
63
64     if (Document* responseDocument = impl().optionalResponseXML())
65         visitor.addOpaqueRoot(responseDocument);
66
67     if (ArrayBuffer* responseArrayBuffer = impl().optionalResponseArrayBuffer())
68         visitor.addOpaqueRoot(responseArrayBuffer);
69
70     if (Blob* responseBlob = impl().optionalResponseBlob())
71         visitor.addOpaqueRoot(responseBlob);
72
73     if (m_response)
74         visitor.append(&m_response);
75 }
76
77 // Custom functions
78 JSValue JSXMLHttpRequest::open(ExecState* exec)
79 {
80     if (exec->argumentCount() < 2)
81         return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec));
82
83     const URL& url = impl().scriptExecutionContext()->completeURL(exec->uncheckedArgument(1).toString(exec)->value(exec));
84     String method = exec->uncheckedArgument(0).toString(exec)->value(exec);
85
86     ExceptionCode ec = 0;
87     if (exec->argumentCount() >= 3) {
88         bool async = exec->uncheckedArgument(2).toBoolean(exec);
89         if (!exec->argument(3).isUndefined()) {
90             String user = valueToStringWithNullCheck(exec, exec->uncheckedArgument(3));
91
92             if (!exec->argument(4).isUndefined()) {
93                 String password = valueToStringWithNullCheck(exec, exec->uncheckedArgument(4));
94                 impl().open(method, url, async, user, password, ec);
95             } else
96                 impl().open(method, url, async, user, ec);
97         } else
98             impl().open(method, url, async, ec);
99     } else
100         impl().open(method, url, ec);
101
102     setDOMException(exec, ec);
103     return jsUndefined();
104 }
105
106 class SendFunctor {
107 public:
108     SendFunctor()
109         : m_hasSkippedFirstFrame(false)
110         , m_line(0)
111         , m_column(0)
112     {
113     }
114
115     unsigned line() const { return m_line; }
116     unsigned column() const { return m_column; }
117     String url() const { return m_url; }
118
119     StackVisitor::Status operator()(StackVisitor& visitor)
120     {
121         if (!m_hasSkippedFirstFrame) {
122             m_hasSkippedFirstFrame = true;
123             return StackVisitor::Continue;
124         }
125
126         unsigned line = 0;
127         unsigned column = 0;
128         visitor->computeLineAndColumn(line, column);
129         m_line = line;
130         m_column = column;
131         m_url = visitor->sourceURL();
132         return StackVisitor::Done;
133     }
134
135 private:
136     bool m_hasSkippedFirstFrame;
137     unsigned m_line;
138     unsigned m_column;
139     String m_url;
140 };
141
142 JSValue JSXMLHttpRequest::send(ExecState* exec)
143 {
144     InspectorInstrumentation::willSendXMLHttpRequest(impl().scriptExecutionContext(), impl().url());
145
146     ExceptionCode ec = 0;
147     JSValue val = exec->argument(0);
148     if (val.isUndefinedOrNull())
149         impl().send(ec);
150     else if (val.inherits(JSDocument::info()))
151         impl().send(toDocument(val), ec);
152     else if (val.inherits(JSBlob::info()))
153         impl().send(toBlob(val), ec);
154     else if (val.inherits(JSDOMFormData::info()))
155         impl().send(toDOMFormData(val), ec);
156     else if (val.inherits(JSArrayBuffer::info()))
157         impl().send(toArrayBuffer(val), ec);
158     else if (val.inherits(JSArrayBufferView::info())) {
159         RefPtr<ArrayBufferView> view = toArrayBufferView(val);
160         impl().send(view.get(), ec);
161     } else
162         impl().send(val.toString(exec)->value(exec), ec);
163
164     SendFunctor functor;
165     exec->iterate(functor);
166     impl().setLastSendLineAndColumnNumber(functor.line(), functor.column());
167     impl().setLastSendURL(functor.url());
168     setDOMException(exec, ec);
169     return jsUndefined();
170 }
171
172 JSValue JSXMLHttpRequest::responseText(ExecState* exec) const
173 {
174     ExceptionCode ec = 0;
175     String text = impl().responseText(ec);
176     if (ec) {
177         setDOMException(exec, ec);
178         return jsUndefined();
179     }
180     return jsOwnedStringOrNull(exec, text);
181 }
182
183 JSValue JSXMLHttpRequest::response(ExecState* exec) const
184 {
185     // FIXME: Use CachedAttribute for other types than JSON as well.
186     if (m_response && impl().responseCacheIsValid())
187         return m_response.get();
188
189     if (!impl().doneWithoutErrors() && impl().responseTypeCode() > XMLHttpRequest::ResponseTypeText)
190         return jsNull();
191
192     switch (impl().responseTypeCode()) {
193     case XMLHttpRequest::ResponseTypeDefault:
194     case XMLHttpRequest::ResponseTypeText:
195         return responseText(exec);
196
197     case XMLHttpRequest::ResponseTypeJSON:
198         {
199             JSValue value = JSONParse(exec, impl().responseTextIgnoringResponseType());
200             if (!value)
201                 value = jsNull();
202             JSXMLHttpRequest* jsRequest = const_cast<JSXMLHttpRequest*>(this);
203             jsRequest->m_response.set(exec->vm(), jsRequest, value);
204
205             impl().didCacheResponseJSON();
206
207             return value;
208         }
209
210     case XMLHttpRequest::ResponseTypeDocument:
211         {
212             ExceptionCode ec = 0;
213             Document* document = impl().responseXML(ec);
214             if (ec) {
215                 setDOMException(exec, ec);
216                 return jsUndefined();
217             }
218             return toJS(exec, globalObject(), document);
219         }
220
221     case XMLHttpRequest::ResponseTypeBlob:
222         return toJS(exec, globalObject(), impl().responseBlob());
223
224     case XMLHttpRequest::ResponseTypeArrayBuffer:
225         return toJS(exec, globalObject(), impl().responseArrayBuffer());
226     }
227
228     return jsUndefined();
229 }
230
231 } // namespace WebCore