1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtQml module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qqmlxmlhttprequest_p.h"
41
42#include "qqmlengine.h"
43#include "qqmlengine_p.h"
44#include <private/qqmlrefcount_p.h>
45#include "qqmlengine_p.h"
46#include "qqmlexpression_p.h"
47#include "qqmlglobal_p.h"
48#include <private/qv4domerrors_p.h>
49#include <private/qv4engine_p.h>
50#include <private/qv4functionobject_p.h>
51#include <private/qv4scopedvalue_p.h>
52#include <private/qv4jscall_p.h>
53
54#include <QtCore/qobject.h>
55#include <QtQml/qjsvalue.h>
56#include <QtQml/qjsengine.h>
57#include <QtQml/qqmlfile.h>
58#include <QtNetwork/qnetworkreply.h>
59#include <QtCore/qtextcodec.h>
60#include <QtCore/qxmlstream.h>
61#include <QtCore/qstack.h>
62#include <QtCore/qdebug.h>
63#include <QtCore/qbuffer.h>
64
65#include <private/qv4objectproto_p.h>
66#include <private/qv4scopedvalue_p.h>
67#include <private/qv4arraybuffer_p.h>
68#include <private/qv4jsonobject_p.h>
69
70using namespace QV4;
71
72#define V4THROW_REFERENCE(string) \
73 do { \
74 ScopedObject error(scope, scope.engine->newReferenceErrorObject(QStringLiteral(string))); \
75 return scope.engine->throwError(error); \
76 } while (false)
77
78QT_BEGIN_NAMESPACE
79
80DEFINE_BOOL_CONFIG_OPTION(xhrDump, QML_XHR_DUMP);
81DEFINE_BOOL_CONFIG_OPTION(xhrFileWrite, QML_XHR_ALLOW_FILE_WRITE);
82DEFINE_BOOL_CONFIG_OPTION(xhrFileRead, QML_XHR_ALLOW_FILE_READ);
83
84struct QQmlXMLHttpRequestData {
85 QQmlXMLHttpRequestData();
86 ~QQmlXMLHttpRequestData();
87
88 PersistentValue nodeFunction;
89
90 PersistentValue nodePrototype;
91 PersistentValue elementPrototype;
92 PersistentValue attrPrototype;
93 PersistentValue characterDataPrototype;
94 PersistentValue textPrototype;
95 PersistentValue cdataPrototype;
96 PersistentValue documentPrototype;
97};
98
99static inline QQmlXMLHttpRequestData *xhrdata(ExecutionEngine *v4)
100{
101 return (QQmlXMLHttpRequestData *)v4->xmlHttpRequestData();
102}
103
104QQmlXMLHttpRequestData::QQmlXMLHttpRequestData()
105{
106}
107
108QQmlXMLHttpRequestData::~QQmlXMLHttpRequestData()
109{
110}
111
112namespace QV4 {
113
114class DocumentImpl;
115class NodeImpl
116{
117public:
118 NodeImpl() : type(Element), document(nullptr), parent(nullptr) {}
119 virtual ~NodeImpl() {
120 qDeleteAll(c: children);
121 qDeleteAll(c: attributes);
122 }
123
124 // These numbers are copied from the Node IDL definition
125 enum Type {
126 Attr = 2,
127 CDATA = 4,
128 Comment = 8,
129 Document = 9,
130 DocumentFragment = 11,
131 DocumentType = 10,
132 Element = 1,
133 Entity = 6,
134 EntityReference = 5,
135 Notation = 12,
136 ProcessingInstruction = 7,
137 Text = 3
138 };
139 Type type;
140
141 QString namespaceUri;
142 QString name;
143
144 QString data;
145
146 void addref();
147 void release();
148
149 DocumentImpl *document;
150 NodeImpl *parent;
151
152 QList<NodeImpl *> children;
153 QList<NodeImpl *> attributes;
154};
155
156class DocumentImpl : public QQmlRefCount, public NodeImpl
157{
158public:
159 DocumentImpl() : root(nullptr) { type = Document; }
160 virtual ~DocumentImpl() {
161 delete root;
162 }
163
164 QString version;
165 QString encoding;
166 bool isStandalone;
167
168 NodeImpl *root;
169
170 void addref() { QQmlRefCount::addref(); }
171 void release() { QQmlRefCount::release(); }
172};
173
174namespace Heap {
175
176struct NamedNodeMap : Object {
177 void init(NodeImpl *data, const QList<NodeImpl *> &list);
178 void destroy() {
179 delete listPtr;
180 if (d)
181 d->release();
182 Object::destroy();
183 }
184 QList<NodeImpl *> &list() {
185 if (listPtr == nullptr)
186 listPtr = new QList<NodeImpl *>;
187 return *listPtr;
188 }
189
190 QList<NodeImpl *> *listPtr; // Only used in NamedNodeMap
191 NodeImpl *d;
192};
193
194struct NodeList : Object {
195 void init(NodeImpl *data);
196 void destroy() {
197 if (d)
198 d->release();
199 Object::destroy();
200 }
201 NodeImpl *d;
202};
203
204struct NodePrototype : Object {
205 void init();
206};
207
208struct Node : Object {
209 void init(NodeImpl *data);
210 void destroy() {
211 if (d)
212 d->release();
213 Object::destroy();
214 }
215 NodeImpl *d;
216};
217
218}
219
220class NamedNodeMap : public Object
221{
222public:
223 V4_OBJECT2(NamedNodeMap, Object)
224 V4_NEEDS_DESTROY
225
226 // C++ API
227 static ReturnedValue create(ExecutionEngine *, NodeImpl *, const QList<NodeImpl *> &);
228
229 // JS API
230 static ReturnedValue virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty);
231};
232
233void Heap::NamedNodeMap::init(NodeImpl *data, const QList<NodeImpl *> &list)
234{
235 Object::init();
236 d = data;
237 this->list() = list;
238 if (d)
239 d->addref();
240}
241
242DEFINE_OBJECT_VTABLE(NamedNodeMap);
243
244class NodeList : public Object
245{
246public:
247 V4_OBJECT2(NodeList, Object)
248 V4_NEEDS_DESTROY
249
250 // JS API
251 static ReturnedValue virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty);
252
253 // C++ API
254 static ReturnedValue create(ExecutionEngine *, NodeImpl *);
255
256};
257
258void Heap::NodeList::init(NodeImpl *data)
259{
260 Object::init();
261 d = data;
262 if (d)
263 d->addref();
264}
265
266DEFINE_OBJECT_VTABLE(NodeList);
267
268class NodePrototype : public Object
269{
270public:
271 V4_OBJECT2(NodePrototype, Object)
272
273 static void initClass(ExecutionEngine *engine);
274
275 // JS API
276 static ReturnedValue method_get_nodeName(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
277 static ReturnedValue method_get_nodeValue(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
278 static ReturnedValue method_get_nodeType(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
279 static ReturnedValue method_get_namespaceUri(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
280
281 static ReturnedValue method_get_parentNode(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
282 static ReturnedValue method_get_childNodes(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
283 static ReturnedValue method_get_firstChild(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
284 static ReturnedValue method_get_lastChild(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
285 static ReturnedValue method_get_previousSibling(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
286 static ReturnedValue method_get_nextSibling(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
287 static ReturnedValue method_get_attributes(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
288
289 //static ReturnedValue ownerDocument(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
290 //static ReturnedValue namespaceURI(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
291 //static ReturnedValue prefix(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
292 //static ReturnedValue localName(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
293 //static ReturnedValue baseURI(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
294 //static ReturnedValue textContent(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
295
296 static ReturnedValue getProto(ExecutionEngine *v4);
297
298};
299
300void Heap::NodePrototype::init()
301{
302 Object::init();
303 Scope scope(internalClass->engine);
304 ScopedObject o(scope, this);
305
306 o->defineAccessorProperty(QStringLiteral("nodeName"), getter: QV4::NodePrototype::method_get_nodeName, setter: nullptr);
307 o->defineAccessorProperty(QStringLiteral("nodeValue"), getter: QV4::NodePrototype::method_get_nodeValue, setter: nullptr);
308 o->defineAccessorProperty(QStringLiteral("nodeType"), getter: QV4::NodePrototype::method_get_nodeType, setter: nullptr);
309 o->defineAccessorProperty(QStringLiteral("namespaceUri"), getter: QV4::NodePrototype::method_get_namespaceUri, setter: nullptr);
310
311 o->defineAccessorProperty(QStringLiteral("parentNode"), getter: QV4::NodePrototype::method_get_parentNode, setter: nullptr);
312 o->defineAccessorProperty(QStringLiteral("childNodes"), getter: QV4::NodePrototype::method_get_childNodes, setter: nullptr);
313 o->defineAccessorProperty(QStringLiteral("firstChild"), getter: QV4::NodePrototype::method_get_firstChild, setter: nullptr);
314 o->defineAccessorProperty(QStringLiteral("lastChild"), getter: QV4::NodePrototype::method_get_lastChild, setter: nullptr);
315 o->defineAccessorProperty(QStringLiteral("previousSibling"), getter: QV4::NodePrototype::method_get_previousSibling, setter: nullptr);
316 o->defineAccessorProperty(QStringLiteral("nextSibling"), getter: QV4::NodePrototype::method_get_nextSibling, setter: nullptr);
317 o->defineAccessorProperty(QStringLiteral("attributes"), getter: QV4::NodePrototype::method_get_attributes, setter: nullptr);
318}
319
320
321DEFINE_OBJECT_VTABLE(NodePrototype);
322
323struct Node : public Object
324{
325 V4_OBJECT2(Node, Object)
326 V4_NEEDS_DESTROY
327
328 // C++ API
329 static ReturnedValue create(ExecutionEngine *v4, NodeImpl *);
330
331 bool isNull() const;
332};
333
334void Heap::Node::init(NodeImpl *data)
335{
336 Object::init();
337 d = data;
338 if (d)
339 d->addref();
340}
341
342DEFINE_OBJECT_VTABLE(Node);
343
344class Element : public Node
345{
346public:
347 // C++ API
348 static ReturnedValue prototype(ExecutionEngine *);
349};
350
351class Attr : public Node
352{
353public:
354 // JS API
355 static ReturnedValue method_name(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
356// static void specified(CallContext *);
357 static ReturnedValue method_value(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
358 static ReturnedValue method_ownerElement(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
359// static void schemaTypeInfo(CallContext *);
360// static void isId(CallContext *c);
361
362 // C++ API
363 static ReturnedValue prototype(ExecutionEngine *);
364};
365
366class CharacterData : public Node
367{
368public:
369 // JS API
370 static ReturnedValue method_length(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
371
372 // C++ API
373 static ReturnedValue prototype(ExecutionEngine *v4);
374};
375
376class Text : public CharacterData
377{
378public:
379 // JS API
380 static ReturnedValue method_isElementContentWhitespace(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
381 static ReturnedValue method_wholeText(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
382
383 // C++ API
384 static ReturnedValue prototype(ExecutionEngine *);
385};
386
387class CDATA : public Text
388{
389public:
390 // C++ API
391 static ReturnedValue prototype(ExecutionEngine *v4);
392};
393
394class Document : public Node
395{
396public:
397 // JS API
398 static ReturnedValue method_xmlVersion(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
399 static ReturnedValue method_xmlEncoding(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
400 static ReturnedValue method_xmlStandalone(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
401 static ReturnedValue method_documentElement(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
402
403 // C++ API
404 static ReturnedValue prototype(ExecutionEngine *);
405 static ReturnedValue load(ExecutionEngine *engine, const QByteArray &data);
406};
407
408}
409
410void NodeImpl::addref()
411{
412 document->addref();
413}
414
415void NodeImpl::release()
416{
417 document->release();
418}
419
420ReturnedValue NodePrototype::method_get_nodeName(const FunctionObject *b, const Value *thisObject, const Value *, int)
421{
422 Scope scope(b);
423 Scoped<Node> r(scope, thisObject->as<Node>());
424 if (!r)
425 THROW_TYPE_ERROR();
426
427 QString name;
428 switch (r->d()->d->type) {
429 case NodeImpl::Document:
430 name = QStringLiteral("#document");
431 break;
432 case NodeImpl::CDATA:
433 name = QStringLiteral("#cdata-section");
434 break;
435 case NodeImpl::Text:
436 name = QStringLiteral("#text");
437 break;
438 default:
439 name = r->d()->d->name;
440 break;
441 }
442 return Encode(scope.engine->newString(s: name));
443}
444
445ReturnedValue NodePrototype::method_get_nodeValue(const FunctionObject *b, const Value *thisObject, const Value *, int)
446{
447 QV4::Scope scope(b);
448 Scoped<Node> r(scope, thisObject->as<Node>());
449 if (!r)
450 THROW_TYPE_ERROR();
451
452 if (r->d()->d->type == NodeImpl::Document ||
453 r->d()->d->type == NodeImpl::DocumentFragment ||
454 r->d()->d->type == NodeImpl::DocumentType ||
455 r->d()->d->type == NodeImpl::Element ||
456 r->d()->d->type == NodeImpl::Entity ||
457 r->d()->d->type == NodeImpl::EntityReference ||
458 r->d()->d->type == NodeImpl::Notation)
459 RETURN_RESULT(Encode::null());
460
461 return Encode(scope.engine->newString(s: r->d()->d->data));
462}
463
464ReturnedValue NodePrototype::method_get_nodeType(const FunctionObject *b, const Value *thisObject, const Value *, int)
465{
466 QV4::Scope scope(b);
467 Scoped<Node> r(scope, thisObject->as<Node>());
468 if (!r)
469 THROW_TYPE_ERROR();
470
471 return Encode(r->d()->d->type);
472}
473
474ReturnedValue NodePrototype::method_get_namespaceUri(const FunctionObject *b, const Value *thisObject, const Value *, int)
475{
476 QV4::Scope scope(b);
477 Scoped<Node> r(scope, thisObject->as<Node>());
478 if (!r)
479 THROW_TYPE_ERROR();
480
481 return Encode(scope.engine->newString(s: r->d()->d->namespaceUri));
482}
483
484ReturnedValue NodePrototype::method_get_parentNode(const FunctionObject *b, const Value *thisObject, const Value *, int)
485{
486 QV4::Scope scope(b);
487 Scoped<Node> r(scope, thisObject->as<Node>());
488 if (!r)
489 THROW_TYPE_ERROR();
490
491 if (r->d()->d->parent)
492 return Node::create(v4: scope.engine, r->d()->d->parent);
493 else
494 return Encode::null();
495}
496
497ReturnedValue NodePrototype::method_get_childNodes(const FunctionObject *b, const Value *thisObject, const Value *, int)
498{
499 QV4::Scope scope(b);
500 Scoped<Node> r(scope, thisObject->as<Node>());
501 if (!r)
502 THROW_TYPE_ERROR();
503
504 return NodeList::create(scope.engine, r->d()->d);
505}
506
507ReturnedValue NodePrototype::method_get_firstChild(const FunctionObject *b, const Value *thisObject, const Value *, int)
508{
509 QV4::Scope scope(b);
510 Scoped<Node> r(scope, thisObject->as<Node>());
511 if (!r)
512 THROW_TYPE_ERROR();
513
514 if (r->d()->d->children.isEmpty())
515 return Encode::null();
516 else
517 return Node::create(v4: scope.engine, r->d()->d->children.constFirst());
518}
519
520ReturnedValue NodePrototype::method_get_lastChild(const FunctionObject *b, const Value *thisObject, const Value *, int)
521{
522 QV4::Scope scope(b);
523 Scoped<Node> r(scope, thisObject->as<Node>());
524 if (!r)
525 THROW_TYPE_ERROR();
526
527 if (r->d()->d->children.isEmpty())
528 return Encode::null();
529 else
530 return Node::create(v4: scope.engine, r->d()->d->children.constLast());
531}
532
533ReturnedValue NodePrototype::method_get_previousSibling(const FunctionObject *b, const Value *thisObject, const Value *, int)
534{
535 QV4::Scope scope(b);
536 Scoped<Node> r(scope, thisObject->as<Node>());
537 if (!r)
538 THROW_TYPE_ERROR();
539
540 if (!r->d()->d->parent)
541 RETURN_RESULT(Encode::null());
542
543 for (int ii = 0; ii < r->d()->d->parent->children.count(); ++ii) {
544 if (r->d()->d->parent->children.at(i: ii) == r->d()->d) {
545 if (ii == 0)
546 return Encode::null();
547 else
548 return Node::create(v4: scope.engine, r->d()->d->parent->children.at(i: ii - 1));
549 }
550 }
551
552 return Encode::null();
553}
554
555ReturnedValue NodePrototype::method_get_nextSibling(const FunctionObject *b, const Value *thisObject, const Value *, int)
556{
557 QV4::Scope scope(b);
558 Scoped<Node> r(scope, thisObject->as<Node>());
559 if (!r)
560 THROW_TYPE_ERROR();
561
562 if (!r->d()->d->parent)
563 RETURN_RESULT(Encode::null());
564
565 for (int ii = 0; ii < r->d()->d->parent->children.count(); ++ii) {
566 if (r->d()->d->parent->children.at(i: ii) == r->d()->d) {
567 if ((ii + 1) == r->d()->d->parent->children.count())
568 return Encode::null();
569 else
570 return Node::create(v4: scope.engine, r->d()->d->parent->children.at(i: ii + 1));
571 }
572 }
573
574 return Encode::null();
575}
576
577ReturnedValue NodePrototype::method_get_attributes(const FunctionObject *b, const Value *thisObject, const Value *, int)
578{
579 QV4::Scope scope(b);
580 Scoped<Node> r(scope, thisObject->as<Node>());
581 if (!r)
582 THROW_TYPE_ERROR();
583
584 if (r->d()->d->type != NodeImpl::Element)
585 return Encode::null();
586 else
587 return NamedNodeMap::create(scope.engine, r->d()->d, r->d()->d->attributes);
588}
589
590ReturnedValue NodePrototype::getProto(ExecutionEngine *v4)
591{
592 Scope scope(v4);
593 QQmlXMLHttpRequestData *d = xhrdata(v4);
594 if (d->nodePrototype.isUndefined()) {
595 ScopedObject p(scope, v4->memoryManager->allocate<NodePrototype>());
596 d->nodePrototype.set(engine: v4, value: p);
597 v4->freezeObject(value: p);
598 }
599 return d->nodePrototype.value();
600}
601
602ReturnedValue Node::create(ExecutionEngine *v4, NodeImpl *data)
603{
604 Scope scope(v4);
605
606 Scoped<Node> instance(scope, v4->memoryManager->allocate<Node>(args: data));
607 ScopedObject p(scope);
608
609 switch (data->type) {
610 case NodeImpl::Attr:
611 instance->setPrototypeUnchecked((p = Attr::prototype(v4)));
612 break;
613 case NodeImpl::Comment:
614 case NodeImpl::Document:
615 case NodeImpl::DocumentFragment:
616 case NodeImpl::DocumentType:
617 case NodeImpl::Entity:
618 case NodeImpl::EntityReference:
619 case NodeImpl::Notation:
620 case NodeImpl::ProcessingInstruction:
621 return Encode::undefined();
622 case NodeImpl::CDATA:
623 instance->setPrototypeUnchecked((p = CDATA::prototype(v4)));
624 break;
625 case NodeImpl::Text:
626 instance->setPrototypeUnchecked((p = Text::prototype(v4)));
627 break;
628 case NodeImpl::Element:
629 instance->setPrototypeUnchecked((p = Element::prototype(v4)));
630 break;
631 }
632
633 return instance.asReturnedValue();
634}
635
636ReturnedValue Element::prototype(ExecutionEngine *engine)
637{
638 QQmlXMLHttpRequestData *d = xhrdata(v4: engine);
639 if (d->elementPrototype.isUndefined()) {
640 Scope scope(engine);
641 ScopedObject p(scope, engine->newObject());
642 ScopedObject pp(scope);
643 p->setPrototypeUnchecked((pp = NodePrototype::getProto(v4: engine)));
644 p->defineAccessorProperty(QStringLiteral("tagName"), getter: NodePrototype::method_get_nodeName, setter: nullptr);
645 d->elementPrototype.set(engine, value: p);
646 engine->freezeObject(value: p);
647 }
648 return d->elementPrototype.value();
649}
650
651ReturnedValue Attr::prototype(ExecutionEngine *engine)
652{
653 QQmlXMLHttpRequestData *d = xhrdata(v4: engine);
654 if (d->attrPrototype.isUndefined()) {
655 Scope scope(engine);
656 ScopedObject p(scope, engine->newObject());
657 ScopedObject pp(scope);
658 p->setPrototypeUnchecked((pp = NodePrototype::getProto(v4: engine)));
659 p->defineAccessorProperty(QStringLiteral("name"), getter: method_name, setter: nullptr);
660 p->defineAccessorProperty(QStringLiteral("value"), getter: method_value, setter: nullptr);
661 p->defineAccessorProperty(QStringLiteral("ownerElement"), getter: method_ownerElement, setter: nullptr);
662 d->attrPrototype.set(engine, value: p);
663 engine->freezeObject(value: p);
664 }
665 return d->attrPrototype.value();
666}
667
668ReturnedValue Attr::method_name(const FunctionObject *b, const Value *thisObject, const Value *, int)
669{
670 QV4::Scope scope(b);
671 Scoped<Node> r(scope, thisObject->as<Node>());
672 if (!r)
673 RETURN_UNDEFINED();
674
675 return Encode(scope.engine->newString(s: r->d()->d->name));
676}
677
678ReturnedValue Attr::method_value(const FunctionObject *b, const Value *thisObject, const Value *, int)
679{
680 QV4::Scope scope(b);
681 Scoped<Node> r(scope, thisObject->as<Node>());
682 if (!r)
683 RETURN_UNDEFINED();
684
685 return Encode(scope.engine->newString(s: r->d()->d->data));
686}
687
688ReturnedValue Attr::method_ownerElement(const FunctionObject *b, const Value *thisObject, const Value *, int)
689{
690 QV4::Scope scope(b);
691 Scoped<Node> r(scope, thisObject->as<Node>());
692 if (!r)
693 RETURN_UNDEFINED();
694
695 return Node::create(v4: scope.engine, data: r->d()->d->parent);
696}
697
698ReturnedValue CharacterData::method_length(const FunctionObject *b, const Value *thisObject, const Value *, int)
699{
700 QV4::Scope scope(b);
701 Scoped<Node> r(scope, thisObject->as<Node>());
702 if (!r)
703 RETURN_UNDEFINED();
704
705 return Encode(r->d()->d->data.length());
706}
707
708ReturnedValue CharacterData::prototype(ExecutionEngine *v4)
709{
710 QQmlXMLHttpRequestData *d = xhrdata(v4);
711 if (d->characterDataPrototype.isUndefined()) {
712 Scope scope(v4);
713 ScopedObject p(scope, v4->newObject());
714 ScopedObject pp(scope);
715 p->setPrototypeUnchecked((pp = NodePrototype::getProto(v4)));
716 p->defineAccessorProperty(QStringLiteral("data"), getter: NodePrototype::method_get_nodeValue, setter: nullptr);
717 p->defineAccessorProperty(QStringLiteral("length"), getter: method_length, setter: nullptr);
718 d->characterDataPrototype.set(engine: v4, value: p);
719 v4->freezeObject(value: p);
720 }
721 return d->characterDataPrototype.value();
722}
723
724ReturnedValue Text::method_isElementContentWhitespace(const FunctionObject *b, const Value *thisObject, const Value *, int)
725{
726 QV4::Scope scope(b);
727 Scoped<Node> r(scope, thisObject->as<Node>());
728 if (!r)
729 RETURN_UNDEFINED();
730
731 return Encode(QStringRef(&r->d()->d->data).trimmed().isEmpty());
732}
733
734ReturnedValue Text::method_wholeText(const FunctionObject *b, const Value *thisObject, const Value *, int)
735{
736 QV4::Scope scope(b);
737 Scoped<Node> r(scope, thisObject->as<Node>());
738 if (!r)
739 RETURN_UNDEFINED();
740
741 return Encode(scope.engine->newString(s: r->d()->d->data));
742}
743
744ReturnedValue Text::prototype(ExecutionEngine *v4)
745{
746 QQmlXMLHttpRequestData *d = xhrdata(v4);
747 if (d->textPrototype.isUndefined()) {
748 Scope scope(v4);
749 ScopedObject p(scope, v4->newObject());
750 ScopedObject pp(scope);
751 p->setPrototypeUnchecked((pp = CharacterData::prototype(v4)));
752 p->defineAccessorProperty(QStringLiteral("isElementContentWhitespace"), getter: method_isElementContentWhitespace, setter: nullptr);
753 p->defineAccessorProperty(QStringLiteral("wholeText"), getter: method_wholeText, setter: nullptr);
754 d->textPrototype.set(engine: v4, value: p);
755 v4->freezeObject(value: p);
756 }
757 return d->textPrototype.value();
758}
759
760ReturnedValue CDATA::prototype(ExecutionEngine *v4)
761{
762 // ### why not just use TextProto???
763 QQmlXMLHttpRequestData *d = xhrdata(v4);
764 if (d->cdataPrototype.isUndefined()) {
765 Scope scope(v4);
766 ScopedObject p(scope, v4->newObject());
767 ScopedObject pp(scope);
768 p->setPrototypeUnchecked((pp = Text::prototype(v4)));
769 d->cdataPrototype.set(engine: v4, value: p);
770 v4->freezeObject(value: p);
771 }
772 return d->cdataPrototype.value();
773}
774
775ReturnedValue Document::prototype(ExecutionEngine *v4)
776{
777 QQmlXMLHttpRequestData *d = xhrdata(v4);
778 if (d->documentPrototype.isUndefined()) {
779 Scope scope(v4);
780 ScopedObject p(scope, v4->newObject());
781 ScopedObject pp(scope);
782 p->setPrototypeUnchecked((pp = NodePrototype::getProto(v4)));
783 p->defineAccessorProperty(QStringLiteral("xmlVersion"), getter: method_xmlVersion, setter: nullptr);
784 p->defineAccessorProperty(QStringLiteral("xmlEncoding"), getter: method_xmlEncoding, setter: nullptr);
785 p->defineAccessorProperty(QStringLiteral("xmlStandalone"), getter: method_xmlStandalone, setter: nullptr);
786 p->defineAccessorProperty(QStringLiteral("documentElement"), getter: method_documentElement, setter: nullptr);
787 d->documentPrototype.set(engine: v4, value: p);
788 v4->freezeObject(value: p);
789 }
790 return d->documentPrototype.value();
791}
792
793ReturnedValue Document::load(ExecutionEngine *v4, const QByteArray &data)
794{
795 Scope scope(v4);
796
797 DocumentImpl *document = nullptr;
798 QStack<NodeImpl *> nodeStack;
799
800 QXmlStreamReader reader(data);
801
802 while (!reader.atEnd()) {
803 switch (reader.readNext()) {
804 case QXmlStreamReader::NoToken:
805 break;
806 case QXmlStreamReader::Invalid:
807 break;
808 case QXmlStreamReader::StartDocument:
809 Q_ASSERT(!document);
810 document = new DocumentImpl;
811 document->document = document;
812 document->version = reader.documentVersion().toString();
813 document->encoding = reader.documentEncoding().toString();
814 document->isStandalone = reader.isStandaloneDocument();
815 break;
816 case QXmlStreamReader::EndDocument:
817 break;
818 case QXmlStreamReader::StartElement:
819 {
820 Q_ASSERT(document);
821 NodeImpl *node = new NodeImpl;
822 node->document = document;
823 node->namespaceUri = reader.namespaceUri().toString();
824 node->name = reader.name().toString();
825 if (nodeStack.isEmpty()) {
826 document->root = node;
827 } else {
828 node->parent = nodeStack.top();
829 node->parent->children.append(t: node);
830 }
831 nodeStack.append(t: node);
832
833 const auto attributes = reader.attributes();
834 for (const QXmlStreamAttribute &a : attributes) {
835 NodeImpl *attr = new NodeImpl;
836 attr->document = document;
837 attr->type = NodeImpl::Attr;
838 attr->namespaceUri = a.namespaceUri().toString();
839 attr->name = a.name().toString();
840 attr->data = a.value().toString();
841 attr->parent = node;
842 node->attributes.append(t: attr);
843 }
844 }
845 break;
846 case QXmlStreamReader::EndElement:
847 nodeStack.pop();
848 break;
849 case QXmlStreamReader::Characters:
850 {
851 NodeImpl *node = new NodeImpl;
852 node->document = document;
853 node->type = reader.isCDATA()?NodeImpl::CDATA:NodeImpl::Text;
854 node->parent = nodeStack.top();
855 node->parent->children.append(t: node);
856 node->data = reader.text().toString();
857 }
858 break;
859 case QXmlStreamReader::Comment:
860 break;
861 case QXmlStreamReader::DTD:
862 break;
863 case QXmlStreamReader::EntityReference:
864 break;
865 case QXmlStreamReader::ProcessingInstruction:
866 break;
867 }
868 }
869
870 if (!document || reader.hasError()) {
871 if (document)
872 document->release();
873 return Encode::null();
874 }
875
876 ScopedObject instance(scope, v4->memoryManager->allocate<Node>(args: document));
877 document->release(); // the GC should own the NodeImpl via Node now
878 ScopedObject p(scope);
879 instance->setPrototypeUnchecked((p = Document::prototype(v4)));
880 return instance.asReturnedValue();
881}
882
883bool Node::isNull() const
884{
885 return d()->d == nullptr;
886}
887
888ReturnedValue NamedNodeMap::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
889{
890 Q_ASSERT(m->as<NamedNodeMap>());
891
892 const NamedNodeMap *r = static_cast<const NamedNodeMap *>(m);
893 QV4::ExecutionEngine *v4 = r->engine();
894
895 if (id.isArrayIndex()) {
896 uint index = id.asArrayIndex();
897
898 if ((int)index < r->d()->list().count()) {
899 if (hasProperty)
900 *hasProperty = true;
901 return Node::create(v4, data: r->d()->list().at(i: index));
902 }
903 if (hasProperty)
904 *hasProperty = false;
905 return Encode::undefined();
906 }
907
908 if (id.isSymbol())
909 return Object::virtualGet(m, id, receiver, hasProperty);
910
911 if (id == v4->id_length()->propertyKey())
912 return Value::fromInt32(i: r->d()->list().count()).asReturnedValue();
913
914 QString str = id.toQString();
915 for (int ii = 0; ii < r->d()->list().count(); ++ii) {
916 if (r->d()->list().at(i: ii)->name == str) {
917 if (hasProperty)
918 *hasProperty = true;
919 return Node::create(v4, data: r->d()->list().at(i: ii));
920 }
921 }
922
923 if (hasProperty)
924 *hasProperty = false;
925 return Encode::undefined();
926}
927
928ReturnedValue NamedNodeMap::create(ExecutionEngine *v4, NodeImpl *data, const QList<NodeImpl *> &list)
929{
930 return (v4->memoryManager->allocate<NamedNodeMap>(args: data, args: list))->asReturnedValue();
931}
932
933ReturnedValue NodeList::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
934{
935 Q_ASSERT(m->as<NodeList>());
936 const NodeList *r = static_cast<const NodeList *>(m);
937 QV4::ExecutionEngine *v4 = r->engine();
938
939 if (id.isArrayIndex()) {
940 uint index = id.asArrayIndex();
941 if ((int)index < r->d()->d->children.count()) {
942 if (hasProperty)
943 *hasProperty = true;
944 return Node::create(v4, data: r->d()->d->children.at(i: index));
945 }
946 if (hasProperty)
947 *hasProperty = false;
948 return Encode::undefined();
949 }
950
951 if (id == v4->id_length()->propertyKey())
952 return Value::fromInt32(i: r->d()->d->children.count()).asReturnedValue();
953 return Object::virtualGet(m, id, receiver, hasProperty);
954}
955
956ReturnedValue NodeList::create(ExecutionEngine *v4, NodeImpl *data)
957{
958 return (v4->memoryManager->allocate<NodeList>(args: data))->asReturnedValue();
959}
960
961ReturnedValue Document::method_documentElement(const FunctionObject *b, const Value *thisObject, const Value *, int)
962{
963 Scope scope(b);
964 Scoped<Node> r(scope, thisObject->as<Node>());
965 if (!r || r->d()->d->type != NodeImpl::Document)
966 RETURN_UNDEFINED();
967
968 return Node::create(v4: scope.engine, data: static_cast<DocumentImpl *>(r->d()->d)->root);
969}
970
971ReturnedValue Document::method_xmlStandalone(const FunctionObject *b, const Value *thisObject, const Value *, int)
972{
973 Scope scope(b);
974 Scoped<Node> r(scope, thisObject->as<Node>());
975 if (!r || r->d()->d->type != NodeImpl::Document)
976 RETURN_UNDEFINED();
977
978 return Encode(static_cast<DocumentImpl *>(r->d()->d)->isStandalone);
979}
980
981ReturnedValue Document::method_xmlVersion(const FunctionObject *b, const Value *thisObject, const Value *, int)
982{
983 Scope scope(b);
984 Scoped<Node> r(scope, thisObject->as<Node>());
985 if (!r || r->d()->d->type != NodeImpl::Document)
986 RETURN_UNDEFINED();
987
988 return Encode(scope.engine->newString(s: static_cast<DocumentImpl *>(r->d()->d)->version));
989}
990
991ReturnedValue Document::method_xmlEncoding(const FunctionObject *b, const Value *thisObject, const Value *, int)
992{
993 Scope scope(b);
994 Scoped<Node> r(scope, thisObject->as<Node>());
995 if (!r || r->d()->d->type != NodeImpl::Document)
996 RETURN_UNDEFINED();
997
998 return Encode(scope.engine->newString(s: static_cast<DocumentImpl *>(r->d()->d)->encoding));
999}
1000
1001class QQmlXMLHttpRequest : public QObject
1002{
1003 Q_OBJECT
1004public:
1005 enum LoadType {
1006 AsynchronousLoad,
1007 SynchronousLoad
1008 };
1009 enum State { Unsent = 0,
1010 Opened = 1, HeadersReceived = 2,
1011 Loading = 3, Done = 4 };
1012
1013 QQmlXMLHttpRequest(QNetworkAccessManager *manager, QV4::ExecutionEngine *v4);
1014 virtual ~QQmlXMLHttpRequest();
1015
1016 bool sendFlag() const;
1017 bool errorFlag() const;
1018 quint32 readyState() const;
1019 int replyStatus() const;
1020 QString replyStatusText() const;
1021
1022 ReturnedValue open(Object *thisObject, const QString &, const QUrl &, LoadType);
1023 ReturnedValue send(Object *thisObject, QQmlContextData *context, const QByteArray &);
1024 ReturnedValue abort(Object *thisObject);
1025
1026 void addHeader(const QString &, const QString &);
1027 QString header(const QString &name) const;
1028 QString headers() const;
1029
1030 QString responseBody();
1031 const QByteArray & rawResponseBody() const;
1032 bool receivedXml() const;
1033
1034 const QString & responseType() const;
1035 void setResponseType(const QString &);
1036
1037 QV4::ReturnedValue jsonResponseBody(QV4::ExecutionEngine*);
1038 QV4::ReturnedValue xmlResponseBody(QV4::ExecutionEngine*);
1039private slots:
1040 void readyRead();
1041 void error(QNetworkReply::NetworkError);
1042 void finished();
1043
1044private:
1045 void requestFromUrl(const QUrl &url);
1046
1047 State m_state;
1048 bool m_errorFlag;
1049 bool m_sendFlag;
1050 QString m_method;
1051 QUrl m_url;
1052 QByteArray m_responseEntityBody;
1053 QByteArray m_data;
1054 int m_redirectCount;
1055
1056 typedef QPair<QByteArray, QByteArray> HeaderPair;
1057 typedef QList<HeaderPair> HeadersList;
1058 HeadersList m_headersList;
1059 void fillHeadersList();
1060
1061 bool m_gotXml;
1062 QByteArray m_mime;
1063 QByteArray m_charset;
1064 QTextCodec *m_textCodec;
1065#if QT_CONFIG(textcodec)
1066 QTextCodec* findTextCodec() const;
1067#endif
1068 void readEncoding();
1069
1070 PersistentValue m_thisObject;
1071 QQmlContextDataRef m_qmlContext;
1072 bool m_wasConstructedWithQmlContext = true;
1073
1074 void dispatchCallbackNow(Object *thisObj);
1075 static void dispatchCallbackNow(Object *thisObj, bool done, bool error);
1076 void dispatchCallbackSafely();
1077
1078 int m_status;
1079 QString m_statusText;
1080 QNetworkRequest m_request;
1081 QStringList m_addedHeaders;
1082 QPointer<QNetworkReply> m_network;
1083 void destroyNetwork();
1084
1085 QNetworkAccessManager *m_nam;
1086 QNetworkAccessManager *networkAccessManager() { return m_nam; }
1087
1088 QString m_responseType;
1089 QV4::PersistentValue m_parsedDocument;
1090};
1091
1092QQmlXMLHttpRequest::QQmlXMLHttpRequest(QNetworkAccessManager *manager, QV4::ExecutionEngine *v4)
1093 : m_state(Unsent), m_errorFlag(false), m_sendFlag(false)
1094 , m_redirectCount(0), m_gotXml(false), m_textCodec(nullptr), m_network(nullptr), m_nam(manager)
1095 , m_responseType()
1096 , m_parsedDocument()
1097{
1098 m_wasConstructedWithQmlContext = v4->callingQmlContext() != nullptr;
1099}
1100
1101QQmlXMLHttpRequest::~QQmlXMLHttpRequest()
1102{
1103 destroyNetwork();
1104}
1105
1106bool QQmlXMLHttpRequest::sendFlag() const
1107{
1108 return m_sendFlag;
1109}
1110
1111bool QQmlXMLHttpRequest::errorFlag() const
1112{
1113 return m_errorFlag;
1114}
1115
1116quint32 QQmlXMLHttpRequest::readyState() const
1117{
1118 return m_state;
1119}
1120
1121int QQmlXMLHttpRequest::replyStatus() const
1122{
1123 return m_status;
1124}
1125
1126QString QQmlXMLHttpRequest::replyStatusText() const
1127{
1128 return m_statusText;
1129}
1130
1131ReturnedValue QQmlXMLHttpRequest::open(Object *thisObject, const QString &method, const QUrl &url, LoadType loadType)
1132{
1133 destroyNetwork();
1134 m_sendFlag = false;
1135 m_errorFlag = false;
1136 m_responseEntityBody = QByteArray();
1137 m_method = method;
1138 m_url = url;
1139 m_request.setAttribute(code: QNetworkRequest::SynchronousRequestAttribute, value: loadType == SynchronousLoad);
1140 m_state = Opened;
1141 m_addedHeaders.clear();
1142 dispatchCallbackNow(thisObj: thisObject);
1143 return Encode::undefined();
1144}
1145
1146void QQmlXMLHttpRequest::addHeader(const QString &name, const QString &value)
1147{
1148 QByteArray utfname = name.toUtf8();
1149
1150 if (m_addedHeaders.contains(str: name, cs: Qt::CaseInsensitive)) {
1151 m_request.setRawHeader(headerName: utfname, value: m_request.rawHeader(headerName: utfname) + ',' + value.toUtf8());
1152 } else {
1153 m_request.setRawHeader(headerName: utfname, value: value.toUtf8());
1154 m_addedHeaders.append(t: name);
1155 }
1156}
1157
1158QString QQmlXMLHttpRequest::header(const QString &name) const
1159{
1160 if (!m_headersList.isEmpty()) {
1161 const QByteArray utfname = name.toLower().toUtf8();
1162 for (const HeaderPair &header : m_headersList) {
1163 if (header.first == utfname)
1164 return QString::fromUtf8(str: header.second);
1165 }
1166 }
1167 return QString();
1168}
1169
1170QString QQmlXMLHttpRequest::headers() const
1171{
1172 QString ret;
1173
1174 for (const HeaderPair &header : m_headersList) {
1175 if (ret.length())
1176 ret.append(s: QLatin1String("\r\n"));
1177 ret += QString::fromUtf8(str: header.first) + QLatin1String(": ")
1178 + QString::fromUtf8(str: header.second);
1179 }
1180 return ret;
1181}
1182
1183void QQmlXMLHttpRequest::fillHeadersList()
1184{
1185 const QList<QByteArray> headerList = m_network->rawHeaderList();
1186
1187 m_headersList.clear();
1188 for (const QByteArray &header : headerList) {
1189 HeaderPair pair (header.toLower(), m_network->rawHeader(headerName: header));
1190 if (pair.first == "set-cookie" ||
1191 pair.first == "set-cookie2")
1192 continue;
1193
1194 m_headersList << pair;
1195 }
1196}
1197
1198void QQmlXMLHttpRequest::requestFromUrl(const QUrl &url)
1199{
1200 QNetworkRequest request = m_request;
1201
1202 if (QQmlFile::isLocalFile(url)) {
1203 if (m_method == QLatin1String("PUT"))
1204 {
1205 if (!xhrFileWrite()) {
1206 if (qEnvironmentVariableIsSet(varName: "QML_XHR_ALLOW_FILE_WRITE")) {
1207 qWarning(msg: "XMLHttpRequest: Tried to use PUT on a local file despite being disabled.");
1208 return;
1209 } else {
1210 qWarning(msg: "XMLHttpRequest: Using PUT on a local file is dangerous "
1211 "and will be disabled by default in a future Qt version."
1212 "Set QML_XHR_ALLOW_FILE_WRITE to 1 if you wish to continue using this feature.");
1213 }
1214 }
1215 } else if (m_method == QLatin1String("GET")) {
1216 if (!xhrFileRead()) {
1217 if (qEnvironmentVariableIsSet(varName: "QML_XHR_ALLOW_FILE_READ")) {
1218 qWarning(msg: "XMLHttpRequest: Tried to use GET on a local file despite being disabled.");
1219 return;
1220 } else {
1221 qWarning(msg: "XMLHttpRequest: Using GET on a local file is dangerous "
1222 "and will be disabled by default in a future Qt version."
1223 "Set QML_XHR_ALLOW_FILE_READ to 1 if you wish to continue using this feature.");
1224 }
1225 }
1226 } else {
1227 qWarning(msg: "XMLHttpRequest: Unsupported method used on a local file");
1228 return;
1229 }
1230 }
1231
1232 request.setUrl(url);
1233 if(m_method == QLatin1String("POST") ||
1234 m_method == QLatin1String("PUT")) {
1235 QVariant var = request.header(header: QNetworkRequest::ContentTypeHeader);
1236 if (var.isValid()) {
1237 QString str = var.toString();
1238 int charsetIdx = str.indexOf(s: QLatin1String("charset="));
1239 if (charsetIdx == -1) {
1240 // No charset - append
1241 if (!str.isEmpty()) str.append(c: QLatin1Char(';'));
1242 str.append(s: QLatin1String("charset=UTF-8"));
1243 } else {
1244 charsetIdx += 8;
1245 int n = 0;
1246 int semiColon = str.indexOf(c: QLatin1Char(';'), from: charsetIdx);
1247 if (semiColon == -1) {
1248 n = str.length() - charsetIdx;
1249 } else {
1250 n = semiColon - charsetIdx;
1251 }
1252
1253 str.replace(i: charsetIdx, len: n, after: QLatin1String("UTF-8"));
1254 }
1255 request.setHeader(header: QNetworkRequest::ContentTypeHeader, value: str);
1256 } else {
1257 request.setHeader(header: QNetworkRequest::ContentTypeHeader,
1258 value: QLatin1String("text/plain;charset=UTF-8"));
1259 }
1260 }
1261
1262 if (xhrDump()) {
1263 qWarning().nospace() << "XMLHttpRequest: " << qPrintable(m_method) << ' ' << qPrintable(url.toString());
1264 if (!m_data.isEmpty()) {
1265 qWarning().nospace() << " "
1266 << qPrintable(QString::fromUtf8(m_data));
1267 }
1268 }
1269
1270 if (m_method == QLatin1String("GET")) {
1271 m_network = networkAccessManager()->get(request);
1272 } else if (m_method == QLatin1String("HEAD")) {
1273 m_network = networkAccessManager()->head(request);
1274 } else if (m_method == QLatin1String("POST")) {
1275 m_network = networkAccessManager()->post(request, data: m_data);
1276 } else if (m_method == QLatin1String("PUT")) {
1277 m_network = networkAccessManager()->put(request, data: m_data);
1278 } else if (m_method == QLatin1String("DELETE")) {
1279 m_network = networkAccessManager()->deleteResource(request);
1280 } else if ((m_method == QLatin1String("OPTIONS")) ||
1281 m_method == QLatin1String("PROPFIND") ||
1282 m_method == QLatin1String("PATCH")) {
1283 QBuffer *buffer = new QBuffer;
1284 buffer->setData(m_data);
1285 buffer->open(openMode: QIODevice::ReadOnly);
1286 m_network = networkAccessManager()->sendCustomRequest(request, verb: QByteArray(m_method.toUtf8().constData()), data: buffer);
1287 buffer->setParent(m_network);
1288 }
1289
1290 if (m_request.attribute(code: QNetworkRequest::SynchronousRequestAttribute).toBool()) {
1291 if (m_network->bytesAvailable() > 0)
1292 readyRead();
1293
1294 QNetworkReply::NetworkError networkError = m_network->error();
1295 if (networkError != QNetworkReply::NoError) {
1296 error(networkError);
1297 } else {
1298 finished();
1299 }
1300 } else {
1301 QObject::connect(sender: m_network, SIGNAL(readyRead()),
1302 receiver: this, SLOT(readyRead()));
1303 QObject::connect(sender: m_network, SIGNAL(errorOccurred(QNetworkReply::NetworkError)),
1304 receiver: this, SLOT(error(QNetworkReply::NetworkError)));
1305 QObject::connect(sender: m_network, SIGNAL(finished()),
1306 receiver: this, SLOT(finished()));
1307 }
1308}
1309
1310ReturnedValue QQmlXMLHttpRequest::send(Object *thisObject, QQmlContextData *context, const QByteArray &data)
1311{
1312 m_errorFlag = false;
1313 m_sendFlag = true;
1314 m_redirectCount = 0;
1315 m_data = data;
1316
1317 m_thisObject = thisObject;
1318 m_qmlContext = context;
1319
1320 requestFromUrl(url: m_url);
1321
1322 return Encode::undefined();
1323}
1324
1325ReturnedValue QQmlXMLHttpRequest::abort(Object *thisObject)
1326{
1327 destroyNetwork();
1328 m_responseEntityBody = QByteArray();
1329 m_errorFlag = true;
1330 m_request = QNetworkRequest();
1331
1332 if (!(m_state == Unsent ||
1333 (m_state == Opened && !m_sendFlag) ||
1334 m_state == Done)) {
1335
1336 m_state = Done;
1337 m_sendFlag = false;
1338 dispatchCallbackNow(thisObj: thisObject);
1339 }
1340
1341 m_state = Unsent;
1342
1343 return Encode::undefined();
1344}
1345
1346void QQmlXMLHttpRequest::readyRead()
1347{
1348 m_status =
1349 m_network->attribute(code: QNetworkRequest::HttpStatusCodeAttribute).toInt();
1350 m_statusText =
1351 QString::fromUtf8(str: m_network->attribute(code: QNetworkRequest::HttpReasonPhraseAttribute).toByteArray());
1352
1353 // ### We assume if this is called the headers are now available
1354 if (m_state < HeadersReceived) {
1355 m_state = HeadersReceived;
1356 fillHeadersList ();
1357 dispatchCallbackSafely();
1358 }
1359
1360 bool wasEmpty = m_responseEntityBody.isEmpty();
1361 m_responseEntityBody.append(a: m_network->readAll());
1362 if (wasEmpty && !m_responseEntityBody.isEmpty())
1363 m_state = Loading;
1364
1365 dispatchCallbackSafely();
1366}
1367
1368static const char *errorToString(QNetworkReply::NetworkError error)
1369{
1370 int idx = QNetworkReply::staticMetaObject.indexOfEnumerator(name: "NetworkError");
1371 if (idx == -1) return "EnumLookupFailed";
1372
1373 QMetaEnum e = QNetworkReply::staticMetaObject.enumerator(index: idx);
1374
1375 const char *name = e.valueToKey(value: error);
1376 if (!name) return "EnumLookupFailed";
1377 else return name;
1378}
1379
1380void QQmlXMLHttpRequest::error(QNetworkReply::NetworkError error)
1381{
1382 m_status =
1383 m_network->attribute(code: QNetworkRequest::HttpStatusCodeAttribute).toInt();
1384 m_statusText =
1385 QString::fromUtf8(str: m_network->attribute(code: QNetworkRequest::HttpReasonPhraseAttribute).toByteArray());
1386
1387 m_request = QNetworkRequest();
1388 m_data.clear();
1389 destroyNetwork();
1390
1391 if (xhrDump()) {
1392 qWarning().nospace() << "XMLHttpRequest: ERROR " << qPrintable(m_url.toString());
1393 qWarning().nospace() << " " << error << ' ' << errorToString(error) << ' ' << m_statusText;
1394 }
1395
1396 if (error == QNetworkReply::ContentAccessDenied ||
1397 error == QNetworkReply::ContentOperationNotPermittedError ||
1398 error == QNetworkReply::ContentNotFoundError ||
1399 error == QNetworkReply::AuthenticationRequiredError ||
1400 error == QNetworkReply::ContentReSendError ||
1401 error == QNetworkReply::UnknownContentError ||
1402 error == QNetworkReply::ProtocolInvalidOperationError ||
1403 error == QNetworkReply::InternalServerError ||
1404 error == QNetworkReply::OperationNotImplementedError ||
1405 error == QNetworkReply::ServiceUnavailableError ||
1406 error == QNetworkReply::UnknownServerError) {
1407 m_state = Loading;
1408 dispatchCallbackSafely();
1409 } else {
1410 m_errorFlag = true;
1411 m_responseEntityBody = QByteArray();
1412 }
1413
1414 m_state = Done;
1415 dispatchCallbackSafely();
1416}
1417
1418#define XMLHTTPREQUEST_MAXIMUM_REDIRECT_RECURSION 15
1419void QQmlXMLHttpRequest::finished()
1420{
1421 m_redirectCount++;
1422 if (m_redirectCount < XMLHTTPREQUEST_MAXIMUM_REDIRECT_RECURSION) {
1423 QVariant redirect = m_network->attribute(code: QNetworkRequest::RedirectionTargetAttribute);
1424 if (redirect.isValid()) {
1425 QUrl url = m_network->url().resolved(relative: redirect.toUrl());
1426 if (!QQmlFile::isLocalFile(url)) {
1427 // See http://www.ietf.org/rfc/rfc2616.txt, section 10.3.4 "303 See Other":
1428 // Result of 303 redirection should be a new "GET" request.
1429 const QVariant code = m_network->attribute(code: QNetworkRequest::HttpStatusCodeAttribute);
1430 if (code.isValid() && code.toInt() == 303 && m_method != QLatin1String("GET"))
1431 m_method = QStringLiteral("GET");
1432 destroyNetwork();
1433
1434 // Discard redirect response body
1435 m_responseEntityBody = QByteArray();
1436
1437 requestFromUrl(url);
1438 return;
1439 }
1440 }
1441 }
1442
1443 m_status =
1444 m_network->attribute(code: QNetworkRequest::HttpStatusCodeAttribute).toInt();
1445 m_statusText =
1446 QString::fromUtf8(str: m_network->attribute(code: QNetworkRequest::HttpReasonPhraseAttribute).toByteArray());
1447
1448 if (m_state < HeadersReceived) {
1449 m_state = HeadersReceived;
1450 fillHeadersList ();
1451 dispatchCallbackSafely();
1452 }
1453 m_responseEntityBody.append(a: m_network->readAll());
1454 readEncoding();
1455
1456 if (xhrDump()) {
1457 qWarning().nospace() << "XMLHttpRequest: RESPONSE " << qPrintable(m_url.toString());
1458 if (!m_responseEntityBody.isEmpty()) {
1459 qWarning().nospace() << " "
1460 << qPrintable(QString::fromUtf8(m_responseEntityBody));
1461 }
1462 }
1463
1464 m_data.clear();
1465 destroyNetwork();
1466 if (m_state < Loading) {
1467 m_state = Loading;
1468 dispatchCallbackSafely();
1469 }
1470 m_state = Done;
1471
1472 dispatchCallbackSafely();
1473
1474 m_thisObject.clear();
1475 m_qmlContext.setContextData(nullptr);
1476}
1477
1478
1479void QQmlXMLHttpRequest::readEncoding()
1480{
1481 for (const HeaderPair &header : qAsConst(t&: m_headersList)) {
1482 if (header.first == "content-type") {
1483 int separatorIdx = header.second.indexOf(c: ';');
1484 if (separatorIdx == -1) {
1485 m_mime = header.second;
1486 } else {
1487 m_mime = header.second.mid(index: 0, len: separatorIdx);
1488 int charsetIdx = header.second.indexOf(c: "charset=");
1489 if (charsetIdx != -1) {
1490 charsetIdx += 8;
1491 separatorIdx = header.second.indexOf(c: ';', from: charsetIdx);
1492 m_charset = header.second.mid(index: charsetIdx, len: separatorIdx >= 0 ? separatorIdx : header.second.length());
1493 }
1494 }
1495 break;
1496 }
1497 }
1498
1499 if (m_mime.isEmpty() || m_mime == "text/xml" || m_mime == "application/xml" || m_mime.endsWith(c: "+xml"))
1500 m_gotXml = true;
1501}
1502
1503bool QQmlXMLHttpRequest::receivedXml() const
1504{
1505 return m_gotXml;
1506}
1507
1508const QString & QQmlXMLHttpRequest::responseType() const
1509{
1510 return m_responseType;
1511}
1512
1513void QQmlXMLHttpRequest::setResponseType(const QString &responseType)
1514{
1515 m_responseType = responseType;
1516}
1517
1518QV4::ReturnedValue QQmlXMLHttpRequest::jsonResponseBody(QV4::ExecutionEngine* engine)
1519{
1520 if (m_parsedDocument.isEmpty()) {
1521 Scope scope(engine);
1522
1523 QJsonParseError error;
1524 const QString& jtext = responseBody();
1525 JsonParser parser(scope.engine, jtext.constData(), jtext.length());
1526 ScopedValue jsonObject(scope, parser.parse(error: &error));
1527 if (error.error != QJsonParseError::NoError)
1528 return engine->throwSyntaxError(QStringLiteral("JSON.parse: Parse error"));
1529
1530 m_parsedDocument.set(engine: scope.engine, value: jsonObject);
1531 }
1532
1533 return m_parsedDocument.value();
1534}
1535
1536QV4::ReturnedValue QQmlXMLHttpRequest::xmlResponseBody(QV4::ExecutionEngine* engine)
1537{
1538 if (m_parsedDocument.isEmpty()) {
1539 m_parsedDocument.set(engine, value: Document::load(v4: engine, data: rawResponseBody()));
1540 }
1541
1542 return m_parsedDocument.value();
1543}
1544
1545#if QT_CONFIG(textcodec)
1546QTextCodec* QQmlXMLHttpRequest::findTextCodec() const
1547{
1548 QTextCodec *codec = nullptr;
1549
1550 if (!m_charset.isEmpty())
1551 codec = QTextCodec::codecForName(name: m_charset);
1552
1553 if (!codec && m_gotXml) {
1554 QXmlStreamReader reader(m_responseEntityBody);
1555 reader.readNext();
1556 codec = QTextCodec::codecForName(name: reader.documentEncoding().toString().toUtf8());
1557 }
1558
1559 if (!codec && m_mime == "text/html")
1560 codec = QTextCodec::codecForHtml(ba: m_responseEntityBody, defaultCodec: nullptr);
1561
1562 if (!codec)
1563 codec = QTextCodec::codecForUtfText(ba: m_responseEntityBody, defaultCodec: nullptr);
1564
1565 if (!codec)
1566 codec = QTextCodec::codecForName(name: "UTF-8");
1567 return codec;
1568}
1569#endif
1570
1571
1572QString QQmlXMLHttpRequest::responseBody()
1573{
1574#if QT_CONFIG(textcodec)
1575 if (!m_textCodec)
1576 m_textCodec = findTextCodec();
1577 if (m_textCodec)
1578 return m_textCodec->toUnicode(m_responseEntityBody);
1579#endif
1580
1581 return QString::fromUtf8(str: m_responseEntityBody);
1582}
1583
1584const QByteArray &QQmlXMLHttpRequest::rawResponseBody() const
1585{
1586 return m_responseEntityBody;
1587}
1588
1589void QQmlXMLHttpRequest::dispatchCallbackNow(Object *thisObj)
1590{
1591 dispatchCallbackNow(thisObj, done: m_state == Done, error: m_errorFlag);
1592}
1593
1594void QQmlXMLHttpRequest::dispatchCallbackNow(Object *thisObj, bool done, bool error)
1595{
1596 Q_ASSERT(thisObj);
1597
1598 const auto dispatch = [thisObj](const QString &eventName) {
1599 QV4::Scope scope(thisObj->engine());
1600 ScopedString s(scope, scope.engine->newString(s: eventName));
1601 ScopedFunctionObject callback(scope, thisObj->get(name: s));
1602 // not an error, but no event handler to call.
1603 if (!callback)
1604 return;
1605
1606 QV4::JSCallData jsCallData(scope);
1607 callback->call(data: jsCallData);
1608
1609 if (scope.engine->hasException) {
1610 QQmlError error = scope.engine->catchExceptionAsQmlError();
1611 QQmlEnginePrivate *qmlEnginePrivate = scope.engine->qmlEngine() ? QQmlEnginePrivate::get(e: scope.engine->qmlEngine()) : nullptr;
1612 QQmlEnginePrivate::warning(qmlEnginePrivate, error);
1613 }
1614 };
1615
1616 dispatch(QStringLiteral("onreadystatechange"));
1617 if (done) {
1618 if (error)
1619 dispatch(QStringLiteral("onerror"));
1620 else
1621 dispatch(QStringLiteral("onload"));
1622 dispatch(QStringLiteral("onloadend"));
1623 }
1624}
1625
1626void QQmlXMLHttpRequest::dispatchCallbackSafely()
1627{
1628 if (m_wasConstructedWithQmlContext && !m_qmlContext.contextData())
1629 // if the calling context object is no longer valid, then it has been
1630 // deleted explicitly (e.g., by a Loader deleting the itemContext when
1631 // the source is changed). We do nothing in this case, as the evaluation
1632 // cannot succeed.
1633 return;
1634
1635 dispatchCallbackNow(thisObj: m_thisObject.as<Object>());
1636}
1637
1638void QQmlXMLHttpRequest::destroyNetwork()
1639{
1640 if (m_network) {
1641 m_network->disconnect();
1642 m_network->deleteLater();
1643 m_network = nullptr;
1644 }
1645}
1646
1647namespace QV4 {
1648namespace Heap {
1649
1650struct QQmlXMLHttpRequestWrapper : Object {
1651 void init(QQmlXMLHttpRequest *request) {
1652 Object::init();
1653 this->request = request;
1654 }
1655
1656 void destroy() {
1657 delete request;
1658 Object::destroy();
1659 }
1660 QQmlXMLHttpRequest *request;
1661};
1662
1663#define QQmlXMLHttpRequestCtorMembers(class, Member) \
1664 Member(class, Pointer, Object *, proto)
1665
1666DECLARE_HEAP_OBJECT(QQmlXMLHttpRequestCtor, FunctionObject) {
1667 DECLARE_MARKOBJECTS(QQmlXMLHttpRequestCtor);
1668 void init(ExecutionEngine *engine);
1669};
1670
1671}
1672
1673struct QQmlXMLHttpRequestWrapper : public Object
1674{
1675 V4_OBJECT2(QQmlXMLHttpRequestWrapper, Object)
1676 V4_NEEDS_DESTROY
1677};
1678
1679struct QQmlXMLHttpRequestCtor : public FunctionObject
1680{
1681 V4_OBJECT2(QQmlXMLHttpRequestCtor, FunctionObject)
1682
1683 static ReturnedValue virtualCallAsConstructor(const FunctionObject *f, const Value *, int, const Value *)
1684 {
1685 Scope scope(f->engine());
1686 const QQmlXMLHttpRequestCtor *ctor = static_cast<const QQmlXMLHttpRequestCtor *>(f);
1687
1688 QQmlXMLHttpRequest *r = new QQmlXMLHttpRequest(scope.engine->networkAccessManager(scope.engine), scope.engine);
1689 Scoped<QQmlXMLHttpRequestWrapper> w(scope, scope.engine->memoryManager->allocate<QQmlXMLHttpRequestWrapper>(args: r));
1690 ScopedObject proto(scope, ctor->d()->proto);
1691 w->setPrototypeUnchecked(proto);
1692 return w.asReturnedValue();
1693 }
1694
1695 static ReturnedValue virtualCall(const FunctionObject *, const Value *, const Value *, int) {
1696 return Encode::undefined();
1697 }
1698
1699 void setupProto();
1700
1701 static ReturnedValue method_open(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
1702 static ReturnedValue method_setRequestHeader(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
1703 static ReturnedValue method_send(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
1704 static ReturnedValue method_abort(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
1705 static ReturnedValue method_getResponseHeader(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
1706 static ReturnedValue method_getAllResponseHeaders(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
1707
1708 static ReturnedValue method_get_readyState(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
1709 static ReturnedValue method_get_status(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
1710 static ReturnedValue method_get_statusText(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
1711 static ReturnedValue method_get_responseText(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
1712 static ReturnedValue method_get_responseXML(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
1713 static ReturnedValue method_get_response(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
1714 static ReturnedValue method_get_responseType(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
1715 static ReturnedValue method_set_responseType(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
1716};
1717
1718}
1719
1720DEFINE_OBJECT_VTABLE(QQmlXMLHttpRequestWrapper);
1721
1722void Heap::QQmlXMLHttpRequestCtor::init(ExecutionEngine *engine)
1723{
1724 Heap::FunctionObject::init(scope: engine->rootContext(), QStringLiteral("XMLHttpRequest"));
1725 Scope scope(engine);
1726 Scoped<QV4::QQmlXMLHttpRequestCtor> ctor(scope, this);
1727
1728 ctor->defineReadonlyProperty(QStringLiteral("UNSENT"), value: Value::fromInt32(i: 0));
1729 ctor->defineReadonlyProperty(QStringLiteral("OPENED"), value: Value::fromInt32(i: 1));
1730 ctor->defineReadonlyProperty(QStringLiteral("HEADERS_RECEIVED"), value: Value::fromInt32(i: 2));
1731 ctor->defineReadonlyProperty(QStringLiteral("LOADING"), value: Value::fromInt32(i: 3));
1732 ctor->defineReadonlyProperty(QStringLiteral("DONE"), value: Value::fromInt32(i: 4));
1733 if (!ctor->d()->proto)
1734 ctor->setupProto();
1735 ScopedString s(scope, engine->id_prototype());
1736 ctor->defineDefaultProperty(name: s, value: ScopedObject(scope, ctor->d()->proto));
1737}
1738
1739DEFINE_OBJECT_VTABLE(QQmlXMLHttpRequestCtor);
1740
1741void QQmlXMLHttpRequestCtor::setupProto()
1742{
1743 ExecutionEngine *v4 = engine();
1744 Scope scope(v4);
1745 ScopedObject p(scope, v4->newObject());
1746 d()->proto.set(e: scope.engine, newVal: p->d());
1747
1748 // Methods
1749 p->defineDefaultProperty(QStringLiteral("open"), code: method_open);
1750 p->defineDefaultProperty(QStringLiteral("setRequestHeader"), code: method_setRequestHeader);
1751 p->defineDefaultProperty(QStringLiteral("send"), code: method_send);
1752 p->defineDefaultProperty(QStringLiteral("abort"), code: method_abort);
1753 p->defineDefaultProperty(QStringLiteral("getResponseHeader"), code: method_getResponseHeader);
1754 p->defineDefaultProperty(QStringLiteral("getAllResponseHeaders"), code: method_getAllResponseHeaders);
1755
1756 // Read-only properties
1757 p->defineAccessorProperty(QStringLiteral("readyState"), getter: method_get_readyState, setter: nullptr);
1758 p->defineAccessorProperty(QStringLiteral("status"),getter: method_get_status, setter: nullptr);
1759 p->defineAccessorProperty(QStringLiteral("statusText"),getter: method_get_statusText, setter: nullptr);
1760 p->defineAccessorProperty(QStringLiteral("responseText"),getter: method_get_responseText, setter: nullptr);
1761 p->defineAccessorProperty(QStringLiteral("responseXML"),getter: method_get_responseXML, setter: nullptr);
1762 p->defineAccessorProperty(QStringLiteral("response"),getter: method_get_response, setter: nullptr);
1763
1764 // Read-write properties
1765 p->defineAccessorProperty(QStringLiteral("responseType"), getter: method_get_responseType, setter: method_set_responseType);
1766
1767 // State values
1768 p->defineReadonlyProperty(QStringLiteral("UNSENT"), value: Value::fromInt32(i: 0));
1769 p->defineReadonlyProperty(QStringLiteral("OPENED"), value: Value::fromInt32(i: 1));
1770 p->defineReadonlyProperty(QStringLiteral("HEADERS_RECEIVED"), value: Value::fromInt32(i: 2));
1771 p->defineReadonlyProperty(QStringLiteral("LOADING"), value: Value::fromInt32(i: 3));
1772 p->defineReadonlyProperty(QStringLiteral("DONE"), value: Value::fromInt32(i: 4));
1773}
1774
1775
1776// XMLHttpRequest methods
1777ReturnedValue QQmlXMLHttpRequestCtor::method_open(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
1778{
1779 Scope scope(b);
1780 Scoped<QQmlXMLHttpRequestWrapper> w(scope, thisObject->as<QQmlXMLHttpRequestWrapper>());
1781 if (!w)
1782 V4THROW_REFERENCE("Not an XMLHttpRequest object");
1783 QQmlXMLHttpRequest *r = w->d()->request;
1784
1785 if (argc < 2 || argc > 5)
1786 THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count");
1787
1788 // Argument 0 - Method
1789 QString method = argv[0].toQStringNoThrow().toUpper();
1790 if (method != QLatin1String("GET") &&
1791 method != QLatin1String("PUT") &&
1792 method != QLatin1String("HEAD") &&
1793 method != QLatin1String("POST") &&
1794 method != QLatin1String("DELETE") &&
1795 method != QLatin1String("OPTIONS") &&
1796 method != QLatin1String("PROPFIND") &&
1797 method != QLatin1String("PATCH"))
1798 THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Unsupported HTTP method type");
1799
1800 // Argument 1 - URL
1801 QUrl url = QUrl(argv[1].toQStringNoThrow());
1802
1803 if (url.isRelative()) {
1804 QQmlContextData *qmlContextData = scope.engine->callingQmlContext();
1805 if (qmlContextData)
1806 url = qmlContextData->resolvedUrl(url);
1807 else
1808 url = scope.engine->resolvedUrl(file: url.url());
1809 }
1810
1811 bool async = true;
1812 // Argument 2 - async (optional)
1813 if (argc > 2) {
1814 async = argv[2].booleanValue();
1815 }
1816
1817 // Argument 3/4 - user/pass (optional)
1818 QString username, password;
1819 if (argc > 3)
1820 username = argv[3].toQStringNoThrow();
1821 if (argc > 4)
1822 password = argv[4].toQStringNoThrow();
1823
1824 // Clear the fragment (if any)
1825 url.setFragment(fragment: QString());
1826
1827 // Set username/password
1828 if (!username.isNull()) url.setUserName(userName: username);
1829 if (!password.isNull()) url.setPassword(password);
1830
1831 return r->open(thisObject: w, method, url, loadType: async ? QQmlXMLHttpRequest::AsynchronousLoad : QQmlXMLHttpRequest::SynchronousLoad);
1832}
1833
1834ReturnedValue QQmlXMLHttpRequestCtor::method_setRequestHeader(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
1835{
1836 Scope scope(b);
1837 Scoped<QQmlXMLHttpRequestWrapper> w(scope, thisObject->as<QQmlXMLHttpRequestWrapper>());
1838 if (!w)
1839 V4THROW_REFERENCE("Not an XMLHttpRequest object");
1840 QQmlXMLHttpRequest *r = w->d()->request;
1841
1842 if (argc != 2)
1843 THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count");
1844
1845 if (r->readyState() != QQmlXMLHttpRequest::Opened || r->sendFlag())
1846 THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
1847
1848 QString name = argv[0].toQStringNoThrow();
1849 QString value = argv[1].toQStringNoThrow();
1850
1851 // ### Check that name and value are well formed
1852
1853 QString nameUpper = name.toUpper();
1854 if (nameUpper == QLatin1String("ACCEPT-CHARSET") ||
1855 nameUpper == QLatin1String("ACCEPT-ENCODING") ||
1856 nameUpper == QLatin1String("CONNECTION") ||
1857 nameUpper == QLatin1String("CONTENT-LENGTH") ||
1858 nameUpper == QLatin1String("COOKIE") ||
1859 nameUpper == QLatin1String("COOKIE2") ||
1860 nameUpper == QLatin1String("CONTENT-TRANSFER-ENCODING") ||
1861 nameUpper == QLatin1String("DATE") ||
1862 nameUpper == QLatin1String("EXPECT") ||
1863 nameUpper == QLatin1String("HOST") ||
1864 nameUpper == QLatin1String("KEEP-ALIVE") ||
1865 nameUpper == QLatin1String("REFERER") ||
1866 nameUpper == QLatin1String("TE") ||
1867 nameUpper == QLatin1String("TRAILER") ||
1868 nameUpper == QLatin1String("TRANSFER-ENCODING") ||
1869 nameUpper == QLatin1String("UPGRADE") ||
1870 nameUpper == QLatin1String("USER-AGENT") ||
1871 nameUpper == QLatin1String("VIA") ||
1872 nameUpper.startsWith(s: QLatin1String("PROXY-")) ||
1873 nameUpper.startsWith(s: QLatin1String("SEC-")))
1874 RETURN_UNDEFINED();
1875
1876 r->addHeader(name, value);
1877
1878 RETURN_UNDEFINED();
1879}
1880
1881ReturnedValue QQmlXMLHttpRequestCtor::method_send(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
1882{
1883 Scope scope(b);
1884 Scoped<QQmlXMLHttpRequestWrapper> w(scope, thisObject->as<QQmlXMLHttpRequestWrapper>());
1885 if (!w)
1886 V4THROW_REFERENCE("Not an XMLHttpRequest object");
1887 QQmlXMLHttpRequest *r = w->d()->request;
1888
1889 if (r->readyState() != QQmlXMLHttpRequest::Opened ||
1890 r->sendFlag())
1891 THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
1892
1893 QByteArray data;
1894 if (argc > 0) {
1895 if (const ArrayBuffer *buffer = argv[0].as<ArrayBuffer>()) {
1896 data = buffer->asByteArray();
1897 } else {
1898 data = argv[0].toQStringNoThrow().toUtf8();
1899 }
1900 }
1901
1902 return r->send(thisObject: w, context: scope.engine->callingQmlContext(), data);
1903}
1904
1905ReturnedValue QQmlXMLHttpRequestCtor::method_abort(const FunctionObject *b, const Value *thisObject, const Value *, int)
1906{
1907 Scope scope(b);
1908 Scoped<QQmlXMLHttpRequestWrapper> w(scope, thisObject->as<QQmlXMLHttpRequestWrapper>());
1909 if (!w)
1910 V4THROW_REFERENCE("Not an XMLHttpRequest object");
1911 QQmlXMLHttpRequest *r = w->d()->request;
1912
1913 return r->abort(thisObject: w);
1914}
1915
1916ReturnedValue QQmlXMLHttpRequestCtor::method_getResponseHeader(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
1917{
1918 Scope scope(b);
1919 Scoped<QQmlXMLHttpRequestWrapper> w(scope, thisObject->as<QQmlXMLHttpRequestWrapper>());
1920 if (!w)
1921 V4THROW_REFERENCE("Not an XMLHttpRequest object");
1922 QQmlXMLHttpRequest *r = w->d()->request;
1923
1924 if (argc != 1)
1925 THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count");
1926
1927 if (r->readyState() != QQmlXMLHttpRequest::Loading &&
1928 r->readyState() != QQmlXMLHttpRequest::Done &&
1929 r->readyState() != QQmlXMLHttpRequest::HeadersReceived)
1930 THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
1931
1932 return Encode(scope.engine->newString(s: r->header(name: argv[0].toQStringNoThrow())));
1933}
1934
1935ReturnedValue QQmlXMLHttpRequestCtor::method_getAllResponseHeaders(const FunctionObject *b, const Value *thisObject, const Value *, int argc)
1936{
1937 Scope scope(b);
1938 Scoped<QQmlXMLHttpRequestWrapper> w(scope, thisObject->as<QQmlXMLHttpRequestWrapper>());
1939 if (!w)
1940 V4THROW_REFERENCE("Not an XMLHttpRequest object");
1941 QQmlXMLHttpRequest *r = w->d()->request;
1942
1943 if (argc != 0)
1944 THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count");
1945
1946 if (r->readyState() != QQmlXMLHttpRequest::Loading &&
1947 r->readyState() != QQmlXMLHttpRequest::Done &&
1948 r->readyState() != QQmlXMLHttpRequest::HeadersReceived)
1949 THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
1950
1951 return Encode(scope.engine->newString(s: r->headers()));
1952}
1953
1954// XMLHttpRequest properties
1955ReturnedValue QQmlXMLHttpRequestCtor::method_get_readyState(const FunctionObject *b, const Value *thisObject, const Value *, int)
1956{
1957 Scope scope(b);
1958 Scoped<QQmlXMLHttpRequestWrapper> w(scope, thisObject->as<QQmlXMLHttpRequestWrapper>());
1959 if (!w)
1960 V4THROW_REFERENCE("Not an XMLHttpRequest object");
1961 QQmlXMLHttpRequest *r = w->d()->request;
1962
1963 return Encode(r->readyState());
1964}
1965
1966ReturnedValue QQmlXMLHttpRequestCtor::method_get_status(const FunctionObject *b, const Value *thisObject, const Value *, int)
1967{
1968 Scope scope(b);
1969 Scoped<QQmlXMLHttpRequestWrapper> w(scope, thisObject->as<QQmlXMLHttpRequestWrapper>());
1970 if (!w)
1971 V4THROW_REFERENCE("Not an XMLHttpRequest object");
1972 QQmlXMLHttpRequest *r = w->d()->request;
1973
1974 if (r->readyState() == QQmlXMLHttpRequest::Unsent ||
1975 r->readyState() == QQmlXMLHttpRequest::Opened)
1976 THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
1977
1978 if (r->errorFlag())
1979 return Encode(0);
1980 else
1981 return Encode(r->replyStatus());
1982}
1983
1984ReturnedValue QQmlXMLHttpRequestCtor::method_get_statusText(const FunctionObject *b, const Value *thisObject, const Value *, int)
1985{
1986 Scope scope(b);
1987 Scoped<QQmlXMLHttpRequestWrapper> w(scope, thisObject->as<QQmlXMLHttpRequestWrapper>());
1988 if (!w)
1989 V4THROW_REFERENCE("Not an XMLHttpRequest object");
1990 QQmlXMLHttpRequest *r = w->d()->request;
1991
1992 if (r->readyState() == QQmlXMLHttpRequest::Unsent ||
1993 r->readyState() == QQmlXMLHttpRequest::Opened)
1994 THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
1995
1996 if (r->errorFlag())
1997 return Encode(scope.engine->newString(s: QString()));
1998 else
1999 return Encode(scope.engine->newString(s: r->replyStatusText()));
2000}
2001
2002ReturnedValue QQmlXMLHttpRequestCtor::method_get_responseText(const FunctionObject *b, const Value *thisObject, const Value *, int)
2003{
2004 Scope scope(b);
2005 Scoped<QQmlXMLHttpRequestWrapper> w(scope, thisObject->as<QQmlXMLHttpRequestWrapper>());
2006 if (!w)
2007 V4THROW_REFERENCE("Not an XMLHttpRequest object");
2008 QQmlXMLHttpRequest *r = w->d()->request;
2009
2010 if (r->readyState() != QQmlXMLHttpRequest::Loading &&
2011 r->readyState() != QQmlXMLHttpRequest::Done)
2012 return Encode(scope.engine->newString(s: QString()));
2013 else
2014 return Encode(scope.engine->newString(s: r->responseBody()));
2015}
2016
2017ReturnedValue QQmlXMLHttpRequestCtor::method_get_responseXML(const FunctionObject *b, const Value *thisObject, const Value *, int)
2018{
2019 Scope scope(b);
2020 Scoped<QQmlXMLHttpRequestWrapper> w(scope, thisObject->as<QQmlXMLHttpRequestWrapper>());
2021 if (!w)
2022 V4THROW_REFERENCE("Not an XMLHttpRequest object");
2023 QQmlXMLHttpRequest *r = w->d()->request;
2024
2025 if (!r->receivedXml() ||
2026 (r->readyState() != QQmlXMLHttpRequest::Loading &&
2027 r->readyState() != QQmlXMLHttpRequest::Done)) {
2028 return Encode::null();
2029 } else {
2030 if (r->responseType().isEmpty())
2031 r->setResponseType(QLatin1String("document"));
2032 return r->xmlResponseBody(engine: scope.engine);
2033 }
2034}
2035
2036ReturnedValue QQmlXMLHttpRequestCtor::method_get_response(const FunctionObject *b, const Value *thisObject, const Value *, int)
2037{
2038 Scope scope(b);
2039 Scoped<QQmlXMLHttpRequestWrapper> w(scope, thisObject->as<QQmlXMLHttpRequestWrapper>());
2040 if (!w)
2041 V4THROW_REFERENCE("Not an XMLHttpRequest object");
2042 QQmlXMLHttpRequest *r = w->d()->request;
2043
2044 if (r->readyState() != QQmlXMLHttpRequest::Loading &&
2045 r->readyState() != QQmlXMLHttpRequest::Done)
2046 RETURN_RESULT(scope.engine->newString(QString()));
2047
2048 const QString& responseType = r->responseType();
2049 if (responseType.compare(other: QLatin1String("text"), cs: Qt::CaseInsensitive) == 0 || responseType.isEmpty()) {
2050 RETURN_RESULT(scope.engine->newString(r->responseBody()));
2051 } else if (responseType.compare(other: QLatin1String("arraybuffer"), cs: Qt::CaseInsensitive) == 0) {
2052 RETURN_RESULT(scope.engine->newArrayBuffer(r->rawResponseBody()));
2053 } else if (responseType.compare(other: QLatin1String("json"), cs: Qt::CaseInsensitive) == 0) {
2054 RETURN_RESULT(r->jsonResponseBody(scope.engine));
2055 } else if (responseType.compare(other: QLatin1String("document"), cs: Qt::CaseInsensitive) == 0) {
2056 RETURN_RESULT(r->xmlResponseBody(scope.engine));
2057 } else {
2058 RETURN_RESULT(scope.engine->newString(QString()));
2059 }
2060}
2061
2062
2063ReturnedValue QQmlXMLHttpRequestCtor::method_get_responseType(const FunctionObject *b, const Value *thisObject, const Value *, int)
2064{
2065 Scope scope(b);
2066 Scoped<QQmlXMLHttpRequestWrapper> w(scope, thisObject->as<QQmlXMLHttpRequestWrapper>());
2067 if (!w)
2068 V4THROW_REFERENCE("Not an XMLHttpRequest object");
2069 QQmlXMLHttpRequest *r = w->d()->request;
2070 return Encode(scope.engine->newString(s: r->responseType()));
2071}
2072
2073ReturnedValue QQmlXMLHttpRequestCtor::method_set_responseType(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
2074{
2075 Scope scope(b);
2076 Scoped<QQmlXMLHttpRequestWrapper> w(scope, thisObject->as<QQmlXMLHttpRequestWrapper>());
2077 if (!w)
2078 V4THROW_REFERENCE("Not an XMLHttpRequest object");
2079 QQmlXMLHttpRequest *r = w->d()->request;
2080
2081 if (argc < 1)
2082 THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count");
2083
2084 // Argument 0 - response type
2085 r->setResponseType(argv[0].toQStringNoThrow());
2086
2087 return Encode::undefined();
2088}
2089
2090void qt_rem_qmlxmlhttprequest(ExecutionEngine * /* engine */, void *d)
2091{
2092 QQmlXMLHttpRequestData *data = (QQmlXMLHttpRequestData *)d;
2093 delete data;
2094}
2095
2096void *qt_add_qmlxmlhttprequest(ExecutionEngine *v4)
2097{
2098 Scope scope(v4);
2099
2100 Scoped<QQmlXMLHttpRequestCtor> ctor(scope, v4->memoryManager->allocate<QQmlXMLHttpRequestCtor>(args: v4));
2101 ScopedString s(scope, v4->newString(QStringLiteral("XMLHttpRequest")));
2102 v4->globalObject->defineReadonlyProperty(name: s, value: ctor);
2103
2104 QQmlXMLHttpRequestData *data = new QQmlXMLHttpRequestData;
2105 return data;
2106}
2107
2108QT_END_NAMESPACE
2109
2110#include <qqmlxmlhttprequest.moc>
2111

source code of qtdeclarative/src/qml/qml/qqmlxmlhttprequest.cpp