/* * This file is part of the KDE libraries * Copyright (C) 2004, 2007 Apple Inc. All rights reserved. * Copyright (C) 2005, 2006 Alexey Proskuryakov * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "JSXMLHttpRequest.h" #include "DOMWindow.h" #include "Event.h" #include "Frame.h" #include "FrameLoader.h" #include "HTMLDocument.h" #include "JSDocument.h" #include "JSEvent.h" #include "XMLHttpRequest.h" #include "kjs_events.h" #include "kjs_window.h" #include "JSXMLHttpRequest.lut.h" namespace KJS { using namespace WebCore; ////////////////////// JSXMLHttpRequest Object //////////////////////// /* Source for JSXMLHttpRequestPrototypeTable. @begin JSXMLHttpRequestPrototypeTable 7 abort JSXMLHttpRequest::Abort DontDelete|Function 0 getAllResponseHeaders JSXMLHttpRequest::GetAllResponseHeaders DontDelete|Function 0 getResponseHeader JSXMLHttpRequest::GetResponseHeader DontDelete|Function 1 open JSXMLHttpRequest::Open DontDelete|Function 5 overrideMimeType JSXMLHttpRequest::OverrideMIMEType DontDelete|Function 1 send JSXMLHttpRequest::Send DontDelete|Function 1 setRequestHeader JSXMLHttpRequest::SetRequestHeader DontDelete|Function 2 # from the EventTarget interface # FIXME: add DOM3 EventTarget methods (addEventListenerNS, removeEventListenerNS). addEventListener JSXMLHttpRequest::AddEventListener DontDelete|Function 3 removeEventListener JSXMLHttpRequest::RemoveEventListener DontDelete|Function 3 dispatchEvent JSXMLHttpRequest::DispatchEvent DontDelete|Function 1 @end */ KJS_DEFINE_PROTOTYPE(JSXMLHttpRequestPrototype) KJS_IMPLEMENT_PROTOTYPE_FUNCTION(JSXMLHttpRequestPrototypeFunction) KJS_IMPLEMENT_PROTOTYPE("JSXMLHttpRequest", JSXMLHttpRequestPrototype, JSXMLHttpRequestPrototypeFunction) JSXMLHttpRequestConstructorImp::JSXMLHttpRequestConstructorImp(ExecState* exec, Document* d) : doc(d) { setPrototype(exec->lexicalInterpreter()->builtinObjectPrototype()); putDirect(exec->propertyNames().prototype, JSXMLHttpRequestPrototype::self(exec), None); } bool JSXMLHttpRequestConstructorImp::implementsConstruct() const { return true; } JSObject* JSXMLHttpRequestConstructorImp::construct(ExecState* exec, const List&) { return new JSXMLHttpRequest(exec, doc.get()); } const ClassInfo JSXMLHttpRequest::info = { "JSXMLHttpRequest", 0, &JSXMLHttpRequestTable, 0 }; /* Source for JSXMLHttpRequestTable. @begin JSXMLHttpRequestTable 7 readyState JSXMLHttpRequest::ReadyState DontDelete|ReadOnly responseText JSXMLHttpRequest::ResponseText DontDelete|ReadOnly responseXML JSXMLHttpRequest::ResponseXML DontDelete|ReadOnly status JSXMLHttpRequest::Status DontDelete|ReadOnly statusText JSXMLHttpRequest::StatusText DontDelete|ReadOnly onreadystatechange JSXMLHttpRequest::Onreadystatechange DontDelete onload JSXMLHttpRequest::Onload DontDelete @end */ bool JSXMLHttpRequest::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) { return getStaticValueSlot(exec, &JSXMLHttpRequestTable, this, propertyName, slot); } JSValue* JSXMLHttpRequest::getValueProperty(ExecState* exec, int token) const { ExceptionCode ec = 0; switch (token) { case ReadyState: return jsNumber(m_impl->getReadyState()); case ResponseText: return jsOwnedStringOrNull(m_impl->getResponseText()); case ResponseXML: if (Document* responseXML = m_impl->getResponseXML()) return toJS(exec, responseXML); return jsNull(); case Status: { JSValue* result = jsNumber(m_impl->getStatus(ec)); setDOMException(exec, ec); return result; } case StatusText: { JSValue* result = jsString(m_impl->getStatusText(ec)); setDOMException(exec, ec); return result; } case Onreadystatechange: if (JSUnprotectedEventListener* listener = static_cast(m_impl->onReadyStateChangeListener())) if (JSObject* listenerObj = listener->listenerObj()) return listenerObj; return jsNull(); case Onload: if (JSUnprotectedEventListener* listener = static_cast(m_impl->onLoadListener())) if (JSObject* listenerObj = listener->listenerObj()) return listenerObj; return jsNull(); default: return 0; } } void JSXMLHttpRequest::put(ExecState* exec, const Identifier& propertyName, JSValue* value, int attr) { lookupPut(exec, propertyName, value, attr, &JSXMLHttpRequestTable, this ); } void JSXMLHttpRequest::putValueProperty(ExecState* exec, int token, JSValue* value, int /*attr*/) { switch (token) { case Onreadystatechange: m_impl->setOnReadyStateChangeListener(Window::retrieveActive(exec)->findOrCreateJSUnprotectedEventListener(value, true)); break; case Onload: m_impl->setOnLoadListener(Window::retrieveActive(exec)->findOrCreateJSUnprotectedEventListener(value, true)); break; } } void JSXMLHttpRequest::mark() { DOMObject::mark(); JSUnprotectedEventListener* onReadyStateChangeListener = static_cast(m_impl->onReadyStateChangeListener()); JSUnprotectedEventListener* onLoadListener = static_cast(m_impl->onLoadListener()); if (onReadyStateChangeListener) onReadyStateChangeListener->mark(); if (onLoadListener) onLoadListener->mark(); typedef XMLHttpRequest::EventListenersMap EventListenersMap; typedef XMLHttpRequest::ListenerVector ListenerVector; EventListenersMap& eventListeners = m_impl->eventListeners(); for (EventListenersMap::iterator mapIter = eventListeners.begin(); mapIter != eventListeners.end(); ++mapIter) { for (ListenerVector::iterator vecIter = mapIter->second.begin(); vecIter != mapIter->second.end(); ++vecIter) { JSUnprotectedEventListener* listener = static_cast(vecIter->get()); listener->mark(); } } } JSXMLHttpRequest::JSXMLHttpRequest(ExecState* exec, Document* d) : m_impl(new XMLHttpRequest(d)) { setPrototype(JSXMLHttpRequestPrototype::self(exec)); ScriptInterpreter::putDOMObject(m_impl.get(), this); } JSXMLHttpRequest::~JSXMLHttpRequest() { m_impl->setOnReadyStateChangeListener(0); m_impl->setOnLoadListener(0); m_impl->eventListeners().clear(); ScriptInterpreter::forgetDOMObject(m_impl.get()); } JSValue* JSXMLHttpRequestPrototypeFunction::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args) { if (!thisObj->inherits(&JSXMLHttpRequest::info)) return throwError(exec, TypeError); JSXMLHttpRequest* request = static_cast(thisObj); ExceptionCode ec = 0; switch (id) { case JSXMLHttpRequest::Abort: request->m_impl->abort(); return jsUndefined(); case JSXMLHttpRequest::GetAllResponseHeaders: return jsStringOrUndefined(request->m_impl->getAllResponseHeaders()); case JSXMLHttpRequest::GetResponseHeader: if (args.size() < 1) return throwError(exec, SyntaxError, "Not enough arguments"); return jsStringOrNull(request->m_impl->getResponseHeader(args[0]->toString(exec))); case JSXMLHttpRequest::Open: { if (args.size() < 2) return throwError(exec, SyntaxError, "Not enough arguments"); String method = args[0]->toString(exec); Frame* frame = Window::retrieveActive(exec)->impl()->frame(); if (!frame) return jsUndefined(); KURL url = frame->loader()->completeURL(DeprecatedString(args[1]->toString(exec))); bool async = true; if (args.size() >= 3) async = args[2]->toBoolean(exec); if (args.size() >= 4 && !args[3]->isUndefined()) { String user = valueToStringWithNullCheck(exec, args[3]); if (args.size() >= 5 && !args[4]->isUndefined()) { String password = valueToStringWithNullCheck(exec, args[4]); request->m_impl->open(method, url, async, user, password, ec); } else request->m_impl->open(method, url, async, user, ec); } else request->m_impl->open(method, url, async, ec); setDOMException(exec, ec); return jsUndefined(); } case JSXMLHttpRequest::Send: { String body; if (args.size() >= 1) { if (args[0]->toObject(exec)->inherits(&JSDocument::info)) { Document* doc = static_cast(static_cast(args[0]->toObject(exec))->impl()); body = doc->toString().deprecatedString(); } else { // converting certain values (like null) to object can set an exception if (exec->hadException()) exec->clearException(); else body = args[0]->toString(exec); } } request->m_impl->send(body, ec); setDOMException(exec, ec); return jsUndefined(); } case JSXMLHttpRequest::SetRequestHeader: if (args.size() < 2) return throwError(exec, SyntaxError, "Not enough arguments"); request->m_impl->setRequestHeader(args[0]->toString(exec), args[1]->toString(exec), ec); setDOMException(exec, ec); return jsUndefined(); case JSXMLHttpRequest::OverrideMIMEType: if (args.size() < 1) return throwError(exec, SyntaxError, "Not enough arguments"); request->m_impl->overrideMIMEType(args[0]->toString(exec)); return jsUndefined(); case JSXMLHttpRequest::AddEventListener: { JSUnprotectedEventListener* listener = Window::retrieveActive(exec)->findOrCreateJSUnprotectedEventListener(args[1], true); if (listener) request->m_impl->addEventListener(args[0]->toString(exec), listener, args[2]->toBoolean(exec)); return jsUndefined(); } case JSXMLHttpRequest::RemoveEventListener: { JSUnprotectedEventListener* listener = Window::retrieveActive(exec)->findJSUnprotectedEventListener(args[1], true); if (listener) request->m_impl->removeEventListener(args[0]->toString(exec), listener, args[2]->toBoolean(exec)); return jsUndefined(); } case JSXMLHttpRequest::DispatchEvent: { bool result = request->m_impl->dispatchEvent(toEvent(args[0]), ec); setDOMException(exec, ec); return jsBoolean(result); } } return jsUndefined(); } } // end namespace