/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtDeclarative module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Digia. For licensing terms and ** conditions see http://qt.digia.com/licensing. For further information ** use the contact form at http://qt.digia.com/contact-us. ** ** 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, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** ** $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 #include #include #include #include #include #include #include #include #include #ifndef QT_NO_XMLSTREAMREADER // 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 children; QList 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 *); NamedNodeMap(); NamedNodeMap(const NamedNodeMap &); ~NamedNodeMap(); bool isNull(); NodeImpl *d; QList *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(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(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(context->thisObject()); if (node.isNull()) return engine->undefinedValue(); return QScriptValue(node.d->type); } QScriptValue Node::parentNode(QScriptContext *context, QScriptEngine *engine) { Node node = qscriptvalue_cast(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(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(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(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(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(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(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, QVariant::fromValue(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(context->thisObject()); if (node.isNull()) return engine->undefinedValue(); return QScriptValue(node.d->name); } QScriptValue Attr::value(QScriptContext *context, QScriptEngine *engine) { Node node = qscriptvalue_cast(context->thisObject()); if (node.isNull()) return engine->undefinedValue(); return QScriptValue(node.d->data); } QScriptValue Attr::ownerElement(QScriptContext *context, QScriptEngine *engine) { Node node = qscriptvalue_cast(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(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(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(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 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, QVariant::fromValue(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(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 *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(QVariant::fromValue(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(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(QVariant::fromValue(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(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(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(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(object.data()); return Node::create(engine(), list.d->children.at(id)); } QScriptValue Document::documentElement(QScriptContext *context, QScriptEngine *engine) { Node document = qscriptvalue_cast(context->thisObject()); if (document.isNull() || document.d->type != NodeImpl::Document) return engine->undefinedValue(); return Node::create(engine, static_cast(document.d)->root); } QScriptValue Document::xmlStandalone(QScriptContext *context, QScriptEngine *engine) { Node document = qscriptvalue_cast(context->thisObject()); if (document.isNull() || document.d->type != NodeImpl::Document) return engine->undefinedValue(); return QScriptValue(static_cast(document.d)->isStandalone); } QScriptValue Document::xmlVersion(QScriptContext *context, QScriptEngine *engine) { Node document = qscriptvalue_cast(context->thisObject()); if (document.isNull() || document.d->type != NodeImpl::Document) return engine->undefinedValue(); return QScriptValue(static_cast(document.d)->version); } QScriptValue Document::xmlEncoding(QScriptContext *context, QScriptEngine *engine) { Node document = qscriptvalue_cast(context->thisObject()); if (document.isNull() || document.d->type != NodeImpl::Document) return engine->undefinedValue(); return QScriptValue(static_cast(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 QByteArray & rawResponseBody() const; bool receivedXml() 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 HeaderPair; typedef QList HeadersList; HeadersList m_headersList; void fillHeadersList(); bool m_gotXml; QByteArray m_mime; QByteArray m_charset; QTextCodec *m_textCodec; #ifndef QT_NO_TEXTCODEC QTextCodec* findTextCodec() const; #endif void readEncoding(); 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 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_gotXml(false), m_textCodec(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(QLatin1String("\r\n")); ret = ret % QString::fromUtf8(header.first) % QLatin1String(": ") % QString::fromUtf8(header.second); } return ret; } void QDeclarativeXMLHttpRequest::fillHeadersList() { QList 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); else if (m_method == QLatin1String("DELETE")) m_network = networkAccessManager()->deleteResource(request); 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()); if (url.scheme().toLower() != QLatin1String("file")) { 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()); readEncoding(); 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(); } void QDeclarativeXMLHttpRequest::readEncoding() { foreach (const HeaderPair &header, m_headersList) { if (header.first == "content-type") { int separatorIdx = header.second.indexOf(';'); if (separatorIdx == -1) { m_mime == header.second; } else { m_mime = header.second.mid(0, separatorIdx); int charsetIdx = header.second.indexOf("charset="); if (charsetIdx != -1) { charsetIdx += 8; separatorIdx = header.second.indexOf(';', charsetIdx); m_charset = header.second.mid(charsetIdx, separatorIdx >= 0 ? separatorIdx : header.second.length()); } } break; } } if (m_mime.isEmpty() || m_mime == "text/xml" || m_mime == "application/xml" || m_mime.endsWith("+xml")) m_gotXml = true; } bool QDeclarativeXMLHttpRequest::receivedXml() const { return m_gotXml; } #ifndef QT_NO_TEXTCODEC QTextCodec* QDeclarativeXMLHttpRequest::findTextCodec() const { QTextCodec *codec = 0; if (!m_charset.isEmpty()) codec = QTextCodec::codecForName(m_charset); if (!codec && m_gotXml) { QXmlStreamReader reader(m_responseEntityBody); reader.readNext(); codec = QTextCodec::codecForName(reader.documentEncoding().toString().toUtf8()); } if (!codec && m_mime == "text/html") codec = QTextCodec::codecForHtml(m_responseEntityBody, 0); if (!codec) codec = QTextCodec::codecForUtfText(m_responseEntityBody, 0); if (!codec) codec = QTextCodec::codecForName("UTF-8"); return codec; } #endif QString QDeclarativeXMLHttpRequest::responseBody() { #ifndef QT_NO_TEXTCODEC if (!m_textCodec) m_textCodec = findTextCodec(); if (m_textCodec) return m_textCodec->toUnicode(m_responseEntityBody); #endif 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(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") && method != QLatin1String("DELETE")) 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(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(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(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(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(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(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(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(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(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(context->thisObject().data().toQObject()); if (!request) THROW_REFERENCE("Not an XMLHttpRequest object"); if (!request->receivedXml() || (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(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 #endif // QT_NO_XMLSTREAMREADER #include