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