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 55using namespace JSC; 56 57namespace WebCore { 58 59void 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 78JSValue 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 106class SendFunctor { 107public: 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 135private: 136 bool m_hasSkippedFirstFrame; 137 unsigned m_line; 138 unsigned m_column; 139 String m_url; 140}; 141 142JSValue 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 172JSValue 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 183JSValue 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 232