src/declarative/qml/qdeclarativexmlhttprequest.cpp
changeset 30 5dc02b23752f
child 37 758a864f9613
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/declarative/qml/qdeclarativexmlhttprequest.cpp	Tue Jul 06 15:10:48 2010 +0300
@@ -0,0 +1,1665 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "private/qdeclarativexmlhttprequest_p.h"
+
+#include "qdeclarativeengine.h"
+#include "private/qdeclarativeengine_p.h"
+#include "private/qdeclarativerefcount_p.h"
+#include "private/qdeclarativeengine_p.h"
+#include "private/qdeclarativeexpression_p.h"
+#include "qdeclarativeglobal_p.h"
+
+#include <QtCore/qobject.h>
+#include <QtScript/qscriptvalue.h>
+#include <QtScript/qscriptcontext.h>
+#include <QtScript/qscriptengine.h>
+#include <QtNetwork/qnetworkreply.h>
+#include <QtCore/qtextcodec.h>
+#include <QtCore/qxmlstream.h>
+#include <QtCore/qstack.h>
+#include <QtCore/qdebug.h>
+
+// From DOM-Level-3-Core spec
+// http://www.w3.org/TR/DOM-Level-3-Core/core.html
+#define INDEX_SIZE_ERR 1
+#define DOMSTRING_SIZE_ERR 2
+#define HIERARCHY_REQUEST_ERR 3
+#define WRONG_DOCUMENT_ERR 4
+#define INVALID_CHARACTER_ERR 5
+#define NO_DATA_ALLOWED_ERR 6
+#define NO_MODIFICATION_ALLOWED_ERR 7
+#define NOT_FOUND_ERR 8
+#define NOT_SUPPORTED_ERR 9
+#define INUSE_ATTRIBUTE_ERR 10
+#define INVALID_STATE_ERR 11
+#define SYNTAX_ERR 12
+#define INVALID_MODIFICATION_ERR 13
+#define NAMESPACE_ERR 14
+#define INVALID_ACCESS_ERR 15
+#define VALIDATION_ERR 16
+#define TYPE_MISMATCH_ERR 17
+
+#define THROW_DOM(error, desc) \
+{ \
+    QScriptValue errorValue = context->throwError(QLatin1String(desc)); \
+    errorValue.setProperty(QLatin1String("code"), error); \
+    return errorValue; \
+} 
+
+#define THROW_SYNTAX(desc) \
+    return context->throwError(QScriptContext::SyntaxError, QLatin1String(desc));
+#define THROW_REFERENCE(desc) \
+    return context->throwError(QScriptContext::ReferenceError, QLatin1String(desc));
+
+#define D(arg) (arg)->release()
+#define A(arg) (arg)->addref()
+
+QT_BEGIN_NAMESPACE
+
+DEFINE_BOOL_CONFIG_OPTION(xhrDump, QML_XHR_DUMP);
+
+class DocumentImpl;
+class NodeImpl 
+{
+public:
+    NodeImpl() : type(Element), document(0), parent(0) {}
+    virtual ~NodeImpl() { 
+        for (int ii = 0; ii < children.count(); ++ii)
+            delete children.at(ii);
+        for (int ii = 0; ii < attributes.count(); ++ii)
+            delete attributes.at(ii);
+    }
+
+    // These numbers are copied from the Node IDL definition
+    enum Type { 
+        Attr = 2, 
+        CDATA = 4, 
+        Comment = 8, 
+        Document = 9, 
+        DocumentFragment = 11, 
+        DocumentType = 10,
+        Element = 1, 
+        Entity = 6, 
+        EntityReference = 5,
+        Notation = 12, 
+        ProcessingInstruction = 7, 
+        Text = 3
+    };
+    Type type;
+
+    QString namespaceUri;
+    QString name;
+
+    QString data;
+
+    void addref();
+    void release();
+
+    DocumentImpl *document;
+    NodeImpl *parent;
+
+    QList<NodeImpl *> children;
+    QList<NodeImpl *> attributes;
+};
+
+class DocumentImpl : public QDeclarativeRefCount, public NodeImpl
+{
+public:
+    DocumentImpl() : root(0) { type = Document; }
+    virtual ~DocumentImpl() {
+        if (root) delete root;
+    }
+
+    QString version;
+    QString encoding;
+    bool isStandalone;
+
+    NodeImpl *root;
+
+    void addref() { QDeclarativeRefCount::addref(); }
+    void release() { QDeclarativeRefCount::release(); }
+};
+
+class NamedNodeMap
+{
+public:
+    // JS API
+    static QScriptValue length(QScriptContext *context, QScriptEngine *engine);
+
+    // C++ API
+    static QScriptValue prototype(QScriptEngine *);
+    static QScriptValue create(QScriptEngine *, NodeImpl *, QList<NodeImpl *> *);
+
+    NamedNodeMap();
+    NamedNodeMap(const NamedNodeMap &);
+    ~NamedNodeMap();
+    bool isNull();
+
+    NodeImpl *d;
+    QList<NodeImpl *> *list;
+private:
+    NamedNodeMap &operator=(const NamedNodeMap &);
+};
+
+class NamedNodeMapClass : public QScriptClass
+{
+public:
+    NamedNodeMapClass(QScriptEngine *engine) : QScriptClass(engine) {}
+
+    virtual QueryFlags queryProperty(const QScriptValue &object, const QScriptString &name, QueryFlags flags, uint *id);
+    virtual QScriptValue property(const QScriptValue &object, const QScriptString &name, uint id);
+};
+
+class NodeList 
+{
+public:
+    // JS API
+    static QScriptValue length(QScriptContext *context, QScriptEngine *engine);
+
+    // C++ API
+    static QScriptValue prototype(QScriptEngine *);
+    static QScriptValue create(QScriptEngine *, NodeImpl *);
+
+    NodeList();
+    NodeList(const NodeList &);
+    ~NodeList();
+    bool isNull();
+
+    NodeImpl *d;
+private:
+    NodeList &operator=(const NodeList &);
+};
+
+class NodeListClass : public QScriptClass
+{
+public:
+    NodeListClass(QScriptEngine *engine) : QScriptClass(engine) {}
+    virtual QueryFlags queryProperty(const QScriptValue &object, const QScriptString &name, QueryFlags flags, uint *id);
+    virtual QScriptValue property(const QScriptValue &object, const QScriptString &name, uint id);
+};
+
+class Node
+{
+public:
+    // JS API
+    static QScriptValue nodeName(QScriptContext *context, QScriptEngine *engine);
+    static QScriptValue nodeValue(QScriptContext *context, QScriptEngine *engine);
+    static QScriptValue nodeType(QScriptContext *context, QScriptEngine *engine);
+
+    static QScriptValue parentNode(QScriptContext *context, QScriptEngine *engine);
+    static QScriptValue childNodes(QScriptContext *context, QScriptEngine *engine);
+    static QScriptValue firstChild(QScriptContext *context, QScriptEngine *engine);
+    static QScriptValue lastChild(QScriptContext *context, QScriptEngine *engine);
+    static QScriptValue previousSibling(QScriptContext *context, QScriptEngine *engine);
+    static QScriptValue nextSibling(QScriptContext *context, QScriptEngine *engine);
+    static QScriptValue attributes(QScriptContext *context, QScriptEngine *engine);
+
+    //static QScriptValue ownerDocument(QScriptContext *context, QScriptEngine *engine);
+    //static QScriptValue namespaceURI(QScriptContext *context, QScriptEngine *engine);
+    //static QScriptValue prefix(QScriptContext *context, QScriptEngine *engine);
+    //static QScriptValue localName(QScriptContext *context, QScriptEngine *engine);
+    //static QScriptValue baseURI(QScriptContext *context, QScriptEngine *engine);
+    //static QScriptValue textContent(QScriptContext *context, QScriptEngine *engine);
+
+    // C++ API
+    static QScriptValue prototype(QScriptEngine *);
+    static QScriptValue create(QScriptEngine *, NodeImpl *);
+
+    Node();
+    Node(const Node &o);
+    ~Node();
+    bool isNull() const;
+
+    NodeImpl *d;
+
+private:
+    Node &operator=(const Node &);
+};
+
+class Element : public Node
+{
+public:
+    // C++ API
+    static QScriptValue prototype(QScriptEngine *);
+};
+
+class Attr : public Node
+{
+public:
+    // JS API
+    static QScriptValue name(QScriptContext *context, QScriptEngine *engine);
+    static QScriptValue specified(QScriptContext *context, QScriptEngine *engine);
+    static QScriptValue value(QScriptContext *context, QScriptEngine *engine);
+    static QScriptValue ownerElement(QScriptContext *context, QScriptEngine *engine);
+    static QScriptValue schemaTypeInfo(QScriptContext *context, QScriptEngine *engine);
+    static QScriptValue isId(QScriptContext *context, QScriptEngine *engine);
+
+    // C++ API
+    static QScriptValue prototype(QScriptEngine *);
+};
+
+class CharacterData : public Node
+{
+public:
+    // JS API
+    static QScriptValue length(QScriptContext *context, QScriptEngine *engine);
+
+    // C++ API
+    static QScriptValue prototype(QScriptEngine *);
+};
+
+class Text : public CharacterData
+{
+public:
+    // JS API
+    static QScriptValue isElementContentWhitespace(QScriptContext *context, QScriptEngine *engine);
+    static QScriptValue wholeText(QScriptContext *context, QScriptEngine *engine);
+
+    // C++ API
+    static QScriptValue prototype(QScriptEngine *);
+};
+
+class CDATA : public Text
+{
+public:
+    // C++ API
+    static QScriptValue prototype(QScriptEngine *);
+};
+
+class Document : public Node
+{
+public:
+    // JS API
+    static QScriptValue xmlVersion(QScriptContext *context, QScriptEngine *engine);
+    static QScriptValue xmlEncoding(QScriptContext *context, QScriptEngine *engine);
+    static QScriptValue xmlStandalone(QScriptContext *context, QScriptEngine *engine);
+    static QScriptValue documentElement(QScriptContext *context, QScriptEngine *engine);
+
+    // C++ API
+    static QScriptValue prototype(QScriptEngine *);
+    static QScriptValue load(QScriptEngine *engine, const QByteArray &data);
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(Node)
+Q_DECLARE_METATYPE(NodeList)
+Q_DECLARE_METATYPE(NamedNodeMap)
+
+QT_BEGIN_NAMESPACE
+
+void NodeImpl::addref() 
+{
+    A(document);
+}
+
+void NodeImpl::release()
+{
+    D(document);
+}
+
+QScriptValue Node::nodeName(QScriptContext *context, QScriptEngine *engine)
+{
+    Node node = qscriptvalue_cast<Node>(context->thisObject());
+    if (node.isNull()) return engine->undefinedValue();
+
+    switch (node.d->type) {
+    case NodeImpl::Document:
+        return QScriptValue(QLatin1String("#document"));
+    case NodeImpl::CDATA:
+        return QScriptValue(QLatin1String("#cdata-section"));
+    case NodeImpl::Text:
+        return QScriptValue(QLatin1String("#text"));
+    default:
+        return QScriptValue(node.d->name);
+    }
+}
+
+QScriptValue Node::nodeValue(QScriptContext *context, QScriptEngine *engine)
+{
+    Node node = qscriptvalue_cast<Node>(context->thisObject());
+    if (node.isNull()) return engine->undefinedValue();
+
+    if (node.d->type == NodeImpl::Document ||
+        node.d->type == NodeImpl::DocumentFragment ||
+        node.d->type == NodeImpl::DocumentType ||
+        node.d->type == NodeImpl::Element ||
+        node.d->type == NodeImpl::Entity ||
+        node.d->type == NodeImpl::EntityReference ||
+        node.d->type == NodeImpl::Notation)
+        return engine->nullValue();
+
+    return QScriptValue(node.d->data);
+}
+
+QScriptValue Node::nodeType(QScriptContext *context, QScriptEngine *engine)
+{
+    Node node = qscriptvalue_cast<Node>(context->thisObject());
+    if (node.isNull()) return engine->undefinedValue();
+    return QScriptValue(node.d->type);
+}
+
+QScriptValue Node::parentNode(QScriptContext *context, QScriptEngine *engine)
+{
+    Node node = qscriptvalue_cast<Node>(context->thisObject());
+    if (node.isNull()) return engine->undefinedValue();
+
+    if (node.d->parent) return Node::create(engine, node.d->parent);
+    else return engine->nullValue();
+}
+
+QScriptValue Node::childNodes(QScriptContext *context, QScriptEngine *engine)
+{
+    Node node = qscriptvalue_cast<Node>(context->thisObject());
+    if (node.isNull()) return engine->undefinedValue();
+
+    return NodeList::create(engine, node.d);
+}
+
+QScriptValue Node::firstChild(QScriptContext *context, QScriptEngine *engine)
+{
+    Node node = qscriptvalue_cast<Node>(context->thisObject());
+    if (node.isNull()) return engine->undefinedValue();
+
+    if (node.d->children.isEmpty()) return engine->nullValue();
+    else return Node::create(engine, node.d->children.first());
+}
+
+QScriptValue Node::lastChild(QScriptContext *context, QScriptEngine *engine)
+{
+    Node node = qscriptvalue_cast<Node>(context->thisObject());
+    if (node.isNull()) return engine->undefinedValue();
+
+    if (node.d->children.isEmpty()) return engine->nullValue();
+    else return Node::create(engine, node.d->children.last());
+}
+
+QScriptValue Node::previousSibling(QScriptContext *context, QScriptEngine *engine)
+{
+    Node node = qscriptvalue_cast<Node>(context->thisObject());
+    if (node.isNull()) return engine->undefinedValue();
+
+    if (!node.d->parent) return engine->nullValue();
+
+    for (int ii = 0; ii < node.d->parent->children.count(); ++ii) {
+        if (node.d->parent->children.at(ii) == node.d) {
+            if (ii == 0) return engine->nullValue();
+            else return Node::create(engine, node.d->parent->children.at(ii - 1));
+        }
+    }
+
+    return engine->nullValue();
+}
+
+QScriptValue Node::nextSibling(QScriptContext *context, QScriptEngine *engine)
+{
+    Node node = qscriptvalue_cast<Node>(context->thisObject());
+    if (node.isNull()) return engine->undefinedValue();
+
+    if (!node.d->parent) return engine->nullValue();
+
+    for (int ii = 0; ii < node.d->parent->children.count(); ++ii) {
+        if (node.d->parent->children.at(ii) == node.d) {
+            if ((ii + 1) == node.d->parent->children.count()) return engine->nullValue();
+            else return Node::create(engine, node.d->parent->children.at(ii + 1)); 
+        }
+    }
+
+    return engine->nullValue();
+}
+
+QScriptValue Node::attributes(QScriptContext *context, QScriptEngine *engine)
+{
+    Node node = qscriptvalue_cast<Node>(context->thisObject());
+    if (node.isNull()) return engine->undefinedValue();
+
+    if (node.d->type != NodeImpl::Element)
+        return engine->nullValue();
+    else
+        return NamedNodeMap::create(engine, node.d, &node.d->attributes);
+}
+
+QScriptValue Node::prototype(QScriptEngine *engine)
+{
+    QScriptValue proto = engine->newObject();
+
+    proto.setProperty(QLatin1String("nodeName"), engine->newFunction(nodeName), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+    proto.setProperty(QLatin1String("nodeValue"), engine->newFunction(nodeValue), QScriptValue::ReadOnly | QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
+    proto.setProperty(QLatin1String("nodeType"), engine->newFunction(nodeType), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+    proto.setProperty(QLatin1String("parentNode"), engine->newFunction(parentNode), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+    proto.setProperty(QLatin1String("childNodes"), engine->newFunction(childNodes), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+    proto.setProperty(QLatin1String("firstChild"), engine->newFunction(firstChild), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+    proto.setProperty(QLatin1String("lastChild"), engine->newFunction(lastChild), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+    proto.setProperty(QLatin1String("previousSibling"), engine->newFunction(previousSibling), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+    proto.setProperty(QLatin1String("nextSibling"), engine->newFunction(nextSibling), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+    proto.setProperty(QLatin1String("attributes"), engine->newFunction(attributes), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+
+    return proto;
+}
+
+QScriptValue Node::create(QScriptEngine *engine, NodeImpl *data)
+{
+    QScriptValue instance = engine->newObject();
+
+    switch (data->type) {
+    case NodeImpl::Attr:
+        instance.setPrototype(Attr::prototype(engine));
+        break;
+    case NodeImpl::Comment:
+    case NodeImpl::Document:
+    case NodeImpl::DocumentFragment:
+    case NodeImpl::DocumentType:
+    case NodeImpl::Entity:
+    case NodeImpl::EntityReference:
+    case NodeImpl::Notation:
+    case NodeImpl::ProcessingInstruction:
+        return QScriptValue();
+    case NodeImpl::CDATA:
+        instance.setPrototype(CDATA::prototype(engine));
+        break;
+    case NodeImpl::Text:
+        instance.setPrototype(Text::prototype(engine));
+        break;
+    case NodeImpl::Element:
+        instance.setPrototype(Element::prototype(engine));
+        break;
+    }
+
+    Node node;
+    node.d = data;
+    if (data) A(data);
+
+    return engine->newVariant(instance, qVariantFromValue(node));
+}
+
+QScriptValue Element::prototype(QScriptEngine *engine)
+{
+    QScriptValue proto = engine->newObject();
+    proto.setPrototype(Node::prototype(engine));
+
+    proto.setProperty(QLatin1String("tagName"), engine->newFunction(nodeName), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+
+    return proto;
+}
+
+QScriptValue Attr::prototype(QScriptEngine *engine)
+{
+    QScriptValue proto = engine->newObject();
+    proto.setPrototype(Node::prototype(engine));
+
+    proto.setProperty(QLatin1String("name"), engine->newFunction(name), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+    proto.setProperty(QLatin1String("value"), engine->newFunction(value), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+    proto.setProperty(QLatin1String("ownerElement"), engine->newFunction(ownerElement), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+
+    return proto;
+}
+
+QScriptValue Attr::name(QScriptContext *context, QScriptEngine *engine)
+{
+    Node node = qscriptvalue_cast<Node>(context->thisObject());
+    if (node.isNull()) return engine->undefinedValue();
+
+    return QScriptValue(node.d->name);
+}
+
+QScriptValue Attr::value(QScriptContext *context, QScriptEngine *engine)
+{
+    Node node = qscriptvalue_cast<Node>(context->thisObject());
+    if (node.isNull()) return engine->undefinedValue();
+
+    return QScriptValue(node.d->data);
+}
+
+QScriptValue Attr::ownerElement(QScriptContext *context, QScriptEngine *engine)
+{
+    Node node = qscriptvalue_cast<Node>(context->thisObject());
+    if (node.isNull()) return engine->undefinedValue();
+
+    return Node::create(engine, node.d->parent);
+}
+
+QScriptValue CharacterData::length(QScriptContext *context, QScriptEngine *engine)
+{
+    Node node = qscriptvalue_cast<Node>(context->thisObject());
+    if (node.isNull()) return engine->undefinedValue();
+
+    return QScriptValue(node.d->data.length());
+}
+
+QScriptValue CharacterData::prototype(QScriptEngine *engine)
+{
+    QScriptValue proto = engine->newObject();
+    proto.setPrototype(Node::prototype(engine));
+
+    proto.setProperty(QLatin1String("data"), engine->newFunction(nodeValue), QScriptValue::ReadOnly | QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
+    proto.setProperty(QLatin1String("length"), engine->newFunction(length), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+
+    return proto;
+}
+
+QScriptValue Text::isElementContentWhitespace(QScriptContext *context, QScriptEngine *engine)
+{
+    Node node = qscriptvalue_cast<Node>(context->thisObject());
+    if (node.isNull()) return engine->undefinedValue();
+
+    return node.d->data.trimmed().isEmpty();
+}
+
+QScriptValue Text::wholeText(QScriptContext *context, QScriptEngine *engine)
+{
+    Node node = qscriptvalue_cast<Node>(context->thisObject());
+    if (node.isNull()) return engine->undefinedValue();
+
+    return node.d->data;
+}
+
+QScriptValue Text::prototype(QScriptEngine *engine)
+{
+    QScriptValue proto = engine->newObject();
+    proto.setPrototype(CharacterData::prototype(engine));
+
+    proto.setProperty(QLatin1String("isElementContentWhitespace"), engine->newFunction(isElementContentWhitespace), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+    proto.setProperty(QLatin1String("wholeText"), engine->newFunction(wholeText), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+
+    return proto;
+}
+
+QScriptValue CDATA::prototype(QScriptEngine *engine)
+{
+    QScriptValue proto = engine->newObject();
+    proto.setPrototype(Text::prototype(engine));
+    return proto;
+}
+
+QScriptValue Document::prototype(QScriptEngine *engine)
+{
+    QScriptValue proto = engine->newObject();
+    proto.setPrototype(Node::prototype(engine));
+
+    proto.setProperty(QLatin1String("xmlVersion"), engine->newFunction(xmlVersion), QScriptValue::ReadOnly | QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
+    proto.setProperty(QLatin1String("xmlEncoding"), engine->newFunction(xmlEncoding), QScriptValue::ReadOnly | QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
+    proto.setProperty(QLatin1String("xmlStandalone"), engine->newFunction(xmlStandalone), QScriptValue::ReadOnly | QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
+    proto.setProperty(QLatin1String("documentElement"), engine->newFunction(documentElement), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+
+    return proto;
+}
+
+QScriptValue Document::load(QScriptEngine *engine, const QByteArray &data)
+{
+    Q_ASSERT(engine);
+
+    DocumentImpl *document = 0;
+    QStack<NodeImpl *> nodeStack;
+
+    QXmlStreamReader reader(data);
+
+    while (!reader.atEnd()) {
+        switch (reader.readNext()) {
+        case QXmlStreamReader::NoToken:
+            break;
+        case QXmlStreamReader::Invalid:
+            break;
+        case QXmlStreamReader::StartDocument:
+            Q_ASSERT(!document);
+            document = new DocumentImpl;
+            document->document = document;
+            document->version = reader.documentVersion().toString();
+            document->encoding = reader.documentEncoding().toString();
+            document->isStandalone = reader.isStandaloneDocument();
+            break;
+        case QXmlStreamReader::EndDocument:
+            break;
+        case QXmlStreamReader::StartElement: 
+        {
+            Q_ASSERT(document);
+            NodeImpl *node = new NodeImpl;
+            node->document = document;
+            node->namespaceUri = reader.namespaceUri().toString();
+            node->name = reader.name().toString();
+            if (nodeStack.isEmpty()) {
+                document->root = node;
+            } else {
+                node->parent = nodeStack.top();
+                node->parent->children.append(node);
+            }
+            nodeStack.append(node);
+
+            foreach (const QXmlStreamAttribute &a, reader.attributes()) {
+                NodeImpl *attr = new NodeImpl;
+                attr->document = document;
+                attr->type = NodeImpl::Attr;
+                attr->namespaceUri = a.namespaceUri().toString();
+                attr->name = a.name().toString();
+                attr->data = a.value().toString();
+                attr->parent = node;
+                node->attributes.append(attr);
+            }
+        } 
+            break;
+        case QXmlStreamReader::EndElement:
+            nodeStack.pop();
+            break;
+        case QXmlStreamReader::Characters:
+        {
+            NodeImpl *node = new NodeImpl;
+            node->document = document;
+            node->type = reader.isCDATA()?NodeImpl::CDATA:NodeImpl::Text;
+            node->parent = nodeStack.top();
+            node->parent->children.append(node);
+            node->data = reader.text().toString();
+        }
+            break;
+        case QXmlStreamReader::Comment:
+            break;
+        case QXmlStreamReader::DTD:
+            break;
+        case QXmlStreamReader::EntityReference:
+            break;
+        case QXmlStreamReader::ProcessingInstruction:
+            break;
+        }
+    }
+
+    if (!document || reader.hasError()) {
+        if (document) D(document);
+        return engine->nullValue();
+    }
+
+    QScriptValue instance = engine->newObject();
+    instance.setPrototype(Document::prototype(engine));
+    Node documentNode;
+    documentNode.d = document;
+    return engine->newVariant(instance, qVariantFromValue(documentNode));
+}
+
+Node::Node()
+: d(0)
+{
+}
+
+Node::Node(const Node &o)
+: d(o.d)
+{
+    if (d) A(d);
+}
+
+Node::~Node()
+{
+    if (d) D(d);
+}
+
+bool Node::isNull() const
+{
+    return d == 0;
+}
+
+QScriptValue NamedNodeMap::length(QScriptContext *context, QScriptEngine *engine)
+{
+    NamedNodeMap map = qscriptvalue_cast<NamedNodeMap>(context->thisObject().data());
+    if (map.isNull()) return engine->undefinedValue();
+
+    return QScriptValue(map.list->count());
+}
+
+QScriptValue NamedNodeMap::prototype(QScriptEngine *engine)
+{
+    QScriptValue proto = engine->newObject();
+
+    proto.setProperty(QLatin1String("length"), engine->newFunction(length), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+
+    return proto;
+}
+
+QScriptValue NamedNodeMap::create(QScriptEngine *engine, NodeImpl *data, QList<NodeImpl *> *list)
+{
+    QScriptValue instance = engine->newObject();
+    instance.setPrototype(NamedNodeMap::prototype(engine));
+
+    NamedNodeMap map;
+    map.d = data;
+    map.list = list;
+    if (data) A(data);
+
+    instance.setData(engine->newVariant(qVariantFromValue(map)));
+
+    if (!QDeclarativeScriptEngine::get(engine)->namedNodeMapClass)
+        QDeclarativeScriptEngine::get(engine)->namedNodeMapClass= new NamedNodeMapClass(engine);
+
+    instance.setScriptClass(QDeclarativeScriptEngine::get(engine)->namedNodeMapClass);
+
+    return instance;
+}
+
+NamedNodeMap::NamedNodeMap()
+: d(0), list(0)
+{
+}
+
+NamedNodeMap::NamedNodeMap(const NamedNodeMap &o)
+: d(o.d), list(o.list)
+{
+    if (d) A(d);
+}
+
+NamedNodeMap::~NamedNodeMap()
+{
+    if (d) D(d);
+}
+
+bool NamedNodeMap::isNull()
+{
+    return d == 0;
+}
+
+QScriptValue NodeList::length(QScriptContext *context, QScriptEngine *engine)
+{
+    NodeList list = qscriptvalue_cast<NodeList>(context->thisObject().data());
+    if (list.isNull()) return engine->undefinedValue();
+
+    return QScriptValue(list.d->children.count());
+}
+
+QScriptValue NodeList::prototype(QScriptEngine *engine)
+{
+    QScriptValue proto = engine->newObject();
+
+    proto.setProperty(QLatin1String("length"), engine->newFunction(length), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+
+    return proto;
+}
+
+QScriptValue NodeList::create(QScriptEngine *engine, NodeImpl *data)
+{
+    QScriptValue instance = engine->newObject();
+    instance.setPrototype(NodeList::prototype(engine));
+
+    NodeList list;
+    list.d = data;
+    if (data) A(data);
+
+    instance.setData(engine->newVariant(qVariantFromValue(list)));
+
+    if (!QDeclarativeScriptEngine::get(engine)->nodeListClass)
+        QDeclarativeScriptEngine::get(engine)->nodeListClass= new NodeListClass(engine);
+
+    instance.setScriptClass(QDeclarativeScriptEngine::get(engine)->nodeListClass);
+
+    return instance;
+}
+
+NodeList::NodeList()
+: d(0)
+{
+}
+
+NodeList::NodeList(const NodeList &o)
+: d(o.d)
+{
+    if (d) A(d);
+}
+
+NodeList::~NodeList()
+{
+    if (d) D(d);
+}
+
+bool NodeList::isNull()
+{
+    return d == 0;
+}
+
+NamedNodeMapClass::QueryFlags NamedNodeMapClass::queryProperty(const QScriptValue &object, const QScriptString &name, QueryFlags flags, uint *id)
+{
+    if (!(flags & HandlesReadAccess))
+        return 0;
+
+    NamedNodeMap map = qscriptvalue_cast<NamedNodeMap>(object.data());
+    Q_ASSERT(!map.isNull());
+
+    bool ok = false;
+    QString nameString = name.toString();
+    uint index = nameString.toUInt(&ok);
+    if (ok) {
+        if ((uint)map.list->count() <= index)
+            return 0;
+
+        *id = index;
+        return HandlesReadAccess;
+    } else {
+        for (int ii = 0; ii < map.list->count(); ++ii) {
+            if (map.list->at(ii) && map.list->at(ii)->name == nameString) {
+                *id = ii;
+                return HandlesReadAccess;
+            }
+        }
+    }
+
+    return 0;
+}
+
+QScriptValue NamedNodeMapClass::property(const QScriptValue &object, const QScriptString &, uint id)
+{
+    NamedNodeMap map = qscriptvalue_cast<NamedNodeMap>(object.data());
+    return Node::create(engine(), map.list->at(id));
+}
+
+NodeListClass::QueryFlags NodeListClass::queryProperty(const QScriptValue &object, const QScriptString &name, QueryFlags flags, uint *id)
+{
+    if (!(flags & HandlesReadAccess))
+        return 0;
+
+    bool ok = false;
+    uint index = name.toString().toUInt(&ok);
+    if (!ok)
+        return 0;
+
+    NodeList list = qscriptvalue_cast<NodeList>(object.data());
+    if (list.isNull() || (uint)list.d->children.count() <= index)
+        return 0; // ### I think we're meant to raise an exception
+
+    *id = index;
+    return HandlesReadAccess;
+}
+
+QScriptValue NodeListClass::property(const QScriptValue &object, const QScriptString &, uint id)
+{
+    NodeList list = qscriptvalue_cast<NodeList>(object.data());
+    return Node::create(engine(), list.d->children.at(id));
+}
+
+QScriptValue Document::documentElement(QScriptContext *context, QScriptEngine *engine)
+{
+    Node document = qscriptvalue_cast<Node>(context->thisObject());
+    if (document.isNull() || document.d->type != NodeImpl::Document) return engine->undefinedValue();
+
+    return Node::create(engine, static_cast<DocumentImpl *>(document.d)->root);
+}
+
+QScriptValue Document::xmlStandalone(QScriptContext *context, QScriptEngine *engine)
+{
+    Node document = qscriptvalue_cast<Node>(context->thisObject());
+    if (document.isNull() || document.d->type != NodeImpl::Document) return engine->undefinedValue();
+
+    return QScriptValue(static_cast<DocumentImpl *>(document.d)->isStandalone);
+}
+
+QScriptValue Document::xmlVersion(QScriptContext *context, QScriptEngine *engine)
+{
+    Node document = qscriptvalue_cast<Node>(context->thisObject());
+    if (document.isNull() || document.d->type != NodeImpl::Document) return engine->undefinedValue();
+
+    return QScriptValue(static_cast<DocumentImpl *>(document.d)->version);
+}
+
+QScriptValue Document::xmlEncoding(QScriptContext *context, QScriptEngine *engine)
+{
+    Node document = qscriptvalue_cast<Node>(context->thisObject());
+    if (document.isNull() || document.d->type != NodeImpl::Document) return engine->undefinedValue();
+
+    return QScriptValue(static_cast<DocumentImpl *>(document.d)->encoding);
+}
+
+class QDeclarativeXMLHttpRequest : public QObject
+{
+Q_OBJECT
+public:
+    enum State { Unsent = 0, 
+                 Opened = 1, HeadersReceived = 2,
+                 Loading = 3, Done = 4 };
+
+    QDeclarativeXMLHttpRequest(QNetworkAccessManager *manager);
+    virtual ~QDeclarativeXMLHttpRequest();
+
+    bool sendFlag() const;
+    bool errorFlag() const;
+    quint32 readyState() const;
+    int replyStatus() const;
+    QString replyStatusText() const;
+
+    QScriptValue open(QScriptValue *me, const QString &, const QUrl &);
+
+    void addHeader(const QString &, const QString &);
+    QString header(const QString &name);
+    QString headers();
+    QScriptValue send(QScriptValue *me, const QByteArray &);
+    QScriptValue abort(QScriptValue *me);
+
+    QString responseBody() const;
+    const QByteArray & rawResponseBody() const;
+private slots:
+    void downloadProgress(qint64);
+    void error(QNetworkReply::NetworkError);
+    void finished();
+
+private:
+    void requestFromUrl(const QUrl &url);
+
+    State m_state;
+    bool m_errorFlag;
+    bool m_sendFlag;
+    QString m_method;
+    QUrl m_url;
+    QByteArray m_responseEntityBody;
+    QByteArray m_data;
+    int m_redirectCount;
+
+    typedef QPair<QByteArray, QByteArray> HeaderPair;
+    typedef QList<HeaderPair> HeadersList;
+    HeadersList m_headersList;
+    void fillHeadersList();
+
+    QScriptValue m_me; // Set to the data object while a send() is ongoing (to access the callback)
+
+    QScriptValue dispatchCallback(QScriptValue *me);
+    void printError(const QScriptValue&);
+
+    int m_status;
+    QString m_statusText;
+    QNetworkRequest m_request;
+    QDeclarativeGuard<QNetworkReply> m_network;
+    void destroyNetwork();
+
+    QNetworkAccessManager *m_nam;
+    QNetworkAccessManager *networkAccessManager() { return m_nam; }
+};
+
+QDeclarativeXMLHttpRequest::QDeclarativeXMLHttpRequest(QNetworkAccessManager *manager)
+: m_state(Unsent), m_errorFlag(false), m_sendFlag(false),
+  m_redirectCount(0), m_network(0), m_nam(manager)
+{
+}
+
+QDeclarativeXMLHttpRequest::~QDeclarativeXMLHttpRequest()
+{
+    destroyNetwork();
+}
+
+bool QDeclarativeXMLHttpRequest::sendFlag() const
+{
+    return m_sendFlag;
+}
+
+bool QDeclarativeXMLHttpRequest::errorFlag() const
+{
+    return m_errorFlag;
+}
+
+quint32 QDeclarativeXMLHttpRequest::readyState() const
+{
+    return m_state;
+}
+
+int QDeclarativeXMLHttpRequest::replyStatus() const
+{
+    return m_status;
+}
+
+QString QDeclarativeXMLHttpRequest::replyStatusText() const
+{
+    return m_statusText;
+}
+
+QScriptValue QDeclarativeXMLHttpRequest::open(QScriptValue *me, const QString &method, const QUrl &url)
+{
+    destroyNetwork();
+    m_sendFlag = false;
+    m_errorFlag = false;
+    m_responseEntityBody = QByteArray();
+    m_method = method;
+    m_url = url;
+    m_state = Opened;
+    return dispatchCallback(me);
+}
+
+void QDeclarativeXMLHttpRequest::addHeader(const QString &name, const QString &value)
+{
+    QByteArray utfname = name.toUtf8();
+
+    if (m_request.hasRawHeader(utfname)) {
+        m_request.setRawHeader(utfname, m_request.rawHeader(utfname) + ',' + value.toUtf8());
+    } else {
+        m_request.setRawHeader(utfname, value.toUtf8());
+    }
+}
+
+QString QDeclarativeXMLHttpRequest::header(const QString &name)
+{
+    QByteArray utfname = name.toLower().toUtf8();
+
+    foreach (const HeaderPair &header, m_headersList) {
+        if (header.first == utfname)
+            return QString::fromUtf8(header.second);
+    }
+    return QString();
+}
+
+QString QDeclarativeXMLHttpRequest::headers()
+{
+    QString ret;
+
+    foreach (const HeaderPair &header, m_headersList) {
+        if (ret.length())
+            ret.append(QString::fromUtf8("\r\n"));
+        ret.append(QString::fromUtf8(header.first));
+        ret.append(QString::fromUtf8(": "));
+        ret.append(QString::fromUtf8(header.second));
+    }
+    return ret;
+}
+
+void QDeclarativeXMLHttpRequest::fillHeadersList()
+{
+    QList<QByteArray> headerList = m_network->rawHeaderList();
+
+    m_headersList.clear();
+    foreach (const QByteArray &header, headerList) {
+        HeaderPair pair (header.toLower(), m_network->rawHeader(header));
+	if (pair.first == "set-cookie" ||
+	    pair.first == "set-cookie2") 
+	    continue;
+
+        m_headersList << pair;
+    }
+}
+
+void QDeclarativeXMLHttpRequest::requestFromUrl(const QUrl &url)
+{
+    QNetworkRequest request = m_request;
+    request.setUrl(url);
+    if(m_method == QLatin1String("POST") ||
+       m_method == QLatin1String("PUT")) {
+        QVariant var = request.header(QNetworkRequest::ContentTypeHeader);
+        if (var.isValid()) {
+            QString str = var.toString();
+            int charsetIdx = str.indexOf(QLatin1String("charset="));
+            if (charsetIdx == -1) {
+                // No charset - append
+                if (!str.isEmpty()) str.append(QLatin1Char(';'));
+                str.append(QLatin1String("charset=UTF-8"));
+            } else {
+                charsetIdx += 8;
+                int n = 0;
+                int semiColon = str.indexOf(QLatin1Char(';'), charsetIdx);
+                if (semiColon == -1) {
+                    n = str.length() - charsetIdx;
+                } else {
+                    n = semiColon - charsetIdx;
+                }
+
+                str.replace(charsetIdx, n, QLatin1String("UTF-8"));
+            }
+            request.setHeader(QNetworkRequest::ContentTypeHeader, str);
+        } else {
+            request.setHeader(QNetworkRequest::ContentTypeHeader, 
+                              QLatin1String("text/plain;charset=UTF-8"));
+        }
+    }
+
+    if (xhrDump()) {
+        qWarning().nospace() << "XMLHttpRequest: " << qPrintable(m_method) << " " << qPrintable(url.toString());
+        if (!m_data.isEmpty()) {
+            qWarning().nospace() << "                " 
+                                 << qPrintable(QString::fromUtf8(m_data));
+        }
+    }
+
+    if (m_method == QLatin1String("GET"))
+        m_network = networkAccessManager()->get(request);
+    else if (m_method == QLatin1String("HEAD"))
+        m_network = networkAccessManager()->head(request);
+    else if(m_method == QLatin1String("POST"))
+        m_network = networkAccessManager()->post(request, m_data);
+    else if(m_method == QLatin1String("PUT"))
+        m_network = networkAccessManager()->put(request, m_data);
+
+    QObject::connect(m_network, SIGNAL(downloadProgress(qint64,qint64)), 
+                     this, SLOT(downloadProgress(qint64)));
+    QObject::connect(m_network, SIGNAL(error(QNetworkReply::NetworkError)),
+                     this, SLOT(error(QNetworkReply::NetworkError)));
+    QObject::connect(m_network, SIGNAL(finished()),
+                     this, SLOT(finished()));
+}
+
+QScriptValue QDeclarativeXMLHttpRequest::send(QScriptValue *me, const QByteArray &data)
+{
+    m_errorFlag = false;
+    m_sendFlag = true;
+    m_redirectCount = 0;
+    m_data = data;
+    m_me = *me;
+
+    requestFromUrl(m_url);
+
+    return QScriptValue();
+}
+
+QScriptValue QDeclarativeXMLHttpRequest::abort(QScriptValue *me)
+{
+    destroyNetwork();
+    m_responseEntityBody = QByteArray();
+    m_errorFlag = true;
+    m_request = QNetworkRequest();
+
+    if (!(m_state == Unsent || 
+          (m_state == Opened && !m_sendFlag) ||
+          m_state == Done)) {
+
+        m_state = Done;
+        m_sendFlag = false;
+        QScriptValue cbv = dispatchCallback(me);
+        if (cbv.isError()) return cbv;
+    }
+
+    m_state = Unsent;
+    return QScriptValue();
+}
+
+void QDeclarativeXMLHttpRequest::downloadProgress(qint64 bytes)
+{
+    Q_UNUSED(bytes)
+    m_status = 
+        m_network->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
+    m_statusText =
+        QString::fromUtf8(m_network->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toByteArray());
+
+    // ### We assume if this is called the headers are now available
+    if (m_state < HeadersReceived) {
+        m_state = HeadersReceived;
+        fillHeadersList ();
+        QScriptValue cbv = dispatchCallback(&m_me);
+        if (cbv.isError()) printError(cbv);
+    }
+
+    bool wasEmpty = m_responseEntityBody.isEmpty();
+    m_responseEntityBody.append(m_network->readAll());
+    if (wasEmpty && !m_responseEntityBody.isEmpty()) {
+        m_state = Loading;
+        QScriptValue cbv = dispatchCallback(&m_me);
+        if (cbv.isError()) printError(cbv);
+    }
+}
+
+void QDeclarativeXMLHttpRequest::error(QNetworkReply::NetworkError error)
+{
+    Q_UNUSED(error)
+    m_status =
+        m_network->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
+    m_statusText =
+        QString::fromUtf8(m_network->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toByteArray());
+
+    m_responseEntityBody = QByteArray();
+
+    m_request = QNetworkRequest();
+    m_data.clear();
+    destroyNetwork();
+
+    if (error == QNetworkReply::ContentAccessDenied ||
+        error == QNetworkReply::ContentOperationNotPermittedError ||
+        error == QNetworkReply::ContentNotFoundError ||
+        error == QNetworkReply::AuthenticationRequiredError ||
+        error == QNetworkReply::ContentReSendError) {
+        m_state = Loading;
+        QScriptValue cbv = dispatchCallback(&m_me);
+        if (cbv.isError()) printError(cbv);
+    } else {
+        m_errorFlag = true;
+    } 
+
+    m_state = Done;
+    QScriptValue cbv = dispatchCallback(&m_me);
+    if (cbv.isError()) printError(cbv);
+}
+
+#define XMLHTTPREQUEST_MAXIMUM_REDIRECT_RECURSION 15
+void QDeclarativeXMLHttpRequest::finished()
+{
+    m_redirectCount++;
+    if (m_redirectCount < XMLHTTPREQUEST_MAXIMUM_REDIRECT_RECURSION) {
+        QVariant redirect = m_network->attribute(QNetworkRequest::RedirectionTargetAttribute);
+        if (redirect.isValid()) {
+            QUrl url = m_network->url().resolved(redirect.toUrl());
+            destroyNetwork();
+            requestFromUrl(url);
+            return;
+        }
+    }
+
+    m_status =
+        m_network->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
+    m_statusText =
+        QString::fromUtf8(m_network->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toByteArray());
+
+    if (m_state < HeadersReceived) {
+        m_state = HeadersReceived;
+        fillHeadersList ();
+        QScriptValue cbv = dispatchCallback(&m_me);
+        if (cbv.isError()) printError(cbv);
+    }
+    m_responseEntityBody.append(m_network->readAll());
+
+    if (xhrDump()) {
+        qWarning().nospace() << "XMLHttpRequest: RESPONSE " << qPrintable(m_url.toString());
+        if (!m_responseEntityBody.isEmpty()) {
+            qWarning().nospace() << "                " 
+                                 << qPrintable(QString::fromUtf8(m_responseEntityBody));
+        }
+    }
+
+
+    m_data.clear();
+    destroyNetwork();
+    if (m_state < Loading) {
+        m_state = Loading;
+        QScriptValue cbv = dispatchCallback(&m_me);
+        if (cbv.isError()) printError(cbv);
+    }
+    m_state = Done;
+    QScriptValue cbv = dispatchCallback(&m_me);
+    if (cbv.isError()) printError(cbv);
+
+    m_me = QScriptValue();
+}
+
+
+QString QDeclarativeXMLHttpRequest::responseBody() const
+{
+    QXmlStreamReader reader(m_responseEntityBody);
+    reader.readNext();
+    QTextCodec *codec = QTextCodec::codecForName(reader.documentEncoding().toString().toUtf8());
+    if (codec)
+        return codec->toUnicode(m_responseEntityBody);
+
+    return QString::fromUtf8(m_responseEntityBody);
+}
+
+const QByteArray &QDeclarativeXMLHttpRequest::rawResponseBody() const
+{
+    return m_responseEntityBody;
+}
+
+QScriptValue QDeclarativeXMLHttpRequest::dispatchCallback(QScriptValue *me)
+{
+    QScriptValue v = me->property(QLatin1String("callback"));
+    return v.call();
+}
+
+void QDeclarativeXMLHttpRequest::printError(const QScriptValue& sv)
+{
+    QDeclarativeError error;
+    QDeclarativeExpressionPrivate::exceptionToError(sv.engine(), error);
+    QDeclarativeEnginePrivate::warning(QDeclarativeEnginePrivate::get(sv.engine()), error);
+}
+
+void QDeclarativeXMLHttpRequest::destroyNetwork()
+{
+    if (m_network) {
+        m_network->disconnect();
+        m_network->deleteLater();
+        m_network = 0;
+    }
+}
+
+// XMLHttpRequest methods
+static QScriptValue qmlxmlhttprequest_open(QScriptContext *context, QScriptEngine *engine)
+{
+    QScriptValue dataObject = context->thisObject().data();
+    QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(dataObject.toQObject());
+    if (!request) 
+        THROW_REFERENCE("Not an XMLHttpRequest object");
+
+    if (context->argumentCount() < 2 || context->argumentCount() > 5)
+        THROW_DOM(SYNTAX_ERR, "Incorrect argument count");
+
+    // Argument 0 - Method
+    QString method = context->argument(0).toString().toUpper();
+    if (method != QLatin1String("GET") && 
+        method != QLatin1String("PUT") &&
+        method != QLatin1String("HEAD") &&
+        method != QLatin1String("POST"))
+        THROW_DOM(SYNTAX_ERR, "Unsupported HTTP method type");
+
+
+    // Argument 1 - URL
+    QUrl url = QUrl::fromEncoded(context->argument(1).toString().toUtf8());
+
+    if (url.isRelative()) {
+        url = QDeclarativeScriptEngine::get(engine)->resolvedUrl(context,url);
+    }
+
+    // Argument 2 - async (optional)
+    if (context->argumentCount() > 2 && !context->argument(2).toBoolean())
+        THROW_DOM(NOT_SUPPORTED_ERR, "Synchronous XMLHttpRequest calls are not supported");
+
+
+    // Argument 3/4 - user/pass (optional)
+    QString username, password;
+    if (context->argumentCount() > 3)
+        username = context->argument(3).toString();
+    if (context->argumentCount() > 4)
+        password = context->argument(4).toString();
+
+
+    // Clear the fragment (if any)
+    url.setFragment(QString());
+    // Set username/password
+    if (!username.isNull()) url.setUserName(username);
+    if (!password.isNull()) url.setPassword(password);
+
+    return request->open(&dataObject, method, url);
+}
+
+static QScriptValue qmlxmlhttprequest_setRequestHeader(QScriptContext *context, QScriptEngine *engine)
+{
+    QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject());
+    if (!request) 
+        THROW_REFERENCE("Not an XMLHttpRequest object");
+
+    if (context->argumentCount() != 2)
+        THROW_DOM(SYNTAX_ERR, "Incorrect argument count");
+
+
+    if (request->readyState() != QDeclarativeXMLHttpRequest::Opened ||
+        request->sendFlag())
+        THROW_DOM(INVALID_STATE_ERR, "Invalid state");
+
+
+    QString name = context->argument(0).toString();
+    QString value = context->argument(1).toString();
+
+    // ### Check that name and value are well formed
+
+    QString nameUpper = name.toUpper();
+    if (nameUpper == QLatin1String("ACCEPT-CHARSET") ||
+        nameUpper == QLatin1String("ACCEPT-ENCODING") ||
+        nameUpper == QLatin1String("CONNECTION") ||
+        nameUpper == QLatin1String("CONTENT-LENGTH") ||
+        nameUpper == QLatin1String("COOKIE") ||
+        nameUpper == QLatin1String("COOKIE2") ||
+        nameUpper == QLatin1String("CONTENT-TRANSFER-ENCODING") ||
+        nameUpper == QLatin1String("DATE") ||
+        nameUpper == QLatin1String("EXPECT") ||
+        nameUpper == QLatin1String("HOST") ||
+        nameUpper == QLatin1String("KEEP-ALIVE") ||
+        nameUpper == QLatin1String("REFERER") ||
+        nameUpper == QLatin1String("TE") ||
+        nameUpper == QLatin1String("TRAILER") ||
+        nameUpper == QLatin1String("TRANSFER-ENCODING") ||
+        nameUpper == QLatin1String("UPGRADE") ||
+        nameUpper == QLatin1String("USER-AGENT") ||
+        nameUpper == QLatin1String("VIA") ||
+        nameUpper.startsWith(QLatin1String("PROXY-")) ||
+        nameUpper.startsWith(QLatin1String("SEC-"))) 
+        return engine->undefinedValue();
+
+    request->addHeader(nameUpper, value);
+
+    return engine->undefinedValue();
+}
+
+static QScriptValue qmlxmlhttprequest_send(QScriptContext *context, QScriptEngine *)
+{
+    QScriptValue dataObject = context->thisObject().data();
+    QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(dataObject.toQObject());
+    if (!request) 
+        THROW_REFERENCE("Not an XMLHttpRequest object");
+
+    if (request->readyState() != QDeclarativeXMLHttpRequest::Opened)
+        THROW_DOM(INVALID_STATE_ERR, "Invalid state");
+
+    if (request->sendFlag())
+        THROW_DOM(INVALID_STATE_ERR, "Invalid state");
+
+    QByteArray data;
+    if (context->argumentCount() > 0)
+        data = context->argument(0).toString().toUtf8();
+
+    return request->send(&dataObject, data);
+}
+
+static QScriptValue qmlxmlhttprequest_abort(QScriptContext *context, QScriptEngine *)
+{
+    QScriptValue dataObject = context->thisObject().data();
+    QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(dataObject.toQObject());
+    if (!request) 
+        THROW_REFERENCE("Not an XMLHttpRequest object");
+
+    return request->abort(&dataObject);
+}
+
+static QScriptValue qmlxmlhttprequest_getResponseHeader(QScriptContext *context, QScriptEngine *engine)
+{
+    Q_UNUSED(engine)
+    QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject());
+    if (!request) 
+        THROW_REFERENCE("Not an XMLHttpRequest object");
+
+    if (context->argumentCount() != 1)
+        THROW_DOM(SYNTAX_ERR, "Incorrect argument count");
+
+    if (request->readyState() != QDeclarativeXMLHttpRequest::Loading &&
+        request->readyState() != QDeclarativeXMLHttpRequest::Done &&
+        request->readyState() != QDeclarativeXMLHttpRequest::HeadersReceived)
+        THROW_DOM(INVALID_STATE_ERR, "Invalid state");
+
+    QString headerName = context->argument(0).toString();
+
+    return QScriptValue(request->header(headerName));
+}
+
+static QScriptValue qmlxmlhttprequest_getAllResponseHeaders(QScriptContext *context, QScriptEngine *engine)
+{
+    Q_UNUSED(engine)
+    QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject());
+    if (!request) 
+        THROW_REFERENCE("Not an XMLHttpRequest object");
+
+    if (context->argumentCount() != 0)
+        THROW_DOM(SYNTAX_ERR, "Incorrect argument count");
+
+    if (request->readyState() != QDeclarativeXMLHttpRequest::Loading &&
+        request->readyState() != QDeclarativeXMLHttpRequest::Done &&
+        request->readyState() != QDeclarativeXMLHttpRequest::HeadersReceived)
+        THROW_DOM(INVALID_STATE_ERR, "Invalid state");
+
+    return QScriptValue(request->headers());
+}
+
+// XMLHttpRequest properties
+static QScriptValue qmlxmlhttprequest_readyState(QScriptContext *context, QScriptEngine *engine)
+{
+    Q_UNUSED(engine)
+    QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject());
+    if (!request) 
+        THROW_REFERENCE("Not an XMLHttpRequest object");
+
+    return QScriptValue(request->readyState());
+}
+
+static QScriptValue qmlxmlhttprequest_status(QScriptContext *context, QScriptEngine *engine)
+{
+    Q_UNUSED(engine)
+    QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject());
+    if (!request) 
+        THROW_REFERENCE("Not an XMLHttpRequest object");
+
+    if (request->readyState() == QDeclarativeXMLHttpRequest::Unsent ||
+        request->readyState() == QDeclarativeXMLHttpRequest::Opened)
+        THROW_DOM(INVALID_STATE_ERR, "Invalid state");
+
+    if (request->errorFlag())
+        return QScriptValue(0);
+    else
+        return QScriptValue(request->replyStatus());
+}
+
+static QScriptValue qmlxmlhttprequest_statusText(QScriptContext *context, QScriptEngine *engine)
+{
+    Q_UNUSED(engine)
+    QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject());
+    if (!request) 
+        THROW_REFERENCE("Not an XMLHttpRequest object");
+
+    if (request->readyState() == QDeclarativeXMLHttpRequest::Unsent ||
+        request->readyState() == QDeclarativeXMLHttpRequest::Opened)
+        THROW_DOM(INVALID_STATE_ERR, "Invalid state");
+
+    if (request->errorFlag())
+        return QScriptValue(0);
+    else
+        return QScriptValue(request->replyStatusText());
+}
+
+static QScriptValue qmlxmlhttprequest_responseText(QScriptContext *context, QScriptEngine *engine)
+{
+    Q_UNUSED(engine)
+    QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject());
+    if (!request) 
+        THROW_REFERENCE("Not an XMLHttpRequest object");
+
+    if (request->readyState() != QDeclarativeXMLHttpRequest::Loading &&
+        request->readyState() != QDeclarativeXMLHttpRequest::Done)
+        return QScriptValue(QString());
+    else 
+        return QScriptValue(request->responseBody());
+}
+
+static QScriptValue qmlxmlhttprequest_responseXML(QScriptContext *context, QScriptEngine *engine)
+{
+    QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject());
+    if (!request) 
+        THROW_REFERENCE("Not an XMLHttpRequest object");
+
+    if (request->readyState() != QDeclarativeXMLHttpRequest::Loading &&
+        request->readyState() != QDeclarativeXMLHttpRequest::Done)
+        return engine->nullValue();
+    else  
+        return Document::load(engine, request->rawResponseBody());
+}
+
+static QScriptValue qmlxmlhttprequest_onreadystatechange(QScriptContext *context, QScriptEngine *engine)
+{
+    Q_UNUSED(engine);
+    QScriptValue dataObject = context->thisObject().data();
+    QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(dataObject.toQObject());
+    if (!request) 
+        THROW_REFERENCE("Not an XMLHttpRequest object");
+
+    if (context->argumentCount()) {
+        QScriptValue v = context->argument(0);
+        dataObject.setProperty(QLatin1String("callback"), v);
+        return v;
+    } else {
+        return dataObject.property(QLatin1String("callback"));
+    }
+}
+
+// Constructor
+static QScriptValue qmlxmlhttprequest_new(QScriptContext *context, QScriptEngine *engine)
+{
+    if (context->isCalledAsConstructor()) {
+        context->thisObject().setData(engine->newQObject(new QDeclarativeXMLHttpRequest(QDeclarativeScriptEngine::get(engine)->networkAccessManager()), QScriptEngine::ScriptOwnership));
+    }
+    return engine->undefinedValue();
+}
+
+void qt_add_qmlxmlhttprequest(QScriptEngine *engine)
+{
+    QScriptValue prototype = engine->newObject();
+
+    // Methods
+    prototype.setProperty(QLatin1String("open"), engine->newFunction(qmlxmlhttprequest_open, 2));
+    prototype.setProperty(QLatin1String("setRequestHeader"), engine->newFunction(qmlxmlhttprequest_setRequestHeader, 2));
+    prototype.setProperty(QLatin1String("send"), engine->newFunction(qmlxmlhttprequest_send));
+    prototype.setProperty(QLatin1String("abort"), engine->newFunction(qmlxmlhttprequest_abort));
+    prototype.setProperty(QLatin1String("getResponseHeader"), engine->newFunction(qmlxmlhttprequest_getResponseHeader, 1));
+    prototype.setProperty(QLatin1String("getAllResponseHeaders"), engine->newFunction(qmlxmlhttprequest_getAllResponseHeaders));
+
+    // Read-only properties
+    prototype.setProperty(QLatin1String("readyState"), engine->newFunction(qmlxmlhttprequest_readyState), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+    prototype.setProperty(QLatin1String("status"), engine->newFunction(qmlxmlhttprequest_status), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+    prototype.setProperty(QLatin1String("statusText"), engine->newFunction(qmlxmlhttprequest_statusText), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+    prototype.setProperty(QLatin1String("responseText"), engine->newFunction(qmlxmlhttprequest_responseText), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+    prototype.setProperty(QLatin1String("responseXML"), engine->newFunction(qmlxmlhttprequest_responseXML), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+    prototype.setProperty(QLatin1String("onreadystatechange"), engine->newFunction(qmlxmlhttprequest_onreadystatechange), QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
+
+    // State values
+    prototype.setProperty(QLatin1String("UNSENT"), 0, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+    prototype.setProperty(QLatin1String("OPENED"), 1, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+    prototype.setProperty(QLatin1String("HEADERS_RECEIVED"), 2, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+    prototype.setProperty(QLatin1String("LOADING"), 3, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+    prototype.setProperty(QLatin1String("DONE"), 4, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+
+    // Constructor
+    QScriptValue constructor = engine->newFunction(qmlxmlhttprequest_new, prototype);
+    constructor.setProperty(QLatin1String("UNSENT"), 0, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+    constructor.setProperty(QLatin1String("OPENED"), 1, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+    constructor.setProperty(QLatin1String("HEADERS_RECEIVED"), 2, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+    constructor.setProperty(QLatin1String("LOADING"), 3, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+    constructor.setProperty(QLatin1String("DONE"), 4, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+    engine->globalObject().setProperty(QLatin1String("XMLHttpRequest"), constructor);
+
+    // DOM Exception
+    QScriptValue domExceptionPrototype = engine->newObject();
+    domExceptionPrototype.setProperty(QLatin1String("INDEX_SIZE_ERR"), INDEX_SIZE_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+    domExceptionPrototype.setProperty(QLatin1String("DOMSTRING_SIZE_ERR"), DOMSTRING_SIZE_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+    domExceptionPrototype.setProperty(QLatin1String("HIERARCHY_REQUEST_ERR"), HIERARCHY_REQUEST_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+    domExceptionPrototype.setProperty(QLatin1String("WRONG_DOCUMENT_ERR"), WRONG_DOCUMENT_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+    domExceptionPrototype.setProperty(QLatin1String("INVALID_CHARACTER_ERR"), INVALID_CHARACTER_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+    domExceptionPrototype.setProperty(QLatin1String("NO_DATA_ALLOWED_ERR"), NO_DATA_ALLOWED_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+    domExceptionPrototype.setProperty(QLatin1String("NO_MODIFICATION_ALLOWED_ERR"), NO_MODIFICATION_ALLOWED_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+    domExceptionPrototype.setProperty(QLatin1String("NOT_FOUND_ERR"), NOT_FOUND_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+    domExceptionPrototype.setProperty(QLatin1String("NOT_SUPPORTED_ERR"), NOT_SUPPORTED_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+    domExceptionPrototype.setProperty(QLatin1String("INUSE_ATTRIBUTE_ERR"), INUSE_ATTRIBUTE_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+    domExceptionPrototype.setProperty(QLatin1String("INVALID_STATE_ERR"), INVALID_STATE_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+    domExceptionPrototype.setProperty(QLatin1String("SYNTAX_ERR"), SYNTAX_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+    domExceptionPrototype.setProperty(QLatin1String("INVALID_MODIFICATION_ERR"), INVALID_MODIFICATION_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+    domExceptionPrototype.setProperty(QLatin1String("NAMESPACE_ERR"), NAMESPACE_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+    domExceptionPrototype.setProperty(QLatin1String("INVALID_ACCESS_ERR"), INVALID_ACCESS_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+    domExceptionPrototype.setProperty(QLatin1String("VALIDATION_ERR"), VALIDATION_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+    domExceptionPrototype.setProperty(QLatin1String("TYPE_MISMATCH_ERR"), TYPE_MISMATCH_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+
+    engine->globalObject().setProperty(QLatin1String("DOMException"), domExceptionPrototype);
+}
+
+QT_END_NAMESPACE
+
+#include <qdeclarativexmlhttprequest.moc>