Generated should not be supported for things with a shadow
[WebKit-https.git] / Source / WebCore / xml / XMLHttpRequest.cpp
1 /*
2  *  Copyright (C) 2004, 2006, 2008 Apple Inc. All rights reserved.
3  *  Copyright (C) 2005-2007 Alexey Proskuryakov <ap@webkit.org>
4  *  Copyright (C) 2007, 2008 Julien Chaffraix <jchaffraix@webkit.org>
5  *  Copyright (C) 2008, 2011 Google Inc. All rights reserved.
6  *  Copyright (C) 2012 Intel Corporation
7  *
8  *  This library is free software; you can redistribute it and/or
9  *  modify it under the terms of the GNU Lesser General Public
10  *  License as published by the Free Software Foundation; either
11  *  version 2 of the License, or (at your option) any later version.
12  *
13  *  This library is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  *  Lesser General Public License for more details.
17  *
18  *  You should have received a copy of the GNU Lesser General Public
19  *  License along with this library; if not, write to the Free Software
20  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21  */
22
23 #include "config.h"
24 #include "XMLHttpRequest.h"
25
26 #include "Blob.h"
27 #include "BlobData.h"
28 #include "ContentSecurityPolicy.h"
29 #include "ContextFeatures.h"
30 #include "CrossOriginAccessControl.h"
31 #include "DOMFormData.h"
32 #include "DOMImplementation.h"
33 #include "Event.h"
34 #include "EventException.h"
35 #include "EventListener.h"
36 #include "EventNames.h"
37 #include "ExceptionCode.h"
38 #include "File.h"
39 #include "HTMLDocument.h"
40 #include "HTTPParsers.h"
41 #include "HTTPValidation.h"
42 #include "HistogramSupport.h"
43 #include "InspectorInstrumentation.h"
44 #include "MemoryCache.h"
45 #include "ResourceError.h"
46 #include "ResourceRequest.h"
47 #include "ScriptCallStack.h"
48 #include "ScriptProfile.h"
49 #include "SecurityOrigin.h"
50 #include "Settings.h"
51 #include "SharedBuffer.h"
52 #include "TextResourceDecoder.h"
53 #include "ThreadableLoader.h"
54 #include "XMLHttpRequestException.h"
55 #include "XMLHttpRequestProgressEvent.h"
56 #include "XMLHttpRequestUpload.h"
57 #include "markup.h"
58 #include <wtf/ArrayBuffer.h>
59 #include <wtf/ArrayBufferView.h>
60 #include <wtf/RefCountedLeakCounter.h>
61 #include <wtf/StdLibExtras.h>
62 #include <wtf/UnusedParam.h>
63 #include <wtf/text/CString.h>
64
65 #if USE(JSC)
66 #include "JSDOMBinding.h"
67 #include "JSDOMWindow.h"
68 #include <heap/Strong.h>
69 #include <runtime/JSLock.h>
70 #endif
71
72 namespace WebCore {
73
74 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, xmlHttpRequestCounter, ("XMLHttpRequest"));
75
76 // Histogram enum to see when we can deprecate xhr.send(ArrayBuffer).
77 enum XMLHttpRequestSendArrayBufferOrView {
78     XMLHttpRequestSendArrayBuffer,
79     XMLHttpRequestSendArrayBufferView,
80     XMLHttpRequestSendArrayBufferOrViewMax,
81 };
82
83 struct XMLHttpRequestStaticData {
84     WTF_MAKE_NONCOPYABLE(XMLHttpRequestStaticData); WTF_MAKE_FAST_ALLOCATED;
85 public:
86     XMLHttpRequestStaticData();
87     String m_proxyHeaderPrefix;
88     String m_secHeaderPrefix;
89     HashSet<String, CaseFoldingHash> m_forbiddenRequestHeaders;
90 };
91
92 XMLHttpRequestStaticData::XMLHttpRequestStaticData()
93     : m_proxyHeaderPrefix("proxy-")
94     , m_secHeaderPrefix("sec-")
95 {
96     m_forbiddenRequestHeaders.add("accept-charset");
97     m_forbiddenRequestHeaders.add("accept-encoding");
98     m_forbiddenRequestHeaders.add("access-control-request-headers");
99     m_forbiddenRequestHeaders.add("access-control-request-method");
100     m_forbiddenRequestHeaders.add("connection");
101     m_forbiddenRequestHeaders.add("content-length");
102     m_forbiddenRequestHeaders.add("content-transfer-encoding");
103     m_forbiddenRequestHeaders.add("cookie");
104     m_forbiddenRequestHeaders.add("cookie2");
105     m_forbiddenRequestHeaders.add("date");
106     m_forbiddenRequestHeaders.add("expect");
107     m_forbiddenRequestHeaders.add("host");
108     m_forbiddenRequestHeaders.add("keep-alive");
109     m_forbiddenRequestHeaders.add("origin");
110     m_forbiddenRequestHeaders.add("referer");
111     m_forbiddenRequestHeaders.add("te");
112     m_forbiddenRequestHeaders.add("trailer");
113     m_forbiddenRequestHeaders.add("transfer-encoding");
114     m_forbiddenRequestHeaders.add("upgrade");
115     m_forbiddenRequestHeaders.add("user-agent");
116     m_forbiddenRequestHeaders.add("via");
117 }
118
119 static bool isSetCookieHeader(const AtomicString& name)
120 {
121     return equalIgnoringCase(name, "set-cookie") || equalIgnoringCase(name, "set-cookie2");
122 }
123
124 static void replaceCharsetInMediaType(String& mediaType, const String& charsetValue)
125 {
126     unsigned int pos = 0, len = 0;
127
128     findCharsetInMediaType(mediaType, pos, len);
129
130     if (!len) {
131         // When no charset found, do nothing.
132         return;
133     }
134
135     // Found at least one existing charset, replace all occurrences with new charset.
136     while (len) {
137         mediaType.replace(pos, len, charsetValue);
138         unsigned int start = pos + charsetValue.length();
139         findCharsetInMediaType(mediaType, pos, len, start);
140     }
141 }
142
143 static const XMLHttpRequestStaticData* staticData = 0;
144
145 static const XMLHttpRequestStaticData* createXMLHttpRequestStaticData()
146 {
147     staticData = new XMLHttpRequestStaticData;
148     return staticData;
149 }
150
151 static const XMLHttpRequestStaticData* initializeXMLHttpRequestStaticData()
152 {
153     // Uses dummy to avoid warnings about an unused variable.
154     AtomicallyInitializedStatic(const XMLHttpRequestStaticData*, dummy = createXMLHttpRequestStaticData());
155     return dummy;
156 }
157
158 static void logConsoleError(ScriptExecutionContext* context, const String& message)
159 {
160     if (!context)
161         return;
162     // FIXME: It's not good to report the bad usage without indicating what source line it came from.
163     // We should pass additional parameters so we can tell the console where the mistake occurred.
164     context->addConsoleMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, message);
165 }
166
167 PassRefPtr<XMLHttpRequest> XMLHttpRequest::create(ScriptExecutionContext* context, PassRefPtr<SecurityOrigin> securityOrigin)
168 {
169     RefPtr<XMLHttpRequest> xmlHttpRequest(adoptRef(new XMLHttpRequest(context, securityOrigin)));
170     xmlHttpRequest->suspendIfNeeded();
171
172     return xmlHttpRequest.release();
173 }
174
175 XMLHttpRequest::XMLHttpRequest(ScriptExecutionContext* context, PassRefPtr<SecurityOrigin> securityOrigin)
176     : ActiveDOMObject(context, this)
177     , m_async(true)
178     , m_includeCredentials(false)
179 #if ENABLE(XHR_TIMEOUT)
180     , m_timeoutMilliseconds(0)
181 #endif
182     , m_state(UNSENT)
183     , m_createdDocument(false)
184     , m_error(false)
185     , m_uploadEventsAllowed(true)
186     , m_uploadComplete(false)
187     , m_sameOriginRequest(true)
188     , m_receivedLength(0)
189     , m_lastSendLineNumber(0)
190     , m_exceptionCode(0)
191     , m_progressEventThrottle(this)
192     , m_responseTypeCode(ResponseTypeDefault)
193     , m_securityOrigin(securityOrigin)
194 {
195     initializeXMLHttpRequestStaticData();
196 #ifndef NDEBUG
197     xmlHttpRequestCounter.increment();
198 #endif
199 }
200
201 XMLHttpRequest::~XMLHttpRequest()
202 {
203 #ifndef NDEBUG
204     xmlHttpRequestCounter.decrement();
205 #endif
206 }
207
208 Document* XMLHttpRequest::document() const
209 {
210     ASSERT(scriptExecutionContext()->isDocument());
211     return static_cast<Document*>(scriptExecutionContext());
212 }
213
214 SecurityOrigin* XMLHttpRequest::securityOrigin() const
215 {
216     return m_securityOrigin ? m_securityOrigin.get() : scriptExecutionContext()->securityOrigin();
217 }
218
219 #if ENABLE(DASHBOARD_SUPPORT)
220 bool XMLHttpRequest::usesDashboardBackwardCompatibilityMode() const
221 {
222     if (scriptExecutionContext()->isWorkerContext())
223         return false;
224     Settings* settings = document()->settings();
225     return settings && settings->usesDashboardBackwardCompatibilityMode();
226 }
227 #endif
228
229 XMLHttpRequest::State XMLHttpRequest::readyState() const
230 {
231     return m_state;
232 }
233
234 String XMLHttpRequest::responseText(ExceptionCode& ec)
235 {
236     if (m_responseTypeCode != ResponseTypeDefault && m_responseTypeCode != ResponseTypeText) {
237         ec = INVALID_STATE_ERR;
238         return "";
239     }
240     return m_responseBuilder.toStringPreserveCapacity();
241 }
242
243 Document* XMLHttpRequest::responseXML(ExceptionCode& ec)
244 {
245     if (m_responseTypeCode != ResponseTypeDefault && m_responseTypeCode != ResponseTypeDocument) {
246         ec = INVALID_STATE_ERR;
247         return 0;
248     }
249
250     if (m_error || m_state != DONE)
251         return 0;
252
253     if (!m_createdDocument) {
254         bool isHTML = equalIgnoringCase(responseMIMEType(), "text/html");
255
256         // The W3C spec requires the final MIME type to be some valid XML type, or text/html.
257         // If it is text/html, then the responseType of "document" must have been supplied explicitly.
258         if ((m_response.isHTTP() && !responseIsXML() && !isHTML)
259             || (isHTML && m_responseTypeCode == ResponseTypeDefault)
260             || scriptExecutionContext()->isWorkerContext()) {
261             m_responseDocument = 0;
262         } else {
263             if (isHTML)
264                 m_responseDocument = HTMLDocument::create(0, m_url);
265             else
266                 m_responseDocument = Document::create(0, m_url);
267             // FIXME: Set Last-Modified.
268             m_responseDocument->setContent(m_responseBuilder.toStringPreserveCapacity());
269             m_responseDocument->setSecurityOrigin(securityOrigin());
270             m_responseDocument->setContextFeatures(document()->contextFeatures());
271             if (!m_responseDocument->wellFormed())
272                 m_responseDocument = 0;
273         }
274         m_createdDocument = true;
275     }
276
277     return m_responseDocument.get();
278 }
279
280 Blob* XMLHttpRequest::responseBlob(ExceptionCode& ec)
281 {
282     if (m_responseTypeCode != ResponseTypeBlob) {
283         ec = INVALID_STATE_ERR;
284         return 0;
285     }
286     // We always return null before DONE.
287     if (m_state != DONE)
288         return 0;
289
290     if (!m_responseBlob) {
291         // FIXME: This causes two (or more) unnecessary copies of the data.
292         // Chromium stores blob data in the browser process, so we're pulling the data
293         // from the network only to copy it into the renderer to copy it back to the browser.
294         // Ideally we'd get the blob/file-handle from the ResourceResponse directly
295         // instead of copying the bytes. Embedders who store blob data in the
296         // same process as WebCore would at least to teach BlobData to take
297         // a SharedBuffer, even if they don't get the Blob from the network layer directly.
298         OwnPtr<BlobData> blobData = BlobData::create();
299         // If we errored out or got no data, we still return a blob, just an empty one.
300         size_t size = 0;
301         if (m_binaryResponseBuilder) {
302             RefPtr<RawData> rawData = RawData::create();
303             size = m_binaryResponseBuilder->size();
304             rawData->mutableData()->append(m_binaryResponseBuilder->data(), size);
305             blobData->appendData(rawData, 0, BlobDataItem::toEndOfFile);
306             blobData->setContentType(responseMIMEType()); // responseMIMEType defaults to text/xml which may be incorrect.
307             m_binaryResponseBuilder.clear();
308         }
309         m_responseBlob = Blob::create(blobData.release(), size);
310     }
311
312     return m_responseBlob.get();
313 }
314
315 ArrayBuffer* XMLHttpRequest::responseArrayBuffer(ExceptionCode& ec)
316 {
317     if (m_responseTypeCode != ResponseTypeArrayBuffer) {
318         ec = INVALID_STATE_ERR;
319         return 0;
320     }
321
322     if (m_state != DONE)
323         return 0;
324
325     if (!m_responseArrayBuffer.get() && m_binaryResponseBuilder.get() && m_binaryResponseBuilder->size() > 0) {
326         m_responseArrayBuffer = ArrayBuffer::create(const_cast<char*>(m_binaryResponseBuilder->data()), static_cast<unsigned>(m_binaryResponseBuilder->size()));
327         m_binaryResponseBuilder.clear();
328     }
329
330     return m_responseArrayBuffer.get();
331 }
332
333 #if ENABLE(XHR_TIMEOUT)
334 void XMLHttpRequest::setTimeout(unsigned long timeout, ExceptionCode& ec)
335 {
336     // FIXME: Need to trigger or update the timeout Timer here, if needed. http://webkit.org/b/98156
337     // XHR2 spec, 4.7.3. "This implies that the timeout attribute can be set while fetching is in progress. If that occurs it will still be measured relative to the start of fetching."
338     if (scriptExecutionContext()->isDocument() && !m_async) {
339         logConsoleError(scriptExecutionContext(), "XMLHttpRequest.timeout cannot be set for synchronous HTTP(S) requests made from the window context.");
340         ec = INVALID_ACCESS_ERR;
341         return;
342     }
343     m_timeoutMilliseconds = timeout;
344 }
345 #endif
346
347 void XMLHttpRequest::setResponseType(const String& responseType, ExceptionCode& ec)
348 {
349     if (m_state >= LOADING) {
350         ec = INVALID_STATE_ERR;
351         return;
352     }
353
354     // Newer functionality is not available to synchronous requests in window contexts, as a spec-mandated 
355     // attempt to discourage synchronous XHR use. responseType is one such piece of functionality.
356     // We'll only disable this functionality for HTTP(S) requests since sync requests for local protocols
357     // such as file: and data: still make sense to allow.
358     if (!m_async && scriptExecutionContext()->isDocument() && m_url.protocolIsInHTTPFamily()) {
359         logConsoleError(scriptExecutionContext(), "XMLHttpRequest.responseType cannot be changed for synchronous HTTP(S) requests made from the window context.");
360         ec = INVALID_ACCESS_ERR;
361         return;
362     }
363
364     if (responseType == "")
365         m_responseTypeCode = ResponseTypeDefault;
366     else if (responseType == "text")
367         m_responseTypeCode = ResponseTypeText;
368     else if (responseType == "document")
369         m_responseTypeCode = ResponseTypeDocument;
370     else if (responseType == "blob")
371         m_responseTypeCode = ResponseTypeBlob;
372     else if (responseType == "arraybuffer")
373         m_responseTypeCode = ResponseTypeArrayBuffer;
374     else
375         logConsoleError(scriptExecutionContext(), "XMLHttpRequest.responseType \"" + responseType + "\" is not supported.");
376 }
377
378 String XMLHttpRequest::responseType()
379 {
380     switch (m_responseTypeCode) {
381     case ResponseTypeDefault:
382         return "";
383     case ResponseTypeText:
384         return "text";
385     case ResponseTypeDocument:
386         return "document";
387     case ResponseTypeBlob:
388         return "blob";
389     case ResponseTypeArrayBuffer:
390         return "arraybuffer";
391     }
392     return "";
393 }
394
395 XMLHttpRequestUpload* XMLHttpRequest::upload()
396 {
397     if (!m_upload)
398         m_upload = XMLHttpRequestUpload::create(this);
399     return m_upload.get();
400 }
401
402 void XMLHttpRequest::changeState(State newState)
403 {
404     if (m_state != newState) {
405         m_state = newState;
406         callReadyStateChangeListener();
407     }
408 }
409
410 void XMLHttpRequest::callReadyStateChangeListener()
411 {
412     if (!scriptExecutionContext())
413         return;
414
415     InspectorInstrumentationCookie cookie = InspectorInstrumentation::willDispatchXHRReadyStateChangeEvent(scriptExecutionContext(), this);
416
417     if (m_async || (m_state <= OPENED || m_state == DONE))
418         m_progressEventThrottle.dispatchReadyStateChangeEvent(XMLHttpRequestProgressEvent::create(eventNames().readystatechangeEvent), m_state == DONE ? FlushProgressEvent : DoNotFlushProgressEvent);
419
420     InspectorInstrumentation::didDispatchXHRReadyStateChangeEvent(cookie);
421     if (m_state == DONE && !m_error) {
422         InspectorInstrumentationCookie cookie = InspectorInstrumentation::willDispatchXHRLoadEvent(scriptExecutionContext(), this);
423         m_progressEventThrottle.dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().loadEvent));
424         InspectorInstrumentation::didDispatchXHRLoadEvent(cookie);
425         m_progressEventThrottle.dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().loadendEvent));
426     }
427 }
428
429 void XMLHttpRequest::setWithCredentials(bool value, ExceptionCode& ec)
430 {
431     if (m_state > OPENED || m_loader) {
432         ec = INVALID_STATE_ERR;
433         return;
434     }
435
436     m_includeCredentials = value;
437 }
438
439 bool XMLHttpRequest::isAllowedHTTPMethod(const String& method)
440 {
441     return !equalIgnoringCase(method, "TRACE")
442         && !equalIgnoringCase(method, "TRACK")
443         && !equalIgnoringCase(method, "CONNECT");
444 }
445
446 String XMLHttpRequest::uppercaseKnownHTTPMethod(const String& method)
447 {
448     if (equalIgnoringCase(method, "COPY") || equalIgnoringCase(method, "DELETE") || equalIgnoringCase(method, "GET")
449         || equalIgnoringCase(method, "HEAD") || equalIgnoringCase(method, "INDEX") || equalIgnoringCase(method, "LOCK")
450         || equalIgnoringCase(method, "M-POST") || equalIgnoringCase(method, "MKCOL") || equalIgnoringCase(method, "MOVE")
451         || equalIgnoringCase(method, "OPTIONS") || equalIgnoringCase(method, "POST") || equalIgnoringCase(method, "PROPFIND")
452         || equalIgnoringCase(method, "PROPPATCH") || equalIgnoringCase(method, "PUT") || equalIgnoringCase(method, "UNLOCK")) {
453         return method.upper();
454     }
455     return method;
456 }
457
458 bool XMLHttpRequest::isAllowedHTTPHeader(const String& name)
459 {
460     initializeXMLHttpRequestStaticData();
461     return !staticData->m_forbiddenRequestHeaders.contains(name) && !name.startsWith(staticData->m_proxyHeaderPrefix, false)
462         && !name.startsWith(staticData->m_secHeaderPrefix, false);
463 }
464
465 void XMLHttpRequest::open(const String& method, const KURL& url, ExceptionCode& ec)
466 {
467     open(method, url, true, ec);
468 }
469
470 void XMLHttpRequest::open(const String& method, const KURL& url, bool async, ExceptionCode& ec)
471 {
472     internalAbort();
473     State previousState = m_state;
474     m_state = UNSENT;
475     m_error = false;
476     m_uploadComplete = false;
477
478     // clear stuff from possible previous load
479     clearResponse();
480     clearRequest();
481
482     ASSERT(m_state == UNSENT);
483
484     if (!isValidHTTPToken(method)) {
485         ec = SYNTAX_ERR;
486         return;
487     }
488
489     if (!isAllowedHTTPMethod(method)) {
490         ec = SECURITY_ERR;
491         return;
492     }
493
494     if (!scriptExecutionContext()->contentSecurityPolicy()->allowConnectToSource(url)) {
495         // FIXME: Should this be throwing an exception?
496         ec = SECURITY_ERR;
497         return;
498     }
499
500     if (!async && scriptExecutionContext()->isDocument()) {
501         if (document()->settings() && !document()->settings()->syncXHRInDocumentsEnabled()) {
502             logConsoleError(scriptExecutionContext(), "Synchronous XMLHttpRequests are disabled for this page.");
503             ec = INVALID_ACCESS_ERR;
504             return;
505         }
506
507         // Newer functionality is not available to synchronous requests in window contexts, as a spec-mandated
508         // attempt to discourage synchronous XHR use. responseType is one such piece of functionality.
509         // We'll only disable this functionality for HTTP(S) requests since sync requests for local protocols
510         // such as file: and data: still make sense to allow.
511         if (url.protocolIsInHTTPFamily() && m_responseTypeCode != ResponseTypeDefault) {
512             logConsoleError(scriptExecutionContext(), "Synchronous HTTP(S) requests made from the window context cannot have XMLHttpRequest.responseType set.");
513             ec = INVALID_ACCESS_ERR;
514             return;
515         }
516
517 #if ENABLE(XHR_TIMEOUT)
518         // Similarly, timeouts are disabled for synchronous requests as well.
519         if (m_timeoutMilliseconds > 0) {
520             logConsoleError(scriptExecutionContext(), "Synchronous XMLHttpRequests must not have a timeout value set.");
521             ec = INVALID_ACCESS_ERR;
522             return;
523         }
524 #endif
525     }
526
527     m_method = uppercaseKnownHTTPMethod(method);
528
529     m_url = url;
530
531     m_async = async;
532
533     ASSERT(!m_loader);
534
535     // Check previous state to avoid dispatching readyState event
536     // when calling open several times in a row.
537     if (previousState != OPENED)
538         changeState(OPENED);
539     else
540         m_state = OPENED;
541 }
542
543 void XMLHttpRequest::open(const String& method, const KURL& url, bool async, const String& user, ExceptionCode& ec)
544 {
545     KURL urlWithCredentials(url);
546     urlWithCredentials.setUser(user);
547
548     open(method, urlWithCredentials, async, ec);
549 }
550
551 void XMLHttpRequest::open(const String& method, const KURL& url, bool async, const String& user, const String& password, ExceptionCode& ec)
552 {
553     KURL urlWithCredentials(url);
554     urlWithCredentials.setUser(user);
555     urlWithCredentials.setPass(password);
556
557     open(method, urlWithCredentials, async, ec);
558 }
559
560 bool XMLHttpRequest::initSend(ExceptionCode& ec)
561 {
562     if (!scriptExecutionContext())
563         return false;
564
565     if (m_state != OPENED || m_loader) {
566         ec = INVALID_STATE_ERR;
567         return false;
568     }
569
570     m_error = false;
571     return true;
572 }
573
574 void XMLHttpRequest::send(ExceptionCode& ec)
575 {
576     send(String(), ec);
577 }
578
579 void XMLHttpRequest::send(Document* document, ExceptionCode& ec)
580 {
581     ASSERT(document);
582
583     if (!initSend(ec))
584         return;
585
586     if (m_method != "GET" && m_method != "HEAD" && m_url.protocolIsInHTTPFamily()) {
587         String contentType = getRequestHeader("Content-Type");
588         if (contentType.isEmpty()) {
589 #if ENABLE(DASHBOARD_SUPPORT)
590             if (usesDashboardBackwardCompatibilityMode())
591                 setRequestHeaderInternal("Content-Type", "application/x-www-form-urlencoded");
592             else
593 #endif
594                 // FIXME: this should include the charset used for encoding.
595                 setRequestHeaderInternal("Content-Type", "application/xml");
596         }
597
598         // FIXME: According to XMLHttpRequest Level 2, this should use the Document.innerHTML algorithm
599         // from the HTML5 specification to serialize the document.
600         String body = createMarkup(document);
601
602         // FIXME: this should use value of document.inputEncoding to determine the encoding to use.
603         TextEncoding encoding = UTF8Encoding();
604         m_requestEntityBody = FormData::create(encoding.encode(body.characters(), body.length(), EntitiesForUnencodables));
605         if (m_upload)
606             m_requestEntityBody->setAlwaysStream(true);
607     }
608
609     createRequest(ec);
610 }
611
612 void XMLHttpRequest::send(const String& body, ExceptionCode& ec)
613 {
614     if (!initSend(ec))
615         return;
616
617     if (!body.isNull() && m_method != "GET" && m_method != "HEAD" && m_url.protocolIsInHTTPFamily()) {
618         String contentType = getRequestHeader("Content-Type");
619         if (contentType.isEmpty()) {
620 #if ENABLE(DASHBOARD_SUPPORT)
621             if (usesDashboardBackwardCompatibilityMode())
622                 setRequestHeaderInternal("Content-Type", "application/x-www-form-urlencoded");
623             else
624 #endif
625                 setRequestHeaderInternal("Content-Type", "application/xml");
626         } else {
627             replaceCharsetInMediaType(contentType, "UTF-8");
628             m_requestHeaders.set("Content-Type", contentType);
629         }
630
631         m_requestEntityBody = FormData::create(UTF8Encoding().encode(body.characters(), body.length(), EntitiesForUnencodables));
632         if (m_upload)
633             m_requestEntityBody->setAlwaysStream(true);
634     }
635
636     createRequest(ec);
637 }
638
639 void XMLHttpRequest::send(Blob* body, ExceptionCode& ec)
640 {
641     if (!initSend(ec))
642         return;
643
644     if (m_method != "GET" && m_method != "HEAD" && m_url.protocolIsInHTTPFamily()) {
645         // FIXME: Should we set a Content-Type if one is not set.
646         // FIXME: add support for uploading bundles.
647         m_requestEntityBody = FormData::create();
648         if (body->isFile())
649             m_requestEntityBody->appendFile(toFile(body)->path());
650 #if ENABLE(BLOB)
651         else
652             m_requestEntityBody->appendBlob(body->url());
653 #endif
654     }
655
656     createRequest(ec);
657 }
658
659 void XMLHttpRequest::send(DOMFormData* body, ExceptionCode& ec)
660 {
661     if (!initSend(ec))
662         return;
663
664     if (m_method != "GET" && m_method != "HEAD" && m_url.protocolIsInHTTPFamily()) {
665         m_requestEntityBody = FormData::createMultiPart(*(static_cast<FormDataList*>(body)), body->encoding(), document());
666
667         // We need to ask the client to provide the generated file names if needed. When FormData fills the element
668         // for the file, it could set a flag to use the generated file name, i.e. a package file on Mac.
669         m_requestEntityBody->generateFiles(document());
670
671         String contentType = getRequestHeader("Content-Type");
672         if (contentType.isEmpty()) {
673             contentType = makeString("multipart/form-data; boundary=", m_requestEntityBody->boundary().data());
674             setRequestHeaderInternal("Content-Type", contentType);
675         }
676     }
677
678     createRequest(ec);
679 }
680
681 void XMLHttpRequest::send(ArrayBuffer* body, ExceptionCode& ec)
682 {
683     String consoleMessage("ArrayBuffer is deprecated in XMLHttpRequest.send(). Use ArrayBufferView instead.");
684     scriptExecutionContext()->addConsoleMessage(JSMessageSource, LogMessageType, WarningMessageLevel, consoleMessage);
685
686     HistogramSupport::histogramEnumeration("WebCore.XHR.send.ArrayBufferOrView", XMLHttpRequestSendArrayBuffer, XMLHttpRequestSendArrayBufferOrViewMax);
687
688     sendBytesData(body->data(), body->byteLength(), ec);
689 }
690
691 void XMLHttpRequest::send(ArrayBufferView* body, ExceptionCode& ec)
692 {
693     HistogramSupport::histogramEnumeration("WebCore.XHR.send.ArrayBufferOrView", XMLHttpRequestSendArrayBufferView, XMLHttpRequestSendArrayBufferOrViewMax);
694
695     sendBytesData(body->baseAddress(), body->byteLength(), ec);
696 }
697
698 void XMLHttpRequest::sendBytesData(const void* data, size_t length, ExceptionCode& ec)
699 {
700     if (!initSend(ec))
701         return;
702
703     if (m_method != "GET" && m_method != "HEAD" && m_url.protocolIsInHTTPFamily()) {
704         m_requestEntityBody = FormData::create(data, length);
705         if (m_upload)
706             m_requestEntityBody->setAlwaysStream(true);
707     }
708
709     createRequest(ec);
710 }
711
712 void XMLHttpRequest::sendFromInspector(PassRefPtr<FormData> formData, ExceptionCode& ec)
713 {
714     m_requestEntityBody = formData ? formData->deepCopy() : 0;
715     createRequest(ec);
716     m_exceptionCode = ec;
717 }
718
719 void XMLHttpRequest::createRequest(ExceptionCode& ec)
720 {
721 #if ENABLE(BLOB)
722     // Only GET request is supported for blob URL.
723     if (m_url.protocolIs("blob") && m_method != "GET") {
724         ec = XMLHttpRequestException::NETWORK_ERR;
725         return;
726     }
727 #endif
728
729     // The presence of upload event listeners forces us to use preflighting because POSTing to an URL that does not
730     // permit cross origin requests should look exactly like POSTing to an URL that does not respond at all.
731     // Also, only async requests support upload progress events.
732     bool uploadEvents = false;
733     if (m_async) {
734         m_progressEventThrottle.dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().loadstartEvent));
735         if (m_requestEntityBody && m_upload) {
736             uploadEvents = m_upload->hasEventListeners();
737             m_upload->dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().loadstartEvent));
738         }
739     }
740
741     m_sameOriginRequest = securityOrigin()->canRequest(m_url);
742
743     // We also remember whether upload events should be allowed for this request in case the upload listeners are
744     // added after the request is started.
745     m_uploadEventsAllowed = m_sameOriginRequest || uploadEvents || !isSimpleCrossOriginAccessRequest(m_method, m_requestHeaders);
746
747     ResourceRequest request(m_url);
748     request.setHTTPMethod(m_method);
749 #if PLATFORM(CHROMIUM) || PLATFORM(BLACKBERRY)
750     request.setTargetType(ResourceRequest::TargetIsXHR);
751 #endif
752
753     InspectorInstrumentation::willLoadXHR(scriptExecutionContext(), this, m_method, m_url, m_async, m_requestEntityBody ? m_requestEntityBody->deepCopy() : 0, m_requestHeaders, m_includeCredentials);
754
755     if (m_requestEntityBody) {
756         ASSERT(m_method != "GET");
757         ASSERT(m_method != "HEAD");
758         request.setHTTPBody(m_requestEntityBody.release());
759     }
760
761     if (m_requestHeaders.size() > 0)
762         request.addHTTPHeaderFields(m_requestHeaders);
763
764     ThreadableLoaderOptions options;
765     options.sendLoadCallbacks = SendCallbacks;
766     options.sniffContent = DoNotSniffContent;
767     options.preflightPolicy = uploadEvents ? ForcePreflight : ConsiderPreflight;
768     options.allowCredentials = (m_sameOriginRequest || m_includeCredentials) ? AllowStoredCredentials : DoNotAllowStoredCredentials;
769     options.crossOriginRequestPolicy = UseAccessControl;
770     options.securityOrigin = securityOrigin();
771
772 #if ENABLE(XHR_TIMEOUT)
773     if (m_timeoutMilliseconds)
774         request.setTimeoutInterval(m_timeoutMilliseconds / 1000.0);
775 #endif
776
777     m_exceptionCode = 0;
778     m_error = false;
779
780     if (m_async) {
781         if (m_upload)
782             request.setReportUploadProgress(true);
783
784         // ThreadableLoader::create can return null here, for example if we're no longer attached to a page.
785         // This is true while running onunload handlers.
786         // FIXME: Maybe we need to be able to send XMLHttpRequests from onunload, <http://bugs.webkit.org/show_bug.cgi?id=10904>.
787         // FIXME: Maybe create() can return null for other reasons too?
788         m_loader = ThreadableLoader::create(scriptExecutionContext(), this, request, options);
789         if (m_loader) {
790             // Neither this object nor the JavaScript wrapper should be deleted while
791             // a request is in progress because we need to keep the listeners alive,
792             // and they are referenced by the JavaScript wrapper.
793             setPendingActivity(this);
794         }
795     } else {
796         InspectorInstrumentation::willLoadXHRSynchronously(scriptExecutionContext());
797         ThreadableLoader::loadResourceSynchronously(scriptExecutionContext(), request, *this, options);
798         InspectorInstrumentation::didLoadXHRSynchronously(scriptExecutionContext());
799     }
800
801     if (!m_exceptionCode && m_error)
802         m_exceptionCode = XMLHttpRequestException::NETWORK_ERR;
803     ec = m_exceptionCode;
804 }
805
806 void XMLHttpRequest::abort()
807 {
808     // internalAbort() calls dropProtection(), which may release the last reference.
809     RefPtr<XMLHttpRequest> protect(this);
810
811     bool sendFlag = m_loader;
812
813     internalAbort();
814
815     clearResponseBuffers();
816
817     // Clear headers as required by the spec
818     m_requestHeaders.clear();
819
820     if ((m_state <= OPENED && !sendFlag) || m_state == DONE)
821         m_state = UNSENT;
822     else {
823         ASSERT(!m_loader);
824         changeState(DONE);
825         m_state = UNSENT;
826     }
827
828     m_progressEventThrottle.dispatchEventAndLoadEnd(XMLHttpRequestProgressEvent::create(eventNames().abortEvent));
829     if (!m_uploadComplete) {
830         m_uploadComplete = true;
831         if (m_upload && m_uploadEventsAllowed)
832             m_upload->dispatchEventAndLoadEnd(XMLHttpRequestProgressEvent::create(eventNames().abortEvent));
833     }
834 }
835
836 void XMLHttpRequest::internalAbort()
837 {
838     bool hadLoader = m_loader;
839
840     m_error = true;
841
842     // FIXME: when we add the support for multi-part XHR, we will have to think be careful with this initialization.
843     m_receivedLength = 0;
844
845     if (hadLoader) {
846         m_loader->cancel();
847         m_loader = 0;
848     }
849
850     m_decoder = 0;
851
852     InspectorInstrumentation::didFailXHRLoading(scriptExecutionContext(), this);
853
854     if (hadLoader)
855         dropProtection();
856 }
857
858 void XMLHttpRequest::clearResponse()
859 {
860     m_response = ResourceResponse();
861     clearResponseBuffers();
862 }
863
864 void XMLHttpRequest::clearResponseBuffers()
865 {
866     m_responseBuilder.clear();
867     m_createdDocument = false;
868     m_responseDocument = 0;
869     m_responseBlob = 0;
870     m_binaryResponseBuilder.clear();
871     m_responseArrayBuffer.clear();
872 }
873
874 void XMLHttpRequest::clearRequest()
875 {
876     m_requestHeaders.clear();
877     m_requestEntityBody = 0;
878 }
879
880 void XMLHttpRequest::genericError()
881 {
882     clearResponse();
883     clearRequest();
884     m_error = true;
885
886     changeState(DONE);
887 }
888
889 void XMLHttpRequest::networkError()
890 {
891     genericError();
892     m_progressEventThrottle.dispatchEventAndLoadEnd(XMLHttpRequestProgressEvent::create(eventNames().errorEvent));
893     if (!m_uploadComplete) {
894         m_uploadComplete = true;
895         if (m_upload && m_uploadEventsAllowed)
896             m_upload->dispatchEventAndLoadEnd(XMLHttpRequestProgressEvent::create(eventNames().errorEvent));
897     }
898     internalAbort();
899 }
900
901 void XMLHttpRequest::abortError()
902 {
903     genericError();
904     m_progressEventThrottle.dispatchEventAndLoadEnd(XMLHttpRequestProgressEvent::create(eventNames().abortEvent));
905     if (!m_uploadComplete) {
906         m_uploadComplete = true;
907         if (m_upload && m_uploadEventsAllowed)
908             m_upload->dispatchEventAndLoadEnd(XMLHttpRequestProgressEvent::create(eventNames().abortEvent));
909     }
910 }
911
912 void XMLHttpRequest::dropProtection()
913 {
914 #if USE(JSC)
915     // The XHR object itself holds on to the responseText, and
916     // thus has extra cost even independent of any
917     // responseText or responseXML objects it has handed
918     // out. But it is protected from GC while loading, so this
919     // can't be recouped until the load is done, so only
920     // report the extra cost at that point.
921     JSC::JSGlobalData* globalData = scriptExecutionContext()->globalData();
922     JSC::JSLockHolder lock(globalData);
923     globalData->heap.reportExtraMemoryCost(m_responseBuilder.length() * 2);
924 #endif
925
926     unsetPendingActivity(this);
927 }
928
929 void XMLHttpRequest::overrideMimeType(const String& override)
930 {
931     m_mimeTypeOverride = override;
932 }
933
934 void XMLHttpRequest::setRequestHeader(const AtomicString& name, const String& value, ExceptionCode& ec)
935 {
936     if (m_state != OPENED || m_loader) {
937 #if ENABLE(DASHBOARD_SUPPORT)
938         if (usesDashboardBackwardCompatibilityMode())
939             return;
940 #endif
941
942         ec = INVALID_STATE_ERR;
943         return;
944     }
945
946     if (!isValidHTTPToken(name) || !isValidHTTPHeaderValue(value)) {
947         ec = SYNTAX_ERR;
948         return;
949     }
950
951     // A privileged script (e.g. a Dashboard widget) can set any headers.
952     if (!securityOrigin()->canLoadLocalResources() && !isAllowedHTTPHeader(name)) {
953         logConsoleError(scriptExecutionContext(), "Refused to set unsafe header \"" + name + "\"");
954         return;
955     }
956
957     setRequestHeaderInternal(name, value);
958 }
959
960 void XMLHttpRequest::setRequestHeaderInternal(const AtomicString& name, const String& value)
961 {
962     HTTPHeaderMap::AddResult result = m_requestHeaders.add(name, value);
963     if (!result.isNewEntry)
964         result.iterator->value.append(", " + value);
965 }
966
967 String XMLHttpRequest::getRequestHeader(const AtomicString& name) const
968 {
969     return m_requestHeaders.get(name);
970 }
971
972 String XMLHttpRequest::getAllResponseHeaders(ExceptionCode& ec) const
973 {
974     if (m_state < HEADERS_RECEIVED) {
975         ec = INVALID_STATE_ERR;
976         return "";
977     }
978
979     StringBuilder stringBuilder;
980
981     HTTPHeaderSet accessControlExposeHeaderSet;
982     parseAccessControlExposeHeadersAllowList(m_response.httpHeaderField("Access-Control-Expose-Headers"), accessControlExposeHeaderSet);
983     HTTPHeaderMap::const_iterator end = m_response.httpHeaderFields().end();
984     for (HTTPHeaderMap::const_iterator it = m_response.httpHeaderFields().begin(); it!= end; ++it) {
985         // Hide Set-Cookie header fields from the XMLHttpRequest client for these reasons:
986         //     1) If the client did have access to the fields, then it could read HTTP-only
987         //        cookies; those cookies are supposed to be hidden from scripts.
988         //     2) There's no known harm in hiding Set-Cookie header fields entirely; we don't
989         //        know any widely used technique that requires access to them.
990         //     3) Firefox has implemented this policy.
991         if (isSetCookieHeader(it->key) && !securityOrigin()->canLoadLocalResources())
992             continue;
993
994         if (!m_sameOriginRequest && !isOnAccessControlResponseHeaderWhitelist(it->key) && !accessControlExposeHeaderSet.contains(it->key))
995             continue;
996
997         stringBuilder.append(it->key);
998         stringBuilder.append(':');
999         stringBuilder.append(' ');
1000         stringBuilder.append(it->value);
1001         stringBuilder.append('\r');
1002         stringBuilder.append('\n');
1003     }
1004
1005     return stringBuilder.toString();
1006 }
1007
1008 String XMLHttpRequest::getResponseHeader(const AtomicString& name, ExceptionCode& ec) const
1009 {
1010     if (m_state < HEADERS_RECEIVED) {
1011         ec = INVALID_STATE_ERR;
1012         return String();
1013     }
1014
1015     // See comment in getAllResponseHeaders above.
1016     if (isSetCookieHeader(name) && !securityOrigin()->canLoadLocalResources()) {
1017         logConsoleError(scriptExecutionContext(), "Refused to get unsafe header \"" + name + "\"");
1018         return String();
1019     }
1020     
1021     HTTPHeaderSet accessControlExposeHeaderSet;
1022     parseAccessControlExposeHeadersAllowList(m_response.httpHeaderField("Access-Control-Expose-Headers"), accessControlExposeHeaderSet);
1023
1024     if (!m_sameOriginRequest && !isOnAccessControlResponseHeaderWhitelist(name) && !accessControlExposeHeaderSet.contains(name)) {
1025         logConsoleError(scriptExecutionContext(), "Refused to get unsafe header \"" + name + "\"");
1026         return String();
1027     }
1028     return m_response.httpHeaderField(name);
1029 }
1030
1031 String XMLHttpRequest::responseMIMEType() const
1032 {
1033     String mimeType = extractMIMETypeFromMediaType(m_mimeTypeOverride);
1034     if (mimeType.isEmpty()) {
1035         if (m_response.isHTTP())
1036             mimeType = extractMIMETypeFromMediaType(m_response.httpHeaderField("Content-Type"));
1037         else
1038             mimeType = m_response.mimeType();
1039     }
1040     if (mimeType.isEmpty())
1041         mimeType = "text/xml";
1042
1043     return mimeType;
1044 }
1045
1046 bool XMLHttpRequest::responseIsXML() const
1047 {
1048     // FIXME: Remove the lower() call when DOMImplementation.isXMLMIMEType() is modified
1049     //        to do case insensitive MIME type matching.
1050     return DOMImplementation::isXMLMIMEType(responseMIMEType().lower());
1051 }
1052
1053 int XMLHttpRequest::status(ExceptionCode& ec) const
1054 {
1055     if (m_response.httpStatusCode())
1056         return m_response.httpStatusCode();
1057
1058     if (m_state == OPENED) {
1059         // Firefox only raises an exception in this state; we match it.
1060         // Note the case of local file requests, where we have no HTTP response code! Firefox never raises an exception for those, but we match HTTP case for consistency.
1061         ec = INVALID_STATE_ERR;
1062     }
1063
1064     return 0;
1065 }
1066
1067 String XMLHttpRequest::statusText(ExceptionCode& ec) const
1068 {
1069     if (!m_response.httpStatusText().isNull())
1070         return m_response.httpStatusText();
1071
1072     if (m_state == OPENED) {
1073         // See comments in status() above.
1074         ec = INVALID_STATE_ERR;
1075     }
1076
1077     return String();
1078 }
1079
1080 void XMLHttpRequest::didFail(const ResourceError& error)
1081 {
1082
1083     // If we are already in an error state, for instance we called abort(), bail out early.
1084     if (m_error)
1085         return;
1086
1087     if (error.isCancellation()) {
1088         m_exceptionCode = XMLHttpRequestException::ABORT_ERR;
1089         abortError();
1090         return;
1091     }
1092
1093 #if ENABLE(XHR_TIMEOUT)
1094     if (error.isTimeout()) {
1095         didTimeout();
1096         return;
1097     }
1098 #endif
1099
1100     // Network failures are already reported to Web Inspector by ResourceLoader.
1101     if (error.domain() == errorDomainWebKitInternal)
1102         logConsoleError(scriptExecutionContext(), "XMLHttpRequest cannot load " + error.failingURL() + ". " + error.localizedDescription());
1103
1104     m_exceptionCode = XMLHttpRequestException::NETWORK_ERR;
1105     networkError();
1106 }
1107
1108 void XMLHttpRequest::didFailRedirectCheck()
1109 {
1110     networkError();
1111 }
1112
1113 void XMLHttpRequest::didFinishLoading(unsigned long identifier, double)
1114 {
1115     if (m_error)
1116         return;
1117
1118     if (m_state < HEADERS_RECEIVED)
1119         changeState(HEADERS_RECEIVED);
1120
1121     if (m_decoder)
1122         m_responseBuilder.append(m_decoder->flush());
1123
1124     m_responseBuilder.shrinkToFit();
1125
1126     InspectorInstrumentation::didFinishXHRLoading(scriptExecutionContext(), this, identifier, m_responseBuilder.toStringPreserveCapacity(), m_url, m_lastSendURL, m_lastSendLineNumber);
1127
1128     bool hadLoader = m_loader;
1129     m_loader = 0;
1130
1131     changeState(DONE);
1132     m_decoder = 0;
1133
1134     if (hadLoader)
1135         dropProtection();
1136 }
1137
1138 void XMLHttpRequest::didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
1139 {
1140     if (!m_upload)
1141         return;
1142
1143     if (m_uploadEventsAllowed)
1144         m_upload->dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().progressEvent, true, bytesSent, totalBytesToBeSent));
1145
1146     if (bytesSent == totalBytesToBeSent && !m_uploadComplete) {
1147         m_uploadComplete = true;
1148         if (m_uploadEventsAllowed)
1149             m_upload->dispatchEventAndLoadEnd(XMLHttpRequestProgressEvent::create(eventNames().loadEvent));
1150     }
1151 }
1152
1153 void XMLHttpRequest::didReceiveResponse(unsigned long identifier, const ResourceResponse& response)
1154 {
1155     InspectorInstrumentation::didReceiveXHRResponse(scriptExecutionContext(), identifier);
1156
1157     m_response = response;
1158     if (!m_mimeTypeOverride.isEmpty()) {
1159         m_response.setHTTPHeaderField("Content-Type", m_mimeTypeOverride);
1160         m_responseEncoding = extractCharsetFromMediaType(m_mimeTypeOverride);
1161     }
1162
1163     if (m_responseEncoding.isEmpty())
1164         m_responseEncoding = response.textEncodingName();
1165 }
1166
1167 void XMLHttpRequest::didReceiveData(const char* data, int len)
1168 {
1169     if (m_error)
1170         return;
1171
1172     if (m_state < HEADERS_RECEIVED)
1173         changeState(HEADERS_RECEIVED);
1174
1175     bool useDecoder = m_responseTypeCode == ResponseTypeDefault || m_responseTypeCode == ResponseTypeText || m_responseTypeCode == ResponseTypeDocument;
1176
1177     if (useDecoder && !m_decoder) {
1178         if (!m_responseEncoding.isEmpty())
1179             m_decoder = TextResourceDecoder::create("text/plain", m_responseEncoding);
1180         // allow TextResourceDecoder to look inside the m_response if it's XML or HTML
1181         else if (responseIsXML()) {
1182             m_decoder = TextResourceDecoder::create("application/xml");
1183             // Don't stop on encoding errors, unlike it is done for other kinds of XML resources. This matches the behavior of previous WebKit versions, Firefox and Opera.
1184             m_decoder->useLenientXMLDecoding();
1185         } else if (equalIgnoringCase(responseMIMEType(), "text/html"))
1186             m_decoder = TextResourceDecoder::create("text/html", "UTF-8");
1187         else
1188             m_decoder = TextResourceDecoder::create("text/plain", "UTF-8");
1189     }
1190
1191     if (!len)
1192         return;
1193
1194     if (len == -1)
1195         len = strlen(data);
1196
1197     if (useDecoder)
1198         m_responseBuilder.append(m_decoder->decode(data, len));
1199     else if (m_responseTypeCode == ResponseTypeArrayBuffer || m_responseTypeCode == ResponseTypeBlob) {
1200         // Buffer binary data.
1201         if (!m_binaryResponseBuilder)
1202             m_binaryResponseBuilder = SharedBuffer::create();
1203         m_binaryResponseBuilder->append(data, len);
1204     }
1205
1206     if (!m_error) {
1207         long long expectedLength = m_response.expectedContentLength();
1208         m_receivedLength += len;
1209
1210         if (m_async) {
1211             bool lengthComputable = expectedLength > 0 && m_receivedLength <= expectedLength;
1212             unsigned long long total = lengthComputable ? expectedLength : 0;
1213             m_progressEventThrottle.dispatchProgressEvent(lengthComputable, m_receivedLength, total);
1214         }
1215
1216         if (m_state != LOADING)
1217             changeState(LOADING);
1218         else
1219             // Firefox calls readyStateChanged every time it receives data, 4449442
1220             callReadyStateChangeListener();
1221     }
1222 }
1223
1224 #if ENABLE(XHR_TIMEOUT)
1225 void XMLHttpRequest::didTimeout()
1226 {
1227     // internalAbort() calls dropProtection(), which may release the last reference.
1228     RefPtr<XMLHttpRequest> protect(this);
1229     internalAbort();
1230
1231     clearResponse();
1232     clearRequest();
1233
1234     m_error = true;
1235     m_exceptionCode = XMLHttpRequestException::TIMEOUT_ERR;
1236
1237     if (!m_async) {
1238         m_state = DONE;
1239         m_exceptionCode = TIMEOUT_ERR;
1240         return;
1241     }
1242
1243     changeState(DONE);
1244
1245     if (!m_uploadComplete) {
1246         m_uploadComplete = true;
1247         if (m_upload && m_uploadEventsAllowed)
1248             m_upload->dispatchEventAndLoadEnd(XMLHttpRequestProgressEvent::create(eventNames().timeoutEvent));
1249     }
1250     m_progressEventThrottle.dispatchEventAndLoadEnd(XMLHttpRequestProgressEvent::create(eventNames().timeoutEvent));
1251 }
1252 #endif
1253
1254 bool XMLHttpRequest::canSuspend() const
1255 {
1256     return !m_loader;
1257 }
1258
1259 void XMLHttpRequest::suspend(ReasonForSuspension)
1260 {
1261     m_progressEventThrottle.suspend();
1262 }
1263
1264 void XMLHttpRequest::resume()
1265 {
1266     m_progressEventThrottle.resume();
1267 }
1268
1269 void XMLHttpRequest::stop()
1270 {
1271     internalAbort();
1272 }
1273
1274 void XMLHttpRequest::contextDestroyed()
1275 {
1276     ASSERT(!m_loader);
1277     ActiveDOMObject::contextDestroyed();
1278 }
1279
1280 const AtomicString& XMLHttpRequest::interfaceName() const
1281 {
1282     return eventNames().interfaceForXMLHttpRequest;
1283 }
1284
1285 ScriptExecutionContext* XMLHttpRequest::scriptExecutionContext() const
1286 {
1287     return ActiveDOMObject::scriptExecutionContext();
1288 }
1289
1290 EventTargetData* XMLHttpRequest::eventTargetData()
1291 {
1292     return &m_eventTargetData;
1293 }
1294
1295 EventTargetData* XMLHttpRequest::ensureEventTargetData()
1296 {
1297     return &m_eventTargetData;
1298 }
1299
1300 } // namespace WebCore