source: trunk/src/declarative/qml/qdeclarativexmlhttprequest.cpp@ 900

Last change on this file since 900 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 60.0 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
6**
7** This file is part of the QtDeclarative module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "private/qdeclarativexmlhttprequest_p.h"
43
44#include "qdeclarativeengine.h"
45#include "private/qdeclarativeengine_p.h"
46#include "private/qdeclarativerefcount_p.h"
47#include "private/qdeclarativeengine_p.h"
48#include "private/qdeclarativeexpression_p.h"
49#include "qdeclarativeglobal_p.h"
50
51#include <QtCore/qobject.h>
52#include <QtScript/qscriptvalue.h>
53#include <QtScript/qscriptcontext.h>
54#include <QtScript/qscriptengine.h>
55#include <QtNetwork/qnetworkreply.h>
56#include <QtCore/qtextcodec.h>
57#include <QtCore/qxmlstream.h>
58#include <QtCore/qstack.h>
59#include <QtCore/qdebug.h>
60
61#ifndef QT_NO_XMLSTREAMREADER
62
63// From DOM-Level-3-Core spec
64// http://www.w3.org/TR/DOM-Level-3-Core/core.html
65#define INDEX_SIZE_ERR 1
66#define DOMSTRING_SIZE_ERR 2
67#define HIERARCHY_REQUEST_ERR 3
68#define WRONG_DOCUMENT_ERR 4
69#define INVALID_CHARACTER_ERR 5
70#define NO_DATA_ALLOWED_ERR 6
71#define NO_MODIFICATION_ALLOWED_ERR 7
72#define NOT_FOUND_ERR 8
73#define NOT_SUPPORTED_ERR 9
74#define INUSE_ATTRIBUTE_ERR 10
75#define INVALID_STATE_ERR 11
76#define SYNTAX_ERR 12
77#define INVALID_MODIFICATION_ERR 13
78#define NAMESPACE_ERR 14
79#define INVALID_ACCESS_ERR 15
80#define VALIDATION_ERR 16
81#define TYPE_MISMATCH_ERR 17
82
83#define THROW_DOM(error, desc) \
84{ \
85 QScriptValue errorValue = context->throwError(QLatin1String(desc)); \
86 errorValue.setProperty(QLatin1String("code"), error); \
87 return errorValue; \
88}
89
90#define THROW_SYNTAX(desc) \
91 return context->throwError(QScriptContext::SyntaxError, QLatin1String(desc));
92#define THROW_REFERENCE(desc) \
93 return context->throwError(QScriptContext::ReferenceError, QLatin1String(desc));
94
95#define D(arg) (arg)->release()
96#define A(arg) (arg)->addref()
97
98QT_BEGIN_NAMESPACE
99
100DEFINE_BOOL_CONFIG_OPTION(xhrDump, QML_XHR_DUMP);
101
102class DocumentImpl;
103class NodeImpl
104{
105public:
106 NodeImpl() : type(Element), document(0), parent(0) {}
107 virtual ~NodeImpl() {
108 for (int ii = 0; ii < children.count(); ++ii)
109 delete children.at(ii);
110 for (int ii = 0; ii < attributes.count(); ++ii)
111 delete attributes.at(ii);
112 }
113
114 // These numbers are copied from the Node IDL definition
115 enum Type {
116 Attr = 2,
117 CDATA = 4,
118 Comment = 8,
119 Document = 9,
120 DocumentFragment = 11,
121 DocumentType = 10,
122 Element = 1,
123 Entity = 6,
124 EntityReference = 5,
125 Notation = 12,
126 ProcessingInstruction = 7,
127 Text = 3
128 };
129 Type type;
130
131 QString namespaceUri;
132 QString name;
133
134 QString data;
135
136 void addref();
137 void release();
138
139 DocumentImpl *document;
140 NodeImpl *parent;
141
142 QList<NodeImpl *> children;
143 QList<NodeImpl *> attributes;
144};
145
146class DocumentImpl : public QDeclarativeRefCount, public NodeImpl
147{
148public:
149 DocumentImpl() : root(0) { type = Document; }
150 virtual ~DocumentImpl() {
151 if (root) delete root;
152 }
153
154 QString version;
155 QString encoding;
156 bool isStandalone;
157
158 NodeImpl *root;
159
160 void addref() { QDeclarativeRefCount::addref(); }
161 void release() { QDeclarativeRefCount::release(); }
162};
163
164class NamedNodeMap
165{
166public:
167 // JS API
168 static QScriptValue length(QScriptContext *context, QScriptEngine *engine);
169
170 // C++ API
171 static QScriptValue prototype(QScriptEngine *);
172 static QScriptValue create(QScriptEngine *, NodeImpl *, QList<NodeImpl *> *);
173
174 NamedNodeMap();
175 NamedNodeMap(const NamedNodeMap &);
176 ~NamedNodeMap();
177 bool isNull();
178
179 NodeImpl *d;
180 QList<NodeImpl *> *list;
181private:
182 NamedNodeMap &operator=(const NamedNodeMap &);
183};
184
185class NamedNodeMapClass : public QScriptClass
186{
187public:
188 NamedNodeMapClass(QScriptEngine *engine) : QScriptClass(engine) {}
189
190 virtual QueryFlags queryProperty(const QScriptValue &object, const QScriptString &name, QueryFlags flags, uint *id);
191 virtual QScriptValue property(const QScriptValue &object, const QScriptString &name, uint id);
192};
193
194class NodeList
195{
196public:
197 // JS API
198 static QScriptValue length(QScriptContext *context, QScriptEngine *engine);
199
200 // C++ API
201 static QScriptValue prototype(QScriptEngine *);
202 static QScriptValue create(QScriptEngine *, NodeImpl *);
203
204 NodeList();
205 NodeList(const NodeList &);
206 ~NodeList();
207 bool isNull();
208
209 NodeImpl *d;
210private:
211 NodeList &operator=(const NodeList &);
212};
213
214class NodeListClass : public QScriptClass
215{
216public:
217 NodeListClass(QScriptEngine *engine) : QScriptClass(engine) {}
218 virtual QueryFlags queryProperty(const QScriptValue &object, const QScriptString &name, QueryFlags flags, uint *id);
219 virtual QScriptValue property(const QScriptValue &object, const QScriptString &name, uint id);
220};
221
222class Node
223{
224public:
225 // JS API
226 static QScriptValue nodeName(QScriptContext *context, QScriptEngine *engine);
227 static QScriptValue nodeValue(QScriptContext *context, QScriptEngine *engine);
228 static QScriptValue nodeType(QScriptContext *context, QScriptEngine *engine);
229
230 static QScriptValue parentNode(QScriptContext *context, QScriptEngine *engine);
231 static QScriptValue childNodes(QScriptContext *context, QScriptEngine *engine);
232 static QScriptValue firstChild(QScriptContext *context, QScriptEngine *engine);
233 static QScriptValue lastChild(QScriptContext *context, QScriptEngine *engine);
234 static QScriptValue previousSibling(QScriptContext *context, QScriptEngine *engine);
235 static QScriptValue nextSibling(QScriptContext *context, QScriptEngine *engine);
236 static QScriptValue attributes(QScriptContext *context, QScriptEngine *engine);
237
238 //static QScriptValue ownerDocument(QScriptContext *context, QScriptEngine *engine);
239 //static QScriptValue namespaceURI(QScriptContext *context, QScriptEngine *engine);
240 //static QScriptValue prefix(QScriptContext *context, QScriptEngine *engine);
241 //static QScriptValue localName(QScriptContext *context, QScriptEngine *engine);
242 //static QScriptValue baseURI(QScriptContext *context, QScriptEngine *engine);
243 //static QScriptValue textContent(QScriptContext *context, QScriptEngine *engine);
244
245 // C++ API
246 static QScriptValue prototype(QScriptEngine *);
247 static QScriptValue create(QScriptEngine *, NodeImpl *);
248
249 Node();
250 Node(const Node &o);
251 ~Node();
252 bool isNull() const;
253
254 NodeImpl *d;
255
256private:
257 Node &operator=(const Node &);
258};
259
260class Element : public Node
261{
262public:
263 // C++ API
264 static QScriptValue prototype(QScriptEngine *);
265};
266
267class Attr : public Node
268{
269public:
270 // JS API
271 static QScriptValue name(QScriptContext *context, QScriptEngine *engine);
272 static QScriptValue specified(QScriptContext *context, QScriptEngine *engine);
273 static QScriptValue value(QScriptContext *context, QScriptEngine *engine);
274 static QScriptValue ownerElement(QScriptContext *context, QScriptEngine *engine);
275 static QScriptValue schemaTypeInfo(QScriptContext *context, QScriptEngine *engine);
276 static QScriptValue isId(QScriptContext *context, QScriptEngine *engine);
277
278 // C++ API
279 static QScriptValue prototype(QScriptEngine *);
280};
281
282class CharacterData : public Node
283{
284public:
285 // JS API
286 static QScriptValue length(QScriptContext *context, QScriptEngine *engine);
287
288 // C++ API
289 static QScriptValue prototype(QScriptEngine *);
290};
291
292class Text : public CharacterData
293{
294public:
295 // JS API
296 static QScriptValue isElementContentWhitespace(QScriptContext *context, QScriptEngine *engine);
297 static QScriptValue wholeText(QScriptContext *context, QScriptEngine *engine);
298
299 // C++ API
300 static QScriptValue prototype(QScriptEngine *);
301};
302
303class CDATA : public Text
304{
305public:
306 // C++ API
307 static QScriptValue prototype(QScriptEngine *);
308};
309
310class Document : public Node
311{
312public:
313 // JS API
314 static QScriptValue xmlVersion(QScriptContext *context, QScriptEngine *engine);
315 static QScriptValue xmlEncoding(QScriptContext *context, QScriptEngine *engine);
316 static QScriptValue xmlStandalone(QScriptContext *context, QScriptEngine *engine);
317 static QScriptValue documentElement(QScriptContext *context, QScriptEngine *engine);
318
319 // C++ API
320 static QScriptValue prototype(QScriptEngine *);
321 static QScriptValue load(QScriptEngine *engine, const QByteArray &data);
322};
323
324QT_END_NAMESPACE
325
326Q_DECLARE_METATYPE(Node)
327Q_DECLARE_METATYPE(NodeList)
328Q_DECLARE_METATYPE(NamedNodeMap)
329
330QT_BEGIN_NAMESPACE
331
332void NodeImpl::addref()
333{
334 A(document);
335}
336
337void NodeImpl::release()
338{
339 D(document);
340}
341
342QScriptValue Node::nodeName(QScriptContext *context, QScriptEngine *engine)
343{
344 Node node = qscriptvalue_cast<Node>(context->thisObject());
345 if (node.isNull()) return engine->undefinedValue();
346
347 switch (node.d->type) {
348 case NodeImpl::Document:
349 return QScriptValue(QLatin1String("#document"));
350 case NodeImpl::CDATA:
351 return QScriptValue(QLatin1String("#cdata-section"));
352 case NodeImpl::Text:
353 return QScriptValue(QLatin1String("#text"));
354 default:
355 return QScriptValue(node.d->name);
356 }
357}
358
359QScriptValue Node::nodeValue(QScriptContext *context, QScriptEngine *engine)
360{
361 Node node = qscriptvalue_cast<Node>(context->thisObject());
362 if (node.isNull()) return engine->undefinedValue();
363
364 if (node.d->type == NodeImpl::Document ||
365 node.d->type == NodeImpl::DocumentFragment ||
366 node.d->type == NodeImpl::DocumentType ||
367 node.d->type == NodeImpl::Element ||
368 node.d->type == NodeImpl::Entity ||
369 node.d->type == NodeImpl::EntityReference ||
370 node.d->type == NodeImpl::Notation)
371 return engine->nullValue();
372
373 return QScriptValue(node.d->data);
374}
375
376QScriptValue Node::nodeType(QScriptContext *context, QScriptEngine *engine)
377{
378 Node node = qscriptvalue_cast<Node>(context->thisObject());
379 if (node.isNull()) return engine->undefinedValue();
380 return QScriptValue(node.d->type);
381}
382
383QScriptValue Node::parentNode(QScriptContext *context, QScriptEngine *engine)
384{
385 Node node = qscriptvalue_cast<Node>(context->thisObject());
386 if (node.isNull()) return engine->undefinedValue();
387
388 if (node.d->parent) return Node::create(engine, node.d->parent);
389 else return engine->nullValue();
390}
391
392QScriptValue Node::childNodes(QScriptContext *context, QScriptEngine *engine)
393{
394 Node node = qscriptvalue_cast<Node>(context->thisObject());
395 if (node.isNull()) return engine->undefinedValue();
396
397 return NodeList::create(engine, node.d);
398}
399
400QScriptValue Node::firstChild(QScriptContext *context, QScriptEngine *engine)
401{
402 Node node = qscriptvalue_cast<Node>(context->thisObject());
403 if (node.isNull()) return engine->undefinedValue();
404
405 if (node.d->children.isEmpty()) return engine->nullValue();
406 else return Node::create(engine, node.d->children.first());
407}
408
409QScriptValue Node::lastChild(QScriptContext *context, QScriptEngine *engine)
410{
411 Node node = qscriptvalue_cast<Node>(context->thisObject());
412 if (node.isNull()) return engine->undefinedValue();
413
414 if (node.d->children.isEmpty()) return engine->nullValue();
415 else return Node::create(engine, node.d->children.last());
416}
417
418QScriptValue Node::previousSibling(QScriptContext *context, QScriptEngine *engine)
419{
420 Node node = qscriptvalue_cast<Node>(context->thisObject());
421 if (node.isNull()) return engine->undefinedValue();
422
423 if (!node.d->parent) return engine->nullValue();
424
425 for (int ii = 0; ii < node.d->parent->children.count(); ++ii) {
426 if (node.d->parent->children.at(ii) == node.d) {
427 if (ii == 0) return engine->nullValue();
428 else return Node::create(engine, node.d->parent->children.at(ii - 1));
429 }
430 }
431
432 return engine->nullValue();
433}
434
435QScriptValue Node::nextSibling(QScriptContext *context, QScriptEngine *engine)
436{
437 Node node = qscriptvalue_cast<Node>(context->thisObject());
438 if (node.isNull()) return engine->undefinedValue();
439
440 if (!node.d->parent) return engine->nullValue();
441
442 for (int ii = 0; ii < node.d->parent->children.count(); ++ii) {
443 if (node.d->parent->children.at(ii) == node.d) {
444 if ((ii + 1) == node.d->parent->children.count()) return engine->nullValue();
445 else return Node::create(engine, node.d->parent->children.at(ii + 1));
446 }
447 }
448
449 return engine->nullValue();
450}
451
452QScriptValue Node::attributes(QScriptContext *context, QScriptEngine *engine)
453{
454 Node node = qscriptvalue_cast<Node>(context->thisObject());
455 if (node.isNull()) return engine->undefinedValue();
456
457 if (node.d->type != NodeImpl::Element)
458 return engine->nullValue();
459 else
460 return NamedNodeMap::create(engine, node.d, &node.d->attributes);
461}
462
463QScriptValue Node::prototype(QScriptEngine *engine)
464{
465 QScriptValue proto = engine->newObject();
466
467 proto.setProperty(QLatin1String("nodeName"), engine->newFunction(nodeName), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
468 proto.setProperty(QLatin1String("nodeValue"), engine->newFunction(nodeValue), QScriptValue::ReadOnly | QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
469 proto.setProperty(QLatin1String("nodeType"), engine->newFunction(nodeType), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
470 proto.setProperty(QLatin1String("parentNode"), engine->newFunction(parentNode), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
471 proto.setProperty(QLatin1String("childNodes"), engine->newFunction(childNodes), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
472 proto.setProperty(QLatin1String("firstChild"), engine->newFunction(firstChild), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
473 proto.setProperty(QLatin1String("lastChild"), engine->newFunction(lastChild), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
474 proto.setProperty(QLatin1String("previousSibling"), engine->newFunction(previousSibling), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
475 proto.setProperty(QLatin1String("nextSibling"), engine->newFunction(nextSibling), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
476 proto.setProperty(QLatin1String("attributes"), engine->newFunction(attributes), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
477
478 return proto;
479}
480
481QScriptValue Node::create(QScriptEngine *engine, NodeImpl *data)
482{
483 QScriptValue instance = engine->newObject();
484
485 switch (data->type) {
486 case NodeImpl::Attr:
487 instance.setPrototype(Attr::prototype(engine));
488 break;
489 case NodeImpl::Comment:
490 case NodeImpl::Document:
491 case NodeImpl::DocumentFragment:
492 case NodeImpl::DocumentType:
493 case NodeImpl::Entity:
494 case NodeImpl::EntityReference:
495 case NodeImpl::Notation:
496 case NodeImpl::ProcessingInstruction:
497 return QScriptValue();
498 case NodeImpl::CDATA:
499 instance.setPrototype(CDATA::prototype(engine));
500 break;
501 case NodeImpl::Text:
502 instance.setPrototype(Text::prototype(engine));
503 break;
504 case NodeImpl::Element:
505 instance.setPrototype(Element::prototype(engine));
506 break;
507 }
508
509 Node node;
510 node.d = data;
511 if (data) A(data);
512
513 return engine->newVariant(instance, qVariantFromValue(node));
514}
515
516QScriptValue Element::prototype(QScriptEngine *engine)
517{
518 QScriptValue proto = engine->newObject();
519 proto.setPrototype(Node::prototype(engine));
520
521 proto.setProperty(QLatin1String("tagName"), engine->newFunction(nodeName), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
522
523 return proto;
524}
525
526QScriptValue Attr::prototype(QScriptEngine *engine)
527{
528 QScriptValue proto = engine->newObject();
529 proto.setPrototype(Node::prototype(engine));
530
531 proto.setProperty(QLatin1String("name"), engine->newFunction(name), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
532 proto.setProperty(QLatin1String("value"), engine->newFunction(value), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
533 proto.setProperty(QLatin1String("ownerElement"), engine->newFunction(ownerElement), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
534
535 return proto;
536}
537
538QScriptValue Attr::name(QScriptContext *context, QScriptEngine *engine)
539{
540 Node node = qscriptvalue_cast<Node>(context->thisObject());
541 if (node.isNull()) return engine->undefinedValue();
542
543 return QScriptValue(node.d->name);
544}
545
546QScriptValue Attr::value(QScriptContext *context, QScriptEngine *engine)
547{
548 Node node = qscriptvalue_cast<Node>(context->thisObject());
549 if (node.isNull()) return engine->undefinedValue();
550
551 return QScriptValue(node.d->data);
552}
553
554QScriptValue Attr::ownerElement(QScriptContext *context, QScriptEngine *engine)
555{
556 Node node = qscriptvalue_cast<Node>(context->thisObject());
557 if (node.isNull()) return engine->undefinedValue();
558
559 return Node::create(engine, node.d->parent);
560}
561
562QScriptValue CharacterData::length(QScriptContext *context, QScriptEngine *engine)
563{
564 Node node = qscriptvalue_cast<Node>(context->thisObject());
565 if (node.isNull()) return engine->undefinedValue();
566
567 return QScriptValue(node.d->data.length());
568}
569
570QScriptValue CharacterData::prototype(QScriptEngine *engine)
571{
572 QScriptValue proto = engine->newObject();
573 proto.setPrototype(Node::prototype(engine));
574
575 proto.setProperty(QLatin1String("data"), engine->newFunction(nodeValue), QScriptValue::ReadOnly | QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
576 proto.setProperty(QLatin1String("length"), engine->newFunction(length), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
577
578 return proto;
579}
580
581QScriptValue Text::isElementContentWhitespace(QScriptContext *context, QScriptEngine *engine)
582{
583 Node node = qscriptvalue_cast<Node>(context->thisObject());
584 if (node.isNull()) return engine->undefinedValue();
585
586 return node.d->data.trimmed().isEmpty();
587}
588
589QScriptValue Text::wholeText(QScriptContext *context, QScriptEngine *engine)
590{
591 Node node = qscriptvalue_cast<Node>(context->thisObject());
592 if (node.isNull()) return engine->undefinedValue();
593
594 return node.d->data;
595}
596
597QScriptValue Text::prototype(QScriptEngine *engine)
598{
599 QScriptValue proto = engine->newObject();
600 proto.setPrototype(CharacterData::prototype(engine));
601
602 proto.setProperty(QLatin1String("isElementContentWhitespace"), engine->newFunction(isElementContentWhitespace), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
603 proto.setProperty(QLatin1String("wholeText"), engine->newFunction(wholeText), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
604
605 return proto;
606}
607
608QScriptValue CDATA::prototype(QScriptEngine *engine)
609{
610 QScriptValue proto = engine->newObject();
611 proto.setPrototype(Text::prototype(engine));
612 return proto;
613}
614
615QScriptValue Document::prototype(QScriptEngine *engine)
616{
617 QScriptValue proto = engine->newObject();
618 proto.setPrototype(Node::prototype(engine));
619
620 proto.setProperty(QLatin1String("xmlVersion"), engine->newFunction(xmlVersion), QScriptValue::ReadOnly | QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
621 proto.setProperty(QLatin1String("xmlEncoding"), engine->newFunction(xmlEncoding), QScriptValue::ReadOnly | QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
622 proto.setProperty(QLatin1String("xmlStandalone"), engine->newFunction(xmlStandalone), QScriptValue::ReadOnly | QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
623 proto.setProperty(QLatin1String("documentElement"), engine->newFunction(documentElement), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
624
625 return proto;
626}
627
628QScriptValue Document::load(QScriptEngine *engine, const QByteArray &data)
629{
630 Q_ASSERT(engine);
631
632 DocumentImpl *document = 0;
633 QStack<NodeImpl *> nodeStack;
634
635 QXmlStreamReader reader(data);
636
637 while (!reader.atEnd()) {
638 switch (reader.readNext()) {
639 case QXmlStreamReader::NoToken:
640 break;
641 case QXmlStreamReader::Invalid:
642 break;
643 case QXmlStreamReader::StartDocument:
644 Q_ASSERT(!document);
645 document = new DocumentImpl;
646 document->document = document;
647 document->version = reader.documentVersion().toString();
648 document->encoding = reader.documentEncoding().toString();
649 document->isStandalone = reader.isStandaloneDocument();
650 break;
651 case QXmlStreamReader::EndDocument:
652 break;
653 case QXmlStreamReader::StartElement:
654 {
655 Q_ASSERT(document);
656 NodeImpl *node = new NodeImpl;
657 node->document = document;
658 node->namespaceUri = reader.namespaceUri().toString();
659 node->name = reader.name().toString();
660 if (nodeStack.isEmpty()) {
661 document->root = node;
662 } else {
663 node->parent = nodeStack.top();
664 node->parent->children.append(node);
665 }
666 nodeStack.append(node);
667
668 foreach (const QXmlStreamAttribute &a, reader.attributes()) {
669 NodeImpl *attr = new NodeImpl;
670 attr->document = document;
671 attr->type = NodeImpl::Attr;
672 attr->namespaceUri = a.namespaceUri().toString();
673 attr->name = a.name().toString();
674 attr->data = a.value().toString();
675 attr->parent = node;
676 node->attributes.append(attr);
677 }
678 }
679 break;
680 case QXmlStreamReader::EndElement:
681 nodeStack.pop();
682 break;
683 case QXmlStreamReader::Characters:
684 {
685 NodeImpl *node = new NodeImpl;
686 node->document = document;
687 node->type = reader.isCDATA()?NodeImpl::CDATA:NodeImpl::Text;
688 node->parent = nodeStack.top();
689 node->parent->children.append(node);
690 node->data = reader.text().toString();
691 }
692 break;
693 case QXmlStreamReader::Comment:
694 break;
695 case QXmlStreamReader::DTD:
696 break;
697 case QXmlStreamReader::EntityReference:
698 break;
699 case QXmlStreamReader::ProcessingInstruction:
700 break;
701 }
702 }
703
704 if (!document || reader.hasError()) {
705 if (document) D(document);
706 return engine->nullValue();
707 }
708
709 QScriptValue instance = engine->newObject();
710 instance.setPrototype(Document::prototype(engine));
711 Node documentNode;
712 documentNode.d = document;
713 return engine->newVariant(instance, qVariantFromValue(documentNode));
714}
715
716Node::Node()
717: d(0)
718{
719}
720
721Node::Node(const Node &o)
722: d(o.d)
723{
724 if (d) A(d);
725}
726
727Node::~Node()
728{
729 if (d) D(d);
730}
731
732bool Node::isNull() const
733{
734 return d == 0;
735}
736
737QScriptValue NamedNodeMap::length(QScriptContext *context, QScriptEngine *engine)
738{
739 NamedNodeMap map = qscriptvalue_cast<NamedNodeMap>(context->thisObject().data());
740 if (map.isNull()) return engine->undefinedValue();
741
742 return QScriptValue(map.list->count());
743}
744
745QScriptValue NamedNodeMap::prototype(QScriptEngine *engine)
746{
747 QScriptValue proto = engine->newObject();
748
749 proto.setProperty(QLatin1String("length"), engine->newFunction(length), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
750
751 return proto;
752}
753
754QScriptValue NamedNodeMap::create(QScriptEngine *engine, NodeImpl *data, QList<NodeImpl *> *list)
755{
756 QScriptValue instance = engine->newObject();
757 instance.setPrototype(NamedNodeMap::prototype(engine));
758
759 NamedNodeMap map;
760 map.d = data;
761 map.list = list;
762 if (data) A(data);
763
764 instance.setData(engine->newVariant(qVariantFromValue(map)));
765
766 if (!QDeclarativeScriptEngine::get(engine)->namedNodeMapClass)
767 QDeclarativeScriptEngine::get(engine)->namedNodeMapClass= new NamedNodeMapClass(engine);
768
769 instance.setScriptClass(QDeclarativeScriptEngine::get(engine)->namedNodeMapClass);
770
771 return instance;
772}
773
774NamedNodeMap::NamedNodeMap()
775: d(0), list(0)
776{
777}
778
779NamedNodeMap::NamedNodeMap(const NamedNodeMap &o)
780: d(o.d), list(o.list)
781{
782 if (d) A(d);
783}
784
785NamedNodeMap::~NamedNodeMap()
786{
787 if (d) D(d);
788}
789
790bool NamedNodeMap::isNull()
791{
792 return d == 0;
793}
794
795QScriptValue NodeList::length(QScriptContext *context, QScriptEngine *engine)
796{
797 NodeList list = qscriptvalue_cast<NodeList>(context->thisObject().data());
798 if (list.isNull()) return engine->undefinedValue();
799
800 return QScriptValue(list.d->children.count());
801}
802
803QScriptValue NodeList::prototype(QScriptEngine *engine)
804{
805 QScriptValue proto = engine->newObject();
806
807 proto.setProperty(QLatin1String("length"), engine->newFunction(length), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
808
809 return proto;
810}
811
812QScriptValue NodeList::create(QScriptEngine *engine, NodeImpl *data)
813{
814 QScriptValue instance = engine->newObject();
815 instance.setPrototype(NodeList::prototype(engine));
816
817 NodeList list;
818 list.d = data;
819 if (data) A(data);
820
821 instance.setData(engine->newVariant(qVariantFromValue(list)));
822
823 if (!QDeclarativeScriptEngine::get(engine)->nodeListClass)
824 QDeclarativeScriptEngine::get(engine)->nodeListClass= new NodeListClass(engine);
825
826 instance.setScriptClass(QDeclarativeScriptEngine::get(engine)->nodeListClass);
827
828 return instance;
829}
830
831NodeList::NodeList()
832: d(0)
833{
834}
835
836NodeList::NodeList(const NodeList &o)
837: d(o.d)
838{
839 if (d) A(d);
840}
841
842NodeList::~NodeList()
843{
844 if (d) D(d);
845}
846
847bool NodeList::isNull()
848{
849 return d == 0;
850}
851
852NamedNodeMapClass::QueryFlags NamedNodeMapClass::queryProperty(const QScriptValue &object, const QScriptString &name, QueryFlags flags, uint *id)
853{
854 if (!(flags & HandlesReadAccess))
855 return 0;
856
857 NamedNodeMap map = qscriptvalue_cast<NamedNodeMap>(object.data());
858 Q_ASSERT(!map.isNull());
859
860 bool ok = false;
861 QString nameString = name.toString();
862 uint index = nameString.toUInt(&ok);
863 if (ok) {
864 if ((uint)map.list->count() <= index)
865 return 0;
866
867 *id = index;
868 return HandlesReadAccess;
869 } else {
870 for (int ii = 0; ii < map.list->count(); ++ii) {
871 if (map.list->at(ii) && map.list->at(ii)->name == nameString) {
872 *id = ii;
873 return HandlesReadAccess;
874 }
875 }
876 }
877
878 return 0;
879}
880
881QScriptValue NamedNodeMapClass::property(const QScriptValue &object, const QScriptString &, uint id)
882{
883 NamedNodeMap map = qscriptvalue_cast<NamedNodeMap>(object.data());
884 return Node::create(engine(), map.list->at(id));
885}
886
887NodeListClass::QueryFlags NodeListClass::queryProperty(const QScriptValue &object, const QScriptString &name, QueryFlags flags, uint *id)
888{
889 if (!(flags & HandlesReadAccess))
890 return 0;
891
892 bool ok = false;
893 uint index = name.toString().toUInt(&ok);
894 if (!ok)
895 return 0;
896
897 NodeList list = qscriptvalue_cast<NodeList>(object.data());
898 if (list.isNull() || (uint)list.d->children.count() <= index)
899 return 0; // ### I think we're meant to raise an exception
900
901 *id = index;
902 return HandlesReadAccess;
903}
904
905QScriptValue NodeListClass::property(const QScriptValue &object, const QScriptString &, uint id)
906{
907 NodeList list = qscriptvalue_cast<NodeList>(object.data());
908 return Node::create(engine(), list.d->children.at(id));
909}
910
911QScriptValue Document::documentElement(QScriptContext *context, QScriptEngine *engine)
912{
913 Node document = qscriptvalue_cast<Node>(context->thisObject());
914 if (document.isNull() || document.d->type != NodeImpl::Document) return engine->undefinedValue();
915
916 return Node::create(engine, static_cast<DocumentImpl *>(document.d)->root);
917}
918
919QScriptValue Document::xmlStandalone(QScriptContext *context, QScriptEngine *engine)
920{
921 Node document = qscriptvalue_cast<Node>(context->thisObject());
922 if (document.isNull() || document.d->type != NodeImpl::Document) return engine->undefinedValue();
923
924 return QScriptValue(static_cast<DocumentImpl *>(document.d)->isStandalone);
925}
926
927QScriptValue Document::xmlVersion(QScriptContext *context, QScriptEngine *engine)
928{
929 Node document = qscriptvalue_cast<Node>(context->thisObject());
930 if (document.isNull() || document.d->type != NodeImpl::Document) return engine->undefinedValue();
931
932 return QScriptValue(static_cast<DocumentImpl *>(document.d)->version);
933}
934
935QScriptValue Document::xmlEncoding(QScriptContext *context, QScriptEngine *engine)
936{
937 Node document = qscriptvalue_cast<Node>(context->thisObject());
938 if (document.isNull() || document.d->type != NodeImpl::Document) return engine->undefinedValue();
939
940 return QScriptValue(static_cast<DocumentImpl *>(document.d)->encoding);
941}
942
943class QDeclarativeXMLHttpRequest : public QObject
944{
945Q_OBJECT
946public:
947 enum State { Unsent = 0,
948 Opened = 1, HeadersReceived = 2,
949 Loading = 3, Done = 4 };
950
951 QDeclarativeXMLHttpRequest(QNetworkAccessManager *manager);
952 virtual ~QDeclarativeXMLHttpRequest();
953
954 bool sendFlag() const;
955 bool errorFlag() const;
956 quint32 readyState() const;
957 int replyStatus() const;
958 QString replyStatusText() const;
959
960 QScriptValue open(QScriptValue *me, const QString &, const QUrl &);
961
962 void addHeader(const QString &, const QString &);
963 QString header(const QString &name);
964 QString headers();
965 QScriptValue send(QScriptValue *me, const QByteArray &);
966 QScriptValue abort(QScriptValue *me);
967
968 QString responseBody();
969 const QByteArray & rawResponseBody() const;
970 bool receivedXml() const;
971private slots:
972 void downloadProgress(qint64);
973 void error(QNetworkReply::NetworkError);
974 void finished();
975
976private:
977 void requestFromUrl(const QUrl &url);
978
979 State m_state;
980 bool m_errorFlag;
981 bool m_sendFlag;
982 QString m_method;
983 QUrl m_url;
984 QByteArray m_responseEntityBody;
985 QByteArray m_data;
986 int m_redirectCount;
987
988 typedef QPair<QByteArray, QByteArray> HeaderPair;
989 typedef QList<HeaderPair> HeadersList;
990 HeadersList m_headersList;
991 void fillHeadersList();
992
993 bool m_gotXml;
994 QByteArray m_mime;
995 QByteArray m_charset;
996 QTextCodec *m_textCodec;
997#ifndef QT_NO_TEXTCODEC
998 QTextCodec* findTextCodec() const;
999#endif
1000 void readEncoding();
1001
1002 QScriptValue m_me; // Set to the data object while a send() is ongoing (to access the callback)
1003
1004 QScriptValue dispatchCallback(QScriptValue *me);
1005 void printError(const QScriptValue&);
1006
1007 int m_status;
1008 QString m_statusText;
1009 QNetworkRequest m_request;
1010 QDeclarativeGuard<QNetworkReply> m_network;
1011 void destroyNetwork();
1012
1013 QNetworkAccessManager *m_nam;
1014 QNetworkAccessManager *networkAccessManager() { return m_nam; }
1015};
1016
1017QDeclarativeXMLHttpRequest::QDeclarativeXMLHttpRequest(QNetworkAccessManager *manager)
1018: m_state(Unsent), m_errorFlag(false), m_sendFlag(false),
1019 m_redirectCount(0), m_gotXml(false), m_textCodec(0), m_network(0), m_nam(manager)
1020{
1021}
1022
1023QDeclarativeXMLHttpRequest::~QDeclarativeXMLHttpRequest()
1024{
1025 destroyNetwork();
1026}
1027
1028bool QDeclarativeXMLHttpRequest::sendFlag() const
1029{
1030 return m_sendFlag;
1031}
1032
1033bool QDeclarativeXMLHttpRequest::errorFlag() const
1034{
1035 return m_errorFlag;
1036}
1037
1038quint32 QDeclarativeXMLHttpRequest::readyState() const
1039{
1040 return m_state;
1041}
1042
1043int QDeclarativeXMLHttpRequest::replyStatus() const
1044{
1045 return m_status;
1046}
1047
1048QString QDeclarativeXMLHttpRequest::replyStatusText() const
1049{
1050 return m_statusText;
1051}
1052
1053QScriptValue QDeclarativeXMLHttpRequest::open(QScriptValue *me, const QString &method, const QUrl &url)
1054{
1055 destroyNetwork();
1056 m_sendFlag = false;
1057 m_errorFlag = false;
1058 m_responseEntityBody = QByteArray();
1059 m_method = method;
1060 m_url = url;
1061 m_state = Opened;
1062 return dispatchCallback(me);
1063}
1064
1065void QDeclarativeXMLHttpRequest::addHeader(const QString &name, const QString &value)
1066{
1067 QByteArray utfname = name.toUtf8();
1068
1069 if (m_request.hasRawHeader(utfname)) {
1070 m_request.setRawHeader(utfname, m_request.rawHeader(utfname) + ',' + value.toUtf8());
1071 } else {
1072 m_request.setRawHeader(utfname, value.toUtf8());
1073 }
1074}
1075
1076QString QDeclarativeXMLHttpRequest::header(const QString &name)
1077{
1078 QByteArray utfname = name.toLower().toUtf8();
1079
1080 foreach (const HeaderPair &header, m_headersList) {
1081 if (header.first == utfname)
1082 return QString::fromUtf8(header.second);
1083 }
1084 return QString();
1085}
1086
1087QString QDeclarativeXMLHttpRequest::headers()
1088{
1089 QString ret;
1090
1091 foreach (const HeaderPair &header, m_headersList) {
1092 if (ret.length())
1093 ret.append(QString::fromUtf8("\r\n"));
1094 ret.append(QString::fromUtf8(header.first));
1095 ret.append(QString::fromUtf8(": "));
1096 ret.append(QString::fromUtf8(header.second));
1097 }
1098 return ret;
1099}
1100
1101void QDeclarativeXMLHttpRequest::fillHeadersList()
1102{
1103 QList<QByteArray> headerList = m_network->rawHeaderList();
1104
1105 m_headersList.clear();
1106 foreach (const QByteArray &header, headerList) {
1107 HeaderPair pair (header.toLower(), m_network->rawHeader(header));
1108 if (pair.first == "set-cookie" ||
1109 pair.first == "set-cookie2")
1110 continue;
1111
1112 m_headersList << pair;
1113 }
1114}
1115
1116void QDeclarativeXMLHttpRequest::requestFromUrl(const QUrl &url)
1117{
1118 QNetworkRequest request = m_request;
1119 request.setUrl(url);
1120 if(m_method == QLatin1String("POST") ||
1121 m_method == QLatin1String("PUT")) {
1122 QVariant var = request.header(QNetworkRequest::ContentTypeHeader);
1123 if (var.isValid()) {
1124 QString str = var.toString();
1125 int charsetIdx = str.indexOf(QLatin1String("charset="));
1126 if (charsetIdx == -1) {
1127 // No charset - append
1128 if (!str.isEmpty()) str.append(QLatin1Char(';'));
1129 str.append(QLatin1String("charset=UTF-8"));
1130 } else {
1131 charsetIdx += 8;
1132 int n = 0;
1133 int semiColon = str.indexOf(QLatin1Char(';'), charsetIdx);
1134 if (semiColon == -1) {
1135 n = str.length() - charsetIdx;
1136 } else {
1137 n = semiColon - charsetIdx;
1138 }
1139
1140 str.replace(charsetIdx, n, QLatin1String("UTF-8"));
1141 }
1142 request.setHeader(QNetworkRequest::ContentTypeHeader, str);
1143 } else {
1144 request.setHeader(QNetworkRequest::ContentTypeHeader,
1145 QLatin1String("text/plain;charset=UTF-8"));
1146 }
1147 }
1148
1149 if (xhrDump()) {
1150 qWarning().nospace() << "XMLHttpRequest: " << qPrintable(m_method) << " " << qPrintable(url.toString());
1151 if (!m_data.isEmpty()) {
1152 qWarning().nospace() << " "
1153 << qPrintable(QString::fromUtf8(m_data));
1154 }
1155 }
1156
1157 if (m_method == QLatin1String("GET"))
1158 m_network = networkAccessManager()->get(request);
1159 else if (m_method == QLatin1String("HEAD"))
1160 m_network = networkAccessManager()->head(request);
1161 else if(m_method == QLatin1String("POST"))
1162 m_network = networkAccessManager()->post(request, m_data);
1163 else if(m_method == QLatin1String("PUT"))
1164 m_network = networkAccessManager()->put(request, m_data);
1165
1166 QObject::connect(m_network, SIGNAL(downloadProgress(qint64,qint64)),
1167 this, SLOT(downloadProgress(qint64)));
1168 QObject::connect(m_network, SIGNAL(error(QNetworkReply::NetworkError)),
1169 this, SLOT(error(QNetworkReply::NetworkError)));
1170 QObject::connect(m_network, SIGNAL(finished()),
1171 this, SLOT(finished()));
1172}
1173
1174QScriptValue QDeclarativeXMLHttpRequest::send(QScriptValue *me, const QByteArray &data)
1175{
1176 m_errorFlag = false;
1177 m_sendFlag = true;
1178 m_redirectCount = 0;
1179 m_data = data;
1180 m_me = *me;
1181
1182 requestFromUrl(m_url);
1183
1184 return QScriptValue();
1185}
1186
1187QScriptValue QDeclarativeXMLHttpRequest::abort(QScriptValue *me)
1188{
1189 destroyNetwork();
1190 m_responseEntityBody = QByteArray();
1191 m_errorFlag = true;
1192 m_request = QNetworkRequest();
1193
1194 if (!(m_state == Unsent ||
1195 (m_state == Opened && !m_sendFlag) ||
1196 m_state == Done)) {
1197
1198 m_state = Done;
1199 m_sendFlag = false;
1200 QScriptValue cbv = dispatchCallback(me);
1201 if (cbv.isError()) return cbv;
1202 }
1203
1204 m_state = Unsent;
1205 return QScriptValue();
1206}
1207
1208void QDeclarativeXMLHttpRequest::downloadProgress(qint64 bytes)
1209{
1210 Q_UNUSED(bytes)
1211 m_status =
1212 m_network->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
1213 m_statusText =
1214 QString::fromUtf8(m_network->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toByteArray());
1215
1216 // ### We assume if this is called the headers are now available
1217 if (m_state < HeadersReceived) {
1218 m_state = HeadersReceived;
1219 fillHeadersList ();
1220 QScriptValue cbv = dispatchCallback(&m_me);
1221 if (cbv.isError()) printError(cbv);
1222 }
1223
1224 bool wasEmpty = m_responseEntityBody.isEmpty();
1225 m_responseEntityBody.append(m_network->readAll());
1226 if (wasEmpty && !m_responseEntityBody.isEmpty()) {
1227 m_state = Loading;
1228 QScriptValue cbv = dispatchCallback(&m_me);
1229 if (cbv.isError()) printError(cbv);
1230 }
1231}
1232
1233void QDeclarativeXMLHttpRequest::error(QNetworkReply::NetworkError error)
1234{
1235 Q_UNUSED(error)
1236 m_status =
1237 m_network->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
1238 m_statusText =
1239 QString::fromUtf8(m_network->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toByteArray());
1240
1241 m_responseEntityBody = QByteArray();
1242
1243 m_request = QNetworkRequest();
1244 m_data.clear();
1245 destroyNetwork();
1246
1247 if (error == QNetworkReply::ContentAccessDenied ||
1248 error == QNetworkReply::ContentOperationNotPermittedError ||
1249 error == QNetworkReply::ContentNotFoundError ||
1250 error == QNetworkReply::AuthenticationRequiredError ||
1251 error == QNetworkReply::ContentReSendError) {
1252 m_state = Loading;
1253 QScriptValue cbv = dispatchCallback(&m_me);
1254 if (cbv.isError()) printError(cbv);
1255 } else {
1256 m_errorFlag = true;
1257 }
1258
1259 m_state = Done;
1260 QScriptValue cbv = dispatchCallback(&m_me);
1261 if (cbv.isError()) printError(cbv);
1262}
1263
1264#define XMLHTTPREQUEST_MAXIMUM_REDIRECT_RECURSION 15
1265void QDeclarativeXMLHttpRequest::finished()
1266{
1267 m_redirectCount++;
1268 if (m_redirectCount < XMLHTTPREQUEST_MAXIMUM_REDIRECT_RECURSION) {
1269 QVariant redirect = m_network->attribute(QNetworkRequest::RedirectionTargetAttribute);
1270 if (redirect.isValid()) {
1271 QUrl url = m_network->url().resolved(redirect.toUrl());
1272 destroyNetwork();
1273 requestFromUrl(url);
1274 return;
1275 }
1276 }
1277
1278 m_status =
1279 m_network->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
1280 m_statusText =
1281 QString::fromUtf8(m_network->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toByteArray());
1282
1283 if (m_state < HeadersReceived) {
1284 m_state = HeadersReceived;
1285 fillHeadersList ();
1286 QScriptValue cbv = dispatchCallback(&m_me);
1287 if (cbv.isError()) printError(cbv);
1288 }
1289 m_responseEntityBody.append(m_network->readAll());
1290 readEncoding();
1291
1292 if (xhrDump()) {
1293 qWarning().nospace() << "XMLHttpRequest: RESPONSE " << qPrintable(m_url.toString());
1294 if (!m_responseEntityBody.isEmpty()) {
1295 qWarning().nospace() << " "
1296 << qPrintable(QString::fromUtf8(m_responseEntityBody));
1297 }
1298 }
1299
1300
1301 m_data.clear();
1302 destroyNetwork();
1303 if (m_state < Loading) {
1304 m_state = Loading;
1305 QScriptValue cbv = dispatchCallback(&m_me);
1306 if (cbv.isError()) printError(cbv);
1307 }
1308 m_state = Done;
1309 QScriptValue cbv = dispatchCallback(&m_me);
1310 if (cbv.isError()) printError(cbv);
1311
1312 m_me = QScriptValue();
1313}
1314
1315
1316void QDeclarativeXMLHttpRequest::readEncoding()
1317{
1318 foreach (const HeaderPair &header, m_headersList) {
1319 if (header.first == "content-type") {
1320 int separatorIdx = header.second.indexOf(';');
1321 if (separatorIdx == -1) {
1322 m_mime == header.second;
1323 } else {
1324 m_mime = header.second.mid(0, separatorIdx);
1325 int charsetIdx = header.second.indexOf("charset=");
1326 if (charsetIdx != -1) {
1327 charsetIdx += 8;
1328 separatorIdx = header.second.indexOf(';', charsetIdx);
1329 m_charset = header.second.mid(charsetIdx, separatorIdx >= 0 ? separatorIdx : header.second.length());
1330 }
1331 }
1332 break;
1333 }
1334 }
1335
1336 if (m_mime.isEmpty() || m_mime == "text/xml" || m_mime == "application/xml" || m_mime.endsWith("+xml"))
1337 m_gotXml = true;
1338}
1339
1340bool QDeclarativeXMLHttpRequest::receivedXml() const
1341{
1342 return m_gotXml;
1343}
1344
1345
1346#ifndef QT_NO_TEXTCODEC
1347QTextCodec* QDeclarativeXMLHttpRequest::findTextCodec() const
1348{
1349 QTextCodec *codec = 0;
1350
1351 if (!m_charset.isEmpty())
1352 codec = QTextCodec::codecForName(m_charset);
1353
1354 if (!codec && m_gotXml) {
1355 QXmlStreamReader reader(m_responseEntityBody);
1356 reader.readNext();
1357 codec = QTextCodec::codecForName(reader.documentEncoding().toString().toUtf8());
1358 }
1359
1360 if (!codec && m_mime == "text/html")
1361 codec = QTextCodec::codecForHtml(m_responseEntityBody, 0);
1362
1363 if (!codec)
1364 codec = QTextCodec::codecForUtfText(m_responseEntityBody, 0);
1365
1366 if (!codec)
1367 codec = QTextCodec::codecForName("UTF-8");
1368 return codec;
1369}
1370#endif
1371
1372
1373QString QDeclarativeXMLHttpRequest::responseBody()
1374{
1375#ifndef QT_NO_TEXTCODEC
1376 if (!m_textCodec)
1377 m_textCodec = findTextCodec();
1378 if (m_textCodec)
1379 return m_textCodec->toUnicode(m_responseEntityBody);
1380#endif
1381
1382 return QString::fromUtf8(m_responseEntityBody);
1383}
1384
1385const QByteArray &QDeclarativeXMLHttpRequest::rawResponseBody() const
1386{
1387 return m_responseEntityBody;
1388}
1389
1390QScriptValue QDeclarativeXMLHttpRequest::dispatchCallback(QScriptValue *me)
1391{
1392 QScriptValue v = me->property(QLatin1String("callback"));
1393 return v.call();
1394}
1395
1396void QDeclarativeXMLHttpRequest::printError(const QScriptValue& sv)
1397{
1398 QDeclarativeError error;
1399 QDeclarativeExpressionPrivate::exceptionToError(sv.engine(), error);
1400 QDeclarativeEnginePrivate::warning(QDeclarativeEnginePrivate::get(sv.engine()), error);
1401}
1402
1403void QDeclarativeXMLHttpRequest::destroyNetwork()
1404{
1405 if (m_network) {
1406 m_network->disconnect();
1407 m_network->deleteLater();
1408 m_network = 0;
1409 }
1410}
1411
1412// XMLHttpRequest methods
1413static QScriptValue qmlxmlhttprequest_open(QScriptContext *context, QScriptEngine *engine)
1414{
1415 QScriptValue dataObject = context->thisObject().data();
1416 QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(dataObject.toQObject());
1417 if (!request)
1418 THROW_REFERENCE("Not an XMLHttpRequest object");
1419
1420 if (context->argumentCount() < 2 || context->argumentCount() > 5)
1421 THROW_DOM(SYNTAX_ERR, "Incorrect argument count");
1422
1423 // Argument 0 - Method
1424 QString method = context->argument(0).toString().toUpper();
1425 if (method != QLatin1String("GET") &&
1426 method != QLatin1String("PUT") &&
1427 method != QLatin1String("HEAD") &&
1428 method != QLatin1String("POST"))
1429 THROW_DOM(SYNTAX_ERR, "Unsupported HTTP method type");
1430
1431
1432 // Argument 1 - URL
1433 QUrl url = QUrl::fromEncoded(context->argument(1).toString().toUtf8());
1434
1435 if (url.isRelative()) {
1436 url = QDeclarativeScriptEngine::get(engine)->resolvedUrl(context,url);
1437 }
1438
1439 // Argument 2 - async (optional)
1440 if (context->argumentCount() > 2 && !context->argument(2).toBoolean())
1441 THROW_DOM(NOT_SUPPORTED_ERR, "Synchronous XMLHttpRequest calls are not supported");
1442
1443
1444 // Argument 3/4 - user/pass (optional)
1445 QString username, password;
1446 if (context->argumentCount() > 3)
1447 username = context->argument(3).toString();
1448 if (context->argumentCount() > 4)
1449 password = context->argument(4).toString();
1450
1451
1452 // Clear the fragment (if any)
1453 url.setFragment(QString());
1454 // Set username/password
1455 if (!username.isNull()) url.setUserName(username);
1456 if (!password.isNull()) url.setPassword(password);
1457
1458 return request->open(&dataObject, method, url);
1459}
1460
1461static QScriptValue qmlxmlhttprequest_setRequestHeader(QScriptContext *context, QScriptEngine *engine)
1462{
1463 QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject());
1464 if (!request)
1465 THROW_REFERENCE("Not an XMLHttpRequest object");
1466
1467 if (context->argumentCount() != 2)
1468 THROW_DOM(SYNTAX_ERR, "Incorrect argument count");
1469
1470
1471 if (request->readyState() != QDeclarativeXMLHttpRequest::Opened ||
1472 request->sendFlag())
1473 THROW_DOM(INVALID_STATE_ERR, "Invalid state");
1474
1475
1476 QString name = context->argument(0).toString();
1477 QString value = context->argument(1).toString();
1478
1479 // ### Check that name and value are well formed
1480
1481 QString nameUpper = name.toUpper();
1482 if (nameUpper == QLatin1String("ACCEPT-CHARSET") ||
1483 nameUpper == QLatin1String("ACCEPT-ENCODING") ||
1484 nameUpper == QLatin1String("CONNECTION") ||
1485 nameUpper == QLatin1String("CONTENT-LENGTH") ||
1486 nameUpper == QLatin1String("COOKIE") ||
1487 nameUpper == QLatin1String("COOKIE2") ||
1488 nameUpper == QLatin1String("CONTENT-TRANSFER-ENCODING") ||
1489 nameUpper == QLatin1String("DATE") ||
1490 nameUpper == QLatin1String("EXPECT") ||
1491 nameUpper == QLatin1String("HOST") ||
1492 nameUpper == QLatin1String("KEEP-ALIVE") ||
1493 nameUpper == QLatin1String("REFERER") ||
1494 nameUpper == QLatin1String("TE") ||
1495 nameUpper == QLatin1String("TRAILER") ||
1496 nameUpper == QLatin1String("TRANSFER-ENCODING") ||
1497 nameUpper == QLatin1String("UPGRADE") ||
1498 nameUpper == QLatin1String("USER-AGENT") ||
1499 nameUpper == QLatin1String("VIA") ||
1500 nameUpper.startsWith(QLatin1String("PROXY-")) ||
1501 nameUpper.startsWith(QLatin1String("SEC-")))
1502 return engine->undefinedValue();
1503
1504 request->addHeader(nameUpper, value);
1505
1506 return engine->undefinedValue();
1507}
1508
1509static QScriptValue qmlxmlhttprequest_send(QScriptContext *context, QScriptEngine *)
1510{
1511 QScriptValue dataObject = context->thisObject().data();
1512 QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(dataObject.toQObject());
1513 if (!request)
1514 THROW_REFERENCE("Not an XMLHttpRequest object");
1515
1516 if (request->readyState() != QDeclarativeXMLHttpRequest::Opened)
1517 THROW_DOM(INVALID_STATE_ERR, "Invalid state");
1518
1519 if (request->sendFlag())
1520 THROW_DOM(INVALID_STATE_ERR, "Invalid state");
1521
1522 QByteArray data;
1523 if (context->argumentCount() > 0)
1524 data = context->argument(0).toString().toUtf8();
1525
1526 return request->send(&dataObject, data);
1527}
1528
1529static QScriptValue qmlxmlhttprequest_abort(QScriptContext *context, QScriptEngine *)
1530{
1531 QScriptValue dataObject = context->thisObject().data();
1532 QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(dataObject.toQObject());
1533 if (!request)
1534 THROW_REFERENCE("Not an XMLHttpRequest object");
1535
1536 return request->abort(&dataObject);
1537}
1538
1539static QScriptValue qmlxmlhttprequest_getResponseHeader(QScriptContext *context, QScriptEngine *engine)
1540{
1541 Q_UNUSED(engine)
1542 QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject());
1543 if (!request)
1544 THROW_REFERENCE("Not an XMLHttpRequest object");
1545
1546 if (context->argumentCount() != 1)
1547 THROW_DOM(SYNTAX_ERR, "Incorrect argument count");
1548
1549 if (request->readyState() != QDeclarativeXMLHttpRequest::Loading &&
1550 request->readyState() != QDeclarativeXMLHttpRequest::Done &&
1551 request->readyState() != QDeclarativeXMLHttpRequest::HeadersReceived)
1552 THROW_DOM(INVALID_STATE_ERR, "Invalid state");
1553
1554 QString headerName = context->argument(0).toString();
1555
1556 return QScriptValue(request->header(headerName));
1557}
1558
1559static QScriptValue qmlxmlhttprequest_getAllResponseHeaders(QScriptContext *context, QScriptEngine *engine)
1560{
1561 Q_UNUSED(engine)
1562 QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject());
1563 if (!request)
1564 THROW_REFERENCE("Not an XMLHttpRequest object");
1565
1566 if (context->argumentCount() != 0)
1567 THROW_DOM(SYNTAX_ERR, "Incorrect argument count");
1568
1569 if (request->readyState() != QDeclarativeXMLHttpRequest::Loading &&
1570 request->readyState() != QDeclarativeXMLHttpRequest::Done &&
1571 request->readyState() != QDeclarativeXMLHttpRequest::HeadersReceived)
1572 THROW_DOM(INVALID_STATE_ERR, "Invalid state");
1573
1574 return QScriptValue(request->headers());
1575}
1576
1577// XMLHttpRequest properties
1578static QScriptValue qmlxmlhttprequest_readyState(QScriptContext *context, QScriptEngine *engine)
1579{
1580 Q_UNUSED(engine)
1581 QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject());
1582 if (!request)
1583 THROW_REFERENCE("Not an XMLHttpRequest object");
1584
1585 return QScriptValue(request->readyState());
1586}
1587
1588static QScriptValue qmlxmlhttprequest_status(QScriptContext *context, QScriptEngine *engine)
1589{
1590 Q_UNUSED(engine)
1591 QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject());
1592 if (!request)
1593 THROW_REFERENCE("Not an XMLHttpRequest object");
1594
1595 if (request->readyState() == QDeclarativeXMLHttpRequest::Unsent ||
1596 request->readyState() == QDeclarativeXMLHttpRequest::Opened)
1597 THROW_DOM(INVALID_STATE_ERR, "Invalid state");
1598
1599 if (request->errorFlag())
1600 return QScriptValue(0);
1601 else
1602 return QScriptValue(request->replyStatus());
1603}
1604
1605static QScriptValue qmlxmlhttprequest_statusText(QScriptContext *context, QScriptEngine *engine)
1606{
1607 Q_UNUSED(engine)
1608 QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject());
1609 if (!request)
1610 THROW_REFERENCE("Not an XMLHttpRequest object");
1611
1612 if (request->readyState() == QDeclarativeXMLHttpRequest::Unsent ||
1613 request->readyState() == QDeclarativeXMLHttpRequest::Opened)
1614 THROW_DOM(INVALID_STATE_ERR, "Invalid state");
1615
1616 if (request->errorFlag())
1617 return QScriptValue(0);
1618 else
1619 return QScriptValue(request->replyStatusText());
1620}
1621
1622static QScriptValue qmlxmlhttprequest_responseText(QScriptContext *context, QScriptEngine *engine)
1623{
1624 Q_UNUSED(engine)
1625 QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject());
1626 if (!request)
1627 THROW_REFERENCE("Not an XMLHttpRequest object");
1628
1629 if (request->readyState() != QDeclarativeXMLHttpRequest::Loading &&
1630 request->readyState() != QDeclarativeXMLHttpRequest::Done)
1631 return QScriptValue(QString());
1632 else
1633 return QScriptValue(request->responseBody());
1634}
1635
1636static QScriptValue qmlxmlhttprequest_responseXML(QScriptContext *context, QScriptEngine *engine)
1637{
1638 QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject());
1639 if (!request)
1640 THROW_REFERENCE("Not an XMLHttpRequest object");
1641
1642 if (!request->receivedXml() ||
1643 (request->readyState() != QDeclarativeXMLHttpRequest::Loading &&
1644 request->readyState() != QDeclarativeXMLHttpRequest::Done))
1645 return engine->nullValue();
1646 else
1647 return Document::load(engine, request->rawResponseBody());
1648}
1649
1650static QScriptValue qmlxmlhttprequest_onreadystatechange(QScriptContext *context, QScriptEngine *engine)
1651{
1652 Q_UNUSED(engine);
1653 QScriptValue dataObject = context->thisObject().data();
1654 QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(dataObject.toQObject());
1655 if (!request)
1656 THROW_REFERENCE("Not an XMLHttpRequest object");
1657
1658 if (context->argumentCount()) {
1659 QScriptValue v = context->argument(0);
1660 dataObject.setProperty(QLatin1String("callback"), v);
1661 return v;
1662 } else {
1663 return dataObject.property(QLatin1String("callback"));
1664 }
1665}
1666
1667// Constructor
1668static QScriptValue qmlxmlhttprequest_new(QScriptContext *context, QScriptEngine *engine)
1669{
1670 if (context->isCalledAsConstructor()) {
1671 context->thisObject().setData(engine->newQObject(new QDeclarativeXMLHttpRequest(QDeclarativeScriptEngine::get(engine)->networkAccessManager()), QScriptEngine::ScriptOwnership));
1672 }
1673 return engine->undefinedValue();
1674}
1675
1676void qt_add_qmlxmlhttprequest(QScriptEngine *engine)
1677{
1678 QScriptValue prototype = engine->newObject();
1679
1680 // Methods
1681 prototype.setProperty(QLatin1String("open"), engine->newFunction(qmlxmlhttprequest_open, 2));
1682 prototype.setProperty(QLatin1String("setRequestHeader"), engine->newFunction(qmlxmlhttprequest_setRequestHeader, 2));
1683 prototype.setProperty(QLatin1String("send"), engine->newFunction(qmlxmlhttprequest_send));
1684 prototype.setProperty(QLatin1String("abort"), engine->newFunction(qmlxmlhttprequest_abort));
1685 prototype.setProperty(QLatin1String("getResponseHeader"), engine->newFunction(qmlxmlhttprequest_getResponseHeader, 1));
1686 prototype.setProperty(QLatin1String("getAllResponseHeaders"), engine->newFunction(qmlxmlhttprequest_getAllResponseHeaders));
1687
1688 // Read-only properties
1689 prototype.setProperty(QLatin1String("readyState"), engine->newFunction(qmlxmlhttprequest_readyState), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
1690 prototype.setProperty(QLatin1String("status"), engine->newFunction(qmlxmlhttprequest_status), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
1691 prototype.setProperty(QLatin1String("statusText"), engine->newFunction(qmlxmlhttprequest_statusText), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
1692 prototype.setProperty(QLatin1String("responseText"), engine->newFunction(qmlxmlhttprequest_responseText), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
1693 prototype.setProperty(QLatin1String("responseXML"), engine->newFunction(qmlxmlhttprequest_responseXML), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
1694 prototype.setProperty(QLatin1String("onreadystatechange"), engine->newFunction(qmlxmlhttprequest_onreadystatechange), QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
1695
1696 // State values
1697 prototype.setProperty(QLatin1String("UNSENT"), 0, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
1698 prototype.setProperty(QLatin1String("OPENED"), 1, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
1699 prototype.setProperty(QLatin1String("HEADERS_RECEIVED"), 2, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
1700 prototype.setProperty(QLatin1String("LOADING"), 3, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
1701 prototype.setProperty(QLatin1String("DONE"), 4, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
1702
1703 // Constructor
1704 QScriptValue constructor = engine->newFunction(qmlxmlhttprequest_new, prototype);
1705 constructor.setProperty(QLatin1String("UNSENT"), 0, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
1706 constructor.setProperty(QLatin1String("OPENED"), 1, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
1707 constructor.setProperty(QLatin1String("HEADERS_RECEIVED"), 2, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
1708 constructor.setProperty(QLatin1String("LOADING"), 3, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
1709 constructor.setProperty(QLatin1String("DONE"), 4, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
1710 engine->globalObject().setProperty(QLatin1String("XMLHttpRequest"), constructor);
1711
1712 // DOM Exception
1713 QScriptValue domExceptionPrototype = engine->newObject();
1714 domExceptionPrototype.setProperty(QLatin1String("INDEX_SIZE_ERR"), INDEX_SIZE_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
1715 domExceptionPrototype.setProperty(QLatin1String("DOMSTRING_SIZE_ERR"), DOMSTRING_SIZE_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
1716 domExceptionPrototype.setProperty(QLatin1String("HIERARCHY_REQUEST_ERR"), HIERARCHY_REQUEST_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
1717 domExceptionPrototype.setProperty(QLatin1String("WRONG_DOCUMENT_ERR"), WRONG_DOCUMENT_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
1718 domExceptionPrototype.setProperty(QLatin1String("INVALID_CHARACTER_ERR"), INVALID_CHARACTER_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
1719 domExceptionPrototype.setProperty(QLatin1String("NO_DATA_ALLOWED_ERR"), NO_DATA_ALLOWED_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
1720 domExceptionPrototype.setProperty(QLatin1String("NO_MODIFICATION_ALLOWED_ERR"), NO_MODIFICATION_ALLOWED_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
1721 domExceptionPrototype.setProperty(QLatin1String("NOT_FOUND_ERR"), NOT_FOUND_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
1722 domExceptionPrototype.setProperty(QLatin1String("NOT_SUPPORTED_ERR"), NOT_SUPPORTED_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
1723 domExceptionPrototype.setProperty(QLatin1String("INUSE_ATTRIBUTE_ERR"), INUSE_ATTRIBUTE_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
1724 domExceptionPrototype.setProperty(QLatin1String("INVALID_STATE_ERR"), INVALID_STATE_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
1725 domExceptionPrototype.setProperty(QLatin1String("SYNTAX_ERR"), SYNTAX_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
1726 domExceptionPrototype.setProperty(QLatin1String("INVALID_MODIFICATION_ERR"), INVALID_MODIFICATION_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
1727 domExceptionPrototype.setProperty(QLatin1String("NAMESPACE_ERR"), NAMESPACE_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
1728 domExceptionPrototype.setProperty(QLatin1String("INVALID_ACCESS_ERR"), INVALID_ACCESS_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
1729 domExceptionPrototype.setProperty(QLatin1String("VALIDATION_ERR"), VALIDATION_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
1730 domExceptionPrototype.setProperty(QLatin1String("TYPE_MISMATCH_ERR"), TYPE_MISMATCH_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
1731
1732 engine->globalObject().setProperty(QLatin1String("DOMException"), domExceptionPrototype);
1733}
1734
1735QT_END_NAMESPACE
1736
1737#endif // QT_NO_XMLSTREAMREADER
1738
1739#include <qdeclarativexmlhttprequest.moc>
Note: See TracBrowser for help on using the repository browser.