summaryrefslogtreecommitdiffstats
path: root/khtml/ecma/xmlhttprequest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'khtml/ecma/xmlhttprequest.cpp')
-rw-r--r--khtml/ecma/xmlhttprequest.cpp810
1 files changed, 810 insertions, 0 deletions
diff --git a/khtml/ecma/xmlhttprequest.cpp b/khtml/ecma/xmlhttprequest.cpp
new file mode 100644
index 000000000..de77f3d7e
--- /dev/null
+++ b/khtml/ecma/xmlhttprequest.cpp
@@ -0,0 +1,810 @@
+// -*- c-basic-offset: 2 -*-
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 2003 Apple Computer, Inc.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "xmlhttprequest.h"
+#include "xmlhttprequest.lut.h"
+#include "kjs_window.h"
+#include "kjs_events.h"
+
+#include "dom/dom_doc.h"
+#include "dom/dom_exception.h"
+#include "dom/dom_string.h"
+#include "misc/loader.h"
+#include "html/html_documentimpl.h"
+#include "xml/dom2_eventsimpl.h"
+
+#include "khtml_part.h"
+#include "khtmlview.h"
+
+#include <kio/scheduler.h>
+#include <kio/job.h>
+#include <qobject.h>
+#include <kdebug.h>
+
+#ifdef APPLE_CHANGES
+#include "KWQLoader.h"
+#else
+#include <kio/netaccess.h>
+using KIO::NetAccess;
+#endif
+
+#define BANNED_HTTP_HEADERS "authorization,proxy-authorization,"\
+ "content-length,host,connect,copy,move,"\
+ "delete,head,trace,put,propfind,proppatch,"\
+ "mkcol,lock,unlock,options,via,"\
+ "accept-charset,accept-encoding,expect,date,"\
+ "keep-alive,te,trailer,"\
+ "transfer-encoding,upgrade"
+
+using khtml::Decoder;
+
+namespace KJS {
+
+////////////////////// XMLHttpRequest Object ////////////////////////
+
+/* Source for XMLHttpRequestProtoTable.
+@begin XMLHttpRequestProtoTable 7
+ abort XMLHttpRequest::Abort DontDelete|Function 0
+ getAllResponseHeaders XMLHttpRequest::GetAllResponseHeaders DontDelete|Function 0
+ getResponseHeader XMLHttpRequest::GetResponseHeader DontDelete|Function 1
+ open XMLHttpRequest::Open DontDelete|Function 5
+ overrideMimeType XMLHttpRequest::OverrideMIMEType DontDelete|Function 1
+ send XMLHttpRequest::Send DontDelete|Function 1
+ setRequestHeader XMLHttpRequest::SetRequestHeader DontDelete|Function 2
+@end
+*/
+KJS_DEFINE_PROTOTYPE(XMLHttpRequestProto)
+IMPLEMENT_PROTOFUNC_DOM(XMLHttpRequestProtoFunc)
+KJS_IMPLEMENT_PROTOTYPE("XMLHttpRequest", XMLHttpRequestProto,XMLHttpRequestProtoFunc)
+
+
+XMLHttpRequestQObject::XMLHttpRequestQObject(XMLHttpRequest *_jsObject)
+{
+ jsObject = _jsObject;
+}
+
+#ifdef APPLE_CHANGES
+void XMLHttpRequestQObject::slotData( KIO::Job* job, const char *data, int size )
+{
+ jsObject->slotData(job, data, size);
+}
+#else
+void XMLHttpRequestQObject::slotData( KIO::Job* job, const QByteArray &data )
+{
+ jsObject->slotData(job, data);
+}
+#endif
+
+void XMLHttpRequestQObject::slotFinished( KIO::Job* job )
+{
+ jsObject->slotFinished(job);
+}
+
+void XMLHttpRequestQObject::slotRedirection( KIO::Job* job, const KURL& url)
+{
+ jsObject->slotRedirection( job, url );
+}
+
+XMLHttpRequestConstructorImp::XMLHttpRequestConstructorImp(ExecState *, const DOM::Document &d)
+ : ObjectImp(), doc(d)
+{
+}
+
+bool XMLHttpRequestConstructorImp::implementsConstruct() const
+{
+ return true;
+}
+
+Object XMLHttpRequestConstructorImp::construct(ExecState *exec, const List &)
+{
+ return Object(new XMLHttpRequest(exec, doc));
+}
+
+const ClassInfo XMLHttpRequest::info = { "XMLHttpRequest", 0, &XMLHttpRequestTable, 0 };
+
+
+/* Source for XMLHttpRequestTable.
+@begin XMLHttpRequestTable 7
+ readyState XMLHttpRequest::ReadyState DontDelete|ReadOnly
+ responseText XMLHttpRequest::ResponseText DontDelete|ReadOnly
+ responseXML XMLHttpRequest::ResponseXML DontDelete|ReadOnly
+ status XMLHttpRequest::Status DontDelete|ReadOnly
+ statusText XMLHttpRequest::StatusText DontDelete|ReadOnly
+ onreadystatechange XMLHttpRequest::Onreadystatechange DontDelete
+ onload XMLHttpRequest::Onload DontDelete
+@end
+*/
+
+Value XMLHttpRequest::tryGet(ExecState *exec, const Identifier &propertyName) const
+{
+ return DOMObjectLookupGetValue<XMLHttpRequest,DOMObject>(exec, propertyName, &XMLHttpRequestTable, this);
+}
+
+Value XMLHttpRequest::getValueProperty(ExecState *exec, int token) const
+{
+ switch (token) {
+ case ReadyState:
+ return Number(state);
+ case ResponseText:
+ return getString(DOM::DOMString(response));
+ case ResponseXML:
+ if (state != Completed) {
+ return Null();
+ }
+ if (!createdDocument) {
+ QString mimeType = "text/xml";
+
+ if (!m_mimeTypeOverride.isEmpty()) {
+ mimeType = m_mimeTypeOverride;
+ } else {
+ Value header = getResponseHeader("Content-Type");
+ if (header.type() != UndefinedType) {
+ mimeType = QStringList::split(";", header.toString(exec).qstring())[0].stripWhiteSpace();
+ }
+ }
+
+ if (mimeType == "text/xml" || mimeType == "application/xml" || mimeType == "application/xhtml+xml") {
+ responseXML = DOM::Document(doc->implementation()->createDocument());
+
+ DOM::DocumentImpl *docImpl = static_cast<DOM::DocumentImpl *>(responseXML.handle());
+
+ docImpl->open();
+ docImpl->write(response);
+ docImpl->finishParsing();
+ docImpl->close();
+
+ typeIsXML = true;
+ } else {
+ typeIsXML = false;
+ }
+ createdDocument = true;
+ }
+
+ if (!typeIsXML) {
+ return Undefined();
+ }
+
+ return getDOMNode(exec,responseXML);
+ case Status:
+ return getStatus();
+ case StatusText:
+ return getStatusText();
+ case Onreadystatechange:
+ if (onReadyStateChangeListener && onReadyStateChangeListener->listenerObjImp()) {
+ return onReadyStateChangeListener->listenerObj();
+ } else {
+ return Null();
+ }
+ case Onload:
+ if (onLoadListener && onLoadListener->listenerObjImp()) {
+ return onLoadListener->listenerObj();
+ } else {
+ return Null();
+ }
+ default:
+ kdWarning() << "XMLHttpRequest::getValueProperty unhandled token " << token << endl;
+ return Value();
+ }
+}
+
+void XMLHttpRequest::tryPut(ExecState *exec, const Identifier &propertyName, const Value& value, int attr)
+{
+ DOMObjectLookupPut<XMLHttpRequest,DOMObject>(exec, propertyName, value, attr, &XMLHttpRequestTable, this );
+}
+
+void XMLHttpRequest::putValueProperty(ExecState *exec, int token, const Value& value, int /*attr*/)
+{
+ JSEventListener* newListener;
+ switch(token) {
+ case Onreadystatechange:
+ newListener = Window::retrieveActive(exec)->getJSEventListener(value, true);
+ if (newListener != onReadyStateChangeListener) {
+ if (onReadyStateChangeListener) onReadyStateChangeListener->deref();
+ onReadyStateChangeListener = newListener;
+ if (onReadyStateChangeListener) onReadyStateChangeListener->ref();
+ }
+ break;
+ case Onload:
+ newListener = Window::retrieveActive(exec)->getJSEventListener(value, true);
+ if (newListener != onLoadListener) {
+ if (onLoadListener) onLoadListener->deref();
+ onLoadListener = newListener;
+ if (onLoadListener) onLoadListener->ref();
+ }
+ break;
+ default:
+ kdWarning() << "XMLHttpRequest::putValue unhandled token " << token << endl;
+ }
+}
+
+XMLHttpRequest::XMLHttpRequest(ExecState *exec, const DOM::Document &d)
+ : DOMObject(XMLHttpRequestProto::self(exec)),
+ qObject(new XMLHttpRequestQObject(this)),
+ doc(static_cast<DOM::DocumentImpl*>(d.handle())),
+ async(true),
+ contentType(QString::null),
+ job(0),
+ state(Uninitialized),
+ onReadyStateChangeListener(0),
+ onLoadListener(0),
+ decoder(0),
+ createdDocument(false),
+ aborted(false)
+{
+}
+
+XMLHttpRequest::~XMLHttpRequest()
+{
+ if (onReadyStateChangeListener)
+ onReadyStateChangeListener->deref();
+ if (onLoadListener)
+ onLoadListener->deref();
+ delete qObject;
+ qObject = 0;
+ delete decoder;
+ decoder = 0;
+}
+
+void XMLHttpRequest::changeState(XMLHttpRequestState newState)
+{
+ if (state != newState) {
+ state = newState;
+
+ ref();
+
+ if (onReadyStateChangeListener != 0 && doc->view() && doc->view()->part()) {
+ DOM::Event ev = doc->view()->part()->document().createEvent("HTMLEvents");
+ ev.initEvent("readystatechange", true, true);
+ onReadyStateChangeListener->handleEvent(ev);
+ }
+
+ if (state == Completed && onLoadListener != 0 && doc->view() && doc->view()->part()) {
+ DOM::Event ev = doc->view()->part()->document().createEvent("HTMLEvents");
+ ev.initEvent("load", true, true);
+ onLoadListener->handleEvent(ev);
+ }
+
+ deref();
+ }
+}
+
+bool XMLHttpRequest::urlMatchesDocumentDomain(const KURL& _url) const
+{
+ // No need to do work if _url is not valid...
+ if (!_url.isValid())
+ return false;
+
+ KURL documentURL(doc->URL());
+
+ // a local file can load anything
+ if (documentURL.protocol().lower() == "file") {
+ return true;
+ }
+
+ // but a remote document can only load from the same port on the server
+ if (documentURL.protocol().lower() == _url.protocol().lower() &&
+ documentURL.host().lower() == _url.host().lower() &&
+ documentURL.port() == _url.port()) {
+ return true;
+ }
+
+ return false;
+}
+
+void XMLHttpRequest::open(const QString& _method, const KURL& _url, bool _async)
+{
+ abort();
+ aborted = false;
+
+ // clear stuff from possible previous load
+ requestHeaders.clear();
+ responseHeaders = QString();
+ response = QString();
+ createdDocument = false;
+ responseXML = DOM::Document();
+
+ changeState(Uninitialized);
+
+ if (aborted) {
+ return;
+ }
+
+ if (!urlMatchesDocumentDomain(_url)) {
+ return;
+ }
+
+
+ method = _method.lower();
+ url = _url;
+ async = _async;
+
+ changeState(Loading);
+}
+
+void XMLHttpRequest::send(const QString& _body)
+{
+ aborted = false;
+
+ if (method == "post") {
+ QString protocol = url.protocol().lower();
+
+ // Abondon the request when the protocol is other than "http",
+ // instead of blindly changing it to a "get" request.
+ if (!protocol.startsWith("http") && !protocol.startsWith("webdav"))
+ {
+ abort();
+ return;
+ }
+
+ // FIXME: determine post encoding correctly by looking in headers
+ // for charset.
+ QByteArray buf;
+ QCString str = _body.utf8();
+ buf.duplicate(str.data(), str.size() - 1);
+
+ job = KIO::http_post( url, buf, false );
+ if(contentType.isNull())
+ job->addMetaData( "content-type", "Content-type: text/plain" );
+ else
+ job->addMetaData( "content-type", contentType );
+ }
+ else {
+ job = KIO::get( url, false, false );
+ }
+
+ if (!requestHeaders.isEmpty()) {
+ QString rh;
+ QMap<QString, QString>::ConstIterator begin = requestHeaders.begin();
+ QMap<QString, QString>::ConstIterator end = requestHeaders.end();
+ for (QMap<QString, QString>::ConstIterator i = begin; i != end; ++i) {
+ QString key = i.key();
+ QString value = i.data();
+ if (key == "accept") {
+ // The HTTP KIO slave supports an override this way
+ job->addMetaData("accept", value);
+ } else {
+ if (i != begin)
+ rh += "\r\n";
+ rh += key + ": " + value;
+ }
+ }
+
+ job->addMetaData("customHTTPHeader", rh);
+ }
+
+ job->addMetaData("PropagateHttpHeader", "true");
+
+ // Set the default referrer if one is not already supplied
+ // through setRequestHeader. NOTE: the user can still disable
+ // this feature at the protocol level (kio_http).
+ // ### does find() ever succeed? the headers are stored in lower case!
+ if (requestHeaders.find("Referer") == requestHeaders.end()) {
+ KURL documentURL(doc->URL());
+ documentURL.setPass(QString::null);
+ documentURL.setUser(QString::null);
+ job->addMetaData("referrer", documentURL.url());
+ // kdDebug() << "Adding referrer: " << documentURL << endl;
+ }
+
+ if (!async) {
+ QByteArray data;
+ KURL finalURL;
+ QString headers;
+
+#ifdef APPLE_CHANGES
+ data = KWQServeSynchronousRequest(khtml::Cache::loader(), doc->docLoader(), job, finalURL, headers);
+#else
+ QMap<QString, QString> metaData;
+ if ( NetAccess::synchronousRun( job, 0, &data, &finalURL, &metaData ) ) {
+ headers = metaData[ "HTTP-Headers" ];
+ }
+#endif
+ job = 0;
+ processSyncLoadResults(data, finalURL, headers);
+ return;
+ }
+
+ qObject->connect( job, SIGNAL( result( KIO::Job* ) ),
+ SLOT( slotFinished( KIO::Job* ) ) );
+#ifdef APPLE_CHANGES
+ qObject->connect( job, SIGNAL( data( KIO::Job*, const char*, int ) ),
+ SLOT( slotData( KIO::Job*, const char*, int ) ) );
+#else
+ qObject->connect( job, SIGNAL( data( KIO::Job*, const QByteArray& ) ),
+ SLOT( slotData( KIO::Job*, const QByteArray& ) ) );
+#endif
+ qObject->connect( job, SIGNAL(redirection(KIO::Job*, const KURL& ) ),
+ SLOT( slotRedirection(KIO::Job*, const KURL&) ) );
+
+#ifdef APPLE_CHANGES
+ KWQServeRequest(khtml::Cache::loader(), doc->docLoader(), job);
+#else
+ KIO::Scheduler::scheduleJob( job );
+#endif
+}
+
+void XMLHttpRequest::abort()
+{
+ if (job) {
+ job->kill();
+ job = 0;
+ }
+ delete decoder;
+ decoder = 0;
+ aborted = true;
+}
+
+void XMLHttpRequest::overrideMIMEType(const QString& override)
+{
+ m_mimeTypeOverride = override;
+}
+
+void XMLHttpRequest::setRequestHeader(const QString& _name, const QString &value)
+{
+ QString name = _name.lower().stripWhiteSpace();
+
+ // Content-type needs to be set seperately from the other headers
+ if(name == "content-type") {
+ contentType = "Content-type: " + value;
+ return;
+ }
+
+ // Sanitize the referrer header to protect against spoofing...
+ if(name == "referer") {
+ KURL referrerURL(value);
+ if (urlMatchesDocumentDomain(referrerURL))
+ requestHeaders[name] = referrerURL.url();
+ return;
+ }
+
+ // Sanitize the request headers below and handle them as if they are
+ // calls to open. Otherwise, we will end up ignoring them all together!
+ // TODO: Do something about "put" which kio_http sort of supports and
+ // the webDAV headers such as PROPFIND etc...
+ if (name == "get" || name == "post") {
+ KURL reqURL (doc->URL(), value.stripWhiteSpace());
+ open(name, reqURL, async);
+ return;
+ }
+
+ // Reject all banned headers. See BANNED_HTTP_HEADERS above.
+ // kdDebug() << "Banned HTTP Headers: " << BANNED_HTTP_HEADERS << endl;
+ QStringList bannedHeaders = QStringList::split(',',
+ QString::fromLatin1(BANNED_HTTP_HEADERS));
+
+ if (bannedHeaders.contains(name))
+ return; // Denied
+
+ requestHeaders[name] = value.stripWhiteSpace();
+}
+
+Value XMLHttpRequest::getAllResponseHeaders() const
+{
+ if (responseHeaders.isEmpty()) {
+ return Undefined();
+ }
+
+ int endOfLine = responseHeaders.find("\n");
+
+ if (endOfLine == -1) {
+ return Undefined();
+ }
+
+ return String(responseHeaders.mid(endOfLine + 1) + "\n");
+}
+
+Value XMLHttpRequest::getResponseHeader(const QString& name) const
+{
+ if (responseHeaders.isEmpty()) {
+ return Undefined();
+ }
+
+ QRegExp headerLinePattern(name + ":", false);
+
+ int matchLength;
+ int headerLinePos = headerLinePattern.search(responseHeaders, 0);
+ matchLength = headerLinePattern.matchedLength();
+ while (headerLinePos != -1) {
+ if (headerLinePos == 0 || responseHeaders[headerLinePos-1] == '\n') {
+ break;
+ }
+
+ headerLinePos = headerLinePattern.search(responseHeaders, headerLinePos + 1);
+ matchLength = headerLinePattern.matchedLength();
+ }
+
+
+ if (headerLinePos == -1) {
+ return Undefined();
+ }
+
+ int endOfLine = responseHeaders.find("\n", headerLinePos + matchLength);
+
+ return String(responseHeaders.mid(headerLinePos + matchLength, endOfLine - (headerLinePos + matchLength)).stripWhiteSpace());
+}
+
+static Value httpStatus(const QString& response, bool textStatus = false)
+{
+ if (response.isEmpty()) {
+ return Undefined();
+ }
+
+ int endOfLine = response.find("\n");
+ QString firstLine = (endOfLine == -1) ? response : response.left(endOfLine);
+ int codeStart = firstLine.find(" ");
+ int codeEnd = firstLine.find(" ", codeStart + 1);
+
+ if (codeStart == -1 || codeEnd == -1) {
+ return Undefined();
+ }
+
+ if (textStatus) {
+ QString statusText = firstLine.mid(codeEnd + 1, endOfLine - (codeEnd + 1)).stripWhiteSpace();
+ return String(statusText);
+ }
+
+ QString number = firstLine.mid(codeStart + 1, codeEnd - (codeStart + 1));
+
+ bool ok = false;
+ int code = number.toInt(&ok);
+ if (!ok) {
+ return Undefined();
+ }
+
+ return Number(code);
+}
+
+Value XMLHttpRequest::getStatus() const
+{
+ return httpStatus(responseHeaders);
+}
+
+Value XMLHttpRequest::getStatusText() const
+{
+ return httpStatus(responseHeaders, true);
+}
+
+void XMLHttpRequest::processSyncLoadResults(const QByteArray &data, const KURL &finalURL, const QString &headers)
+{
+ if (!urlMatchesDocumentDomain(finalURL)) {
+ abort();
+ return;
+ }
+
+ responseHeaders = headers;
+ changeState(Loaded);
+ if (aborted) {
+ return;
+ }
+
+#ifdef APPLE_CHANGES
+ const char *bytes = (const char *)data.data();
+ int len = (int)data.size();
+
+ slotData(0, bytes, len);
+#else
+ slotData(0, data);
+#endif
+
+ if (aborted) {
+ return;
+ }
+
+ slotFinished(0);
+}
+
+void XMLHttpRequest::slotFinished(KIO::Job *)
+{
+ if (decoder) {
+ response += decoder->flush();
+ }
+
+ // make sure to forget about the job before emitting completed,
+ // since changeState triggers JS code, which might e.g. call abort.
+ job = 0;
+ changeState(Completed);
+
+ delete decoder;
+ decoder = 0;
+}
+
+void XMLHttpRequest::slotRedirection(KIO::Job*, const KURL& url)
+{
+ if (!urlMatchesDocumentDomain(url)) {
+ abort();
+ }
+}
+
+#ifdef APPLE_CHANGES
+void XMLHttpRequest::slotData( KIO::Job*, const char *data, int len )
+#else
+void XMLHttpRequest::slotData(KIO::Job*, const QByteArray &_data)
+#endif
+{
+ if (state < Loaded ) {
+ responseHeaders = job->queryMetaData("HTTP-Headers");
+
+ // NOTE: Replace a 304 response with a 200! Both IE and Mozilla do this.
+ // Problem first reported through bug# 110272.
+ int codeStart = responseHeaders.find("304");
+ if ( codeStart != -1) {
+ int codeEnd = responseHeaders.find("\n", codeStart+3);
+ if (codeEnd != -1)
+ responseHeaders.replace(codeStart, (codeEnd-codeStart), "200 OK");
+ }
+
+ changeState(Loaded);
+ }
+
+#ifndef APPLE_CHANGES
+ const char *data = (const char *)_data.data();
+ int len = (int)_data.size();
+#endif
+
+ if ( decoder == NULL ) {
+ int pos = responseHeaders.find("content-type:", 0, false);
+
+ if ( pos > -1 ) {
+ pos += 13;
+ int index = responseHeaders.find('\n', pos);
+ QString type = responseHeaders.mid(pos, (index-pos));
+ index = type.find (';');
+ if (index > -1)
+ encoding = type.mid( index+1 ).remove(QRegExp("charset[ ]*=[ ]*", false)).stripWhiteSpace();
+ }
+
+ decoder = new Decoder;
+ if (!encoding.isNull())
+ decoder->setEncoding(encoding.latin1(), Decoder::EncodingFromHTTPHeader);
+ else {
+ // Per section 2 of W3C working draft spec, fall back to "UTF-8".
+ decoder->setEncoding("UTF-8", Decoder::DefaultEncoding);
+ }
+ }
+ if (len == 0)
+ return;
+
+ if (len == -1)
+ len = strlen(data);
+
+ QString decoded = decoder->decode(data, len);
+
+ response += decoded;
+
+ if (!aborted) {
+ changeState(Interactive);
+ }
+}
+
+Value XMLHttpRequestProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
+{
+ if (!thisObj.inherits(&XMLHttpRequest::info)) {
+ Object err = Error::create(exec,TypeError);
+ exec->setException(err);
+ return err;
+ }
+
+ XMLHttpRequest *request = static_cast<XMLHttpRequest *>(thisObj.imp());
+ switch (id) {
+ case XMLHttpRequest::Abort:
+ request->abort();
+ return Undefined();
+ case XMLHttpRequest::GetAllResponseHeaders:
+ if (args.size() != 0) {
+ return Undefined();
+ }
+
+ return request->getAllResponseHeaders();
+ case XMLHttpRequest::GetResponseHeader:
+ if (args.size() != 1) {
+ return Undefined();
+ }
+
+ return request->getResponseHeader(args[0].toString(exec).qstring());
+ case XMLHttpRequest::Open:
+ {
+ if (args.size() < 2 || args.size() > 5) {
+ return Undefined();
+ }
+
+ QString method = args[0].toString(exec).qstring();
+ KHTMLPart *part = ::qt_cast<KHTMLPart *>(Window::retrieveActive(exec)->part());
+ if (!part)
+ return Undefined();
+ KURL url = KURL(part->document().completeURL(args[1].toString(exec).qstring()).string());
+
+ bool async = true;
+ if (args.size() >= 3) {
+ async = args[2].toBoolean(exec);
+ }
+
+ if (args.size() >= 4) {
+ url.setUser(args[3].toString(exec).qstring());
+ }
+
+ if (args.size() >= 5) {
+ url.setPass(args[4].toString(exec).qstring());
+ }
+
+ request->open(method, url, async);
+
+ return Undefined();
+ }
+ case XMLHttpRequest::Send:
+ {
+ if (args.size() > 1) {
+ return Undefined();
+ }
+
+ if (request->state != Loading) {
+ return Undefined();
+ }
+
+ QString body;
+ if (args.size() >= 1) {
+ Object obj = Object::dynamicCast(args[0]);
+ if (obj.isValid() && obj.inherits(&DOMDocument::info)) {
+ DOM::Node docNode = static_cast<KJS::DOMDocument *>(obj.imp())->toNode();
+ DOM::DocumentImpl *doc = static_cast<DOM::DocumentImpl *>(docNode.handle());
+
+ try {
+ body = doc->toString().string();
+ // FIXME: also need to set content type, including encoding!
+
+ } catch(DOM::DOMException& e) {
+ Object err = Error::create(exec, GeneralError, "Exception serializing document");
+ exec->setException(err);
+ }
+ } else {
+ body = args[0].toString(exec).qstring();
+ }
+ }
+
+ request->send(body);
+
+ return Undefined();
+ }
+ case XMLHttpRequest::SetRequestHeader:
+ if (args.size() != 2) {
+ return Undefined();
+ }
+
+ request->setRequestHeader(args[0].toString(exec).qstring(), args[1].toString(exec).qstring());
+
+ return Undefined();
+
+ case XMLHttpRequest::OverrideMIMEType:
+ if (args.size() < 1) {
+ Object err = Error::create(exec, SyntaxError, "Not enough arguments");
+ exec->setException(err);
+ return err;
+ }
+
+ request->overrideMIMEType(args[0].toString(exec).qstring());
+ return Undefined();
+ }
+
+ return Undefined();
+}
+
+} // end namespace
+
+
+#include "xmlhttprequest.moc"