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