Support the "json" responseType and JSON response entity in XHR
authorrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 3 Sep 2013 18:45:51 +0000 (18:45 +0000)
committerrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 3 Sep 2013 18:45:51 +0000 (18:45 +0000)
https://bugs.webkit.org/show_bug.cgi?id=73648

Reviewed by Oliver Hunt.

Source/JavaScriptCore:

Based on the patch written by Jarred Nicholls.

Add JSC::JSONParse. This function will be used in XMLHttpRequest.response of type 'json'.

* JavaScriptCore.xcodeproj/project.pbxproj:
* runtime/JSONObject.cpp:
(JSC::JSONParse):
* runtime/JSONObject.h:

Source/WebCore:

Based on the patch written by Jarred Nicholls.

Implement 'json' type for XMLHttpRequest.response. We cache the result on JSC side as a cached attribute
unlike other response types like 'document' and 'blob' for which the parsed response object is cached
in XMLHttpRequest itself. In the long run, we should do the same for other types of response types.

Also refactored the various code to share the code.

Tests: fast/xmlhttprequest/xmlhttprequest-responsetype-json-invalid.html
       fast/xmlhttprequest/xmlhttprequest-responsetype-json-utf16.html
       fast/xmlhttprequest/xmlhttprequest-responsetype-json-valid.html

* ForwardingHeaders/runtime/JSONObject.h: Added.

* bindings/js/JSXMLHttpRequestCustom.cpp:
(WebCore::JSXMLHttpRequest::visitChildren):
(WebCore::JSXMLHttpRequest::response): Use JSONParse to parse the response text and cache the result.
Call didCacheResponseJSON to set the cache status and clear the original response buffer.

* xml/XMLHttpRequest.cpp:
(WebCore::XMLHttpRequest::XMLHttpRequest): Added m_responseCacheIsValid to invalidate the cache of
a json response.
(WebCore::XMLHttpRequest::responseText):
(WebCore::XMLHttpRequest::didCacheResponseJSON): Added; Updates m_responseCacheIsValid and clears the
response buffer to save memory.
(WebCore::XMLHttpRequest::responseXML):
(WebCore::XMLHttpRequest::setResponseType):
(WebCore::XMLHttpRequest::responseType):
(WebCore::XMLHttpRequest::clearResponseBuffers):
(WebCore::XMLHttpRequest::didReceiveData):

* xml/XMLHttpRequest.h:
(WebCore::XMLHttpRequest::doneWithoutErrors): Extracted from responseXML.
(WebCore::XMLHttpRequest::responseTextIgnoringResponseType): Extracted from responseText.
(WebCore::XMLHttpRequest::responseCacheIsValid): Added.
(WebCore::XMLHttpRequest::shouldDecodeResponse): Extracted from didReceiveData.
Also modified to decode when the response type is ResponseTypeJSON.

* xml/XMLHttpRequest.idl: Added CachedAttribute IDL extention on response property. This cache is
used when the response type is 'json'.

LayoutTests:

Add regression tests for XMLHttpRequest.response of type 'json'.

Two of these tests (valid & invalid) come from Jarred Nicholls's original patch.

* fast/xmlhttprequest/resources/xmlhttprequest-responsetype-json-utf-16.json: Added.
* fast/xmlhttprequest/resources/xmlhttprequest-responsetype-json.json: Added.
* fast/xmlhttprequest/xmlhttprequest-responsetype-json-invalid-expected.txt: Added.
* fast/xmlhttprequest/xmlhttprequest-responsetype-json-invalid.html: Added.
* fast/xmlhttprequest/xmlhttprequest-responsetype-json-utf16-expected.txt: Added.
* fast/xmlhttprequest/xmlhttprequest-responsetype-json-utf16.html: Added.
* fast/xmlhttprequest/xmlhttprequest-responsetype-json-valid-expected.txt: Added.
* fast/xmlhttprequest/xmlhttprequest-responsetype-json-valid.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@154992 268f45cc-cd09-0410-ab3c-d52691b4dbfc

19 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/xmlhttprequest/resources/xmlhttprequest-responsetype-json-utf-16.json [new file with mode: 0644]
LayoutTests/fast/xmlhttprequest/resources/xmlhttprequest-responsetype-json.json [new file with mode: 0644]
LayoutTests/fast/xmlhttprequest/xmlhttprequest-responsetype-json-invalid-expected.txt [new file with mode: 0644]
LayoutTests/fast/xmlhttprequest/xmlhttprequest-responsetype-json-invalid.html [new file with mode: 0644]
LayoutTests/fast/xmlhttprequest/xmlhttprequest-responsetype-json-utf16-expected.txt [new file with mode: 0644]
LayoutTests/fast/xmlhttprequest/xmlhttprequest-responsetype-json-utf16.html [new file with mode: 0644]
LayoutTests/fast/xmlhttprequest/xmlhttprequest-responsetype-json-valid-expected.txt [new file with mode: 0644]
LayoutTests/fast/xmlhttprequest/xmlhttprequest-responsetype-json-valid.html [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/runtime/JSONObject.cpp
Source/JavaScriptCore/runtime/JSONObject.h
Source/WebCore/ChangeLog
Source/WebCore/ForwardingHeaders/runtime/JSONObject.h [new file with mode: 0644]
Source/WebCore/bindings/js/JSXMLHttpRequestCustom.cpp
Source/WebCore/xml/XMLHttpRequest.cpp
Source/WebCore/xml/XMLHttpRequest.h
Source/WebCore/xml/XMLHttpRequest.idl

index 50e958a2e520e6d6ae64e34dbcb2730a955853f3..db885ae7c85c6be94771fd24aeb925055ae0c8f7 100644 (file)
@@ -1,3 +1,23 @@
+2013-09-02  Ryosuke Niwa  <rniwa@webkit.org>
+
+        Support the "json" responseType and JSON response entity in XHR
+        https://bugs.webkit.org/show_bug.cgi?id=73648
+
+        Reviewed by Oliver Hunt.
+
+        Add regression tests for XMLHttpRequest.response of type 'json'.
+
+        Two of these tests (valid & invalid) come from Jarred Nicholls's original patch.
+
+        * fast/xmlhttprequest/resources/xmlhttprequest-responsetype-json-utf-16.json: Added.
+        * fast/xmlhttprequest/resources/xmlhttprequest-responsetype-json.json: Added.
+        * fast/xmlhttprequest/xmlhttprequest-responsetype-json-invalid-expected.txt: Added.
+        * fast/xmlhttprequest/xmlhttprequest-responsetype-json-invalid.html: Added.
+        * fast/xmlhttprequest/xmlhttprequest-responsetype-json-utf16-expected.txt: Added.
+        * fast/xmlhttprequest/xmlhttprequest-responsetype-json-utf16.html: Added.
+        * fast/xmlhttprequest/xmlhttprequest-responsetype-json-valid-expected.txt: Added.
+        * fast/xmlhttprequest/xmlhttprequest-responsetype-json-valid.html: Added.
+
 2013-09-03  Commit Queue  <commit-queue@webkit.org>
 
         Unreviewed, rolling out r154881.
diff --git a/LayoutTests/fast/xmlhttprequest/resources/xmlhttprequest-responsetype-json-utf-16.json b/LayoutTests/fast/xmlhttprequest/resources/xmlhttprequest-responsetype-json-utf-16.json
new file mode 100644 (file)
index 0000000..208220e
Binary files /dev/null and b/LayoutTests/fast/xmlhttprequest/resources/xmlhttprequest-responsetype-json-utf-16.json differ
diff --git a/LayoutTests/fast/xmlhttprequest/resources/xmlhttprequest-responsetype-json.json b/LayoutTests/fast/xmlhttprequest/resources/xmlhttprequest-responsetype-json.json
new file mode 100644 (file)
index 0000000..fc60dac
--- /dev/null
@@ -0,0 +1,5 @@
+{
+    "a": ["b", 1, {"c": "d"}],
+    "e": 2,
+    "f": "g"
+}
diff --git a/LayoutTests/fast/xmlhttprequest/xmlhttprequest-responsetype-json-invalid-expected.txt b/LayoutTests/fast/xmlhttprequest/xmlhttprequest-responsetype-json-invalid-expected.txt
new file mode 100644 (file)
index 0000000..236adac
--- /dev/null
@@ -0,0 +1,10 @@
+Tests XMLHttpRequest.responseType of "json" with an invalid payload.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS xhr.response is null
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/xmlhttprequest/xmlhttprequest-responsetype-json-invalid.html b/LayoutTests/fast/xmlhttprequest/xmlhttprequest-responsetype-json-invalid.html
new file mode 100644 (file)
index 0000000..3135d44
--- /dev/null
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../js/resources/js-test-pre.js"></script>
+<script>
+window.jsTestIsAsync = true;
+description('Tests XMLHttpRequest.responseType of "json" with an invalid payload.');
+
+var xhr = new XMLHttpRequest();
+var url = 'resources/xmlhttprequest-get-data.xml';
+
+xhr.open('GET', url);
+xhr.responseType = 'json';
+xhr.onload = function() {
+    shouldBeNull('xhr.response');
+    finishJSTest();
+};
+xhr.onerror = function() {
+    testFailed('An error occurred while loading "' + url + '"');
+    finishJSTest();
+};
+xhr.send(null);
+</script>
+<script src="../js/resources/js-test-post.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+</body>
+</html>
diff --git a/LayoutTests/fast/xmlhttprequest/xmlhttprequest-responsetype-json-utf16-expected.txt b/LayoutTests/fast/xmlhttprequest/xmlhttprequest-responsetype-json-utf16-expected.txt
new file mode 100644 (file)
index 0000000..5f7c41c
--- /dev/null
@@ -0,0 +1,10 @@
+Tests XMLHttpRequest.responseType of "json" fails to parse if the payload was encoded with UTF-16.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+FAIL jsonXHR.response should be null. Was [object Object].
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/xmlhttprequest/xmlhttprequest-responsetype-json-utf16.html b/LayoutTests/fast/xmlhttprequest/xmlhttprequest-responsetype-json-utf16.html
new file mode 100644 (file)
index 0000000..5e255db
--- /dev/null
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../js/resources/js-test-pre.js"></script>
+<script>
+window.jsTestIsAsync = true;
+description('Tests XMLHttpRequest.responseType of "json" fails to parse if the payload was encoded with UTF-16.');
+
+var jsonXHR = new XMLHttpRequest();
+var textXHR = new XMLHttpRequest();
+var jsonUrl = 'resources/xmlhttprequest-responsetype-json-utf-16.json';
+
+jsonXHR.open('GET', jsonUrl);
+jsonXHR.responseType = 'json';
+jsonXHR.onload = function() {
+    shouldBeNull('jsonXHR.response');
+    finishJSTest();
+};
+jsonXHR.onerror = function() {
+    testFailed('An error occurred while loading "' + jsonUrl + '"');
+    finishJSTest();
+};
+jsonXHR.send(null);
+</script>
+<script src="../js/resources/js-test-post.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+</body>
+</html>
diff --git a/LayoutTests/fast/xmlhttprequest/xmlhttprequest-responsetype-json-valid-expected.txt b/LayoutTests/fast/xmlhttprequest/xmlhttprequest-responsetype-json-valid-expected.txt
new file mode 100644 (file)
index 0000000..86fe3cf
--- /dev/null
@@ -0,0 +1,14 @@
+Tests XMLHttpRequest.responseType of "json" with a valid payload.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS jsonXHR.response is null
+PASS jsonXHR.response is non-null.
+PASS jsonXHR.response is jsonXHR.response
+PASS JSON.stringify(jsonXHR.response) is JSON.stringify(JSON.parse(textXHR.responseText))
+PASS jsonXHR.open("GET", jsonUrl); jsonXHR.response is null
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/xmlhttprequest/xmlhttprequest-responsetype-json-valid.html b/LayoutTests/fast/xmlhttprequest/xmlhttprequest-responsetype-json-valid.html
new file mode 100644 (file)
index 0000000..444cdbe
--- /dev/null
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../js/resources/js-test-pre.js"></script>
+<script>
+window.jsTestIsAsync = true;
+description('Tests XMLHttpRequest.responseType of "json" with a valid payload.');
+
+var jsonXHR = new XMLHttpRequest();
+var textXHR = new XMLHttpRequest();
+var jsonUrl = 'resources/xmlhttprequest-responsetype-json.json';
+var response;
+var responseText;
+
+jsonXHR.open('GET', jsonUrl);
+jsonXHR.responseType = 'json';
+jsonXHR.onload = function() {
+    shouldBeNonNull('jsonXHR.response');
+    shouldBe('jsonXHR.response', 'jsonXHR.response');
+
+    textXHR.open('GET', jsonUrl);
+    textXHR.onload = function() {
+        shouldBe('JSON.stringify(jsonXHR.response)', 'JSON.stringify(JSON.parse(textXHR.responseText))');
+
+        // When calling open() to reuse an XHR instance, the cached response
+        // should have been cleared.
+        shouldBeNull('jsonXHR.open("GET", jsonUrl); jsonXHR.response');
+
+        finishJSTest();
+    };
+    textXHR.onerror = function() {
+        testFailed('An error occurred while loading "' + jsonUrl + '"');
+        finishJSTest();
+    };
+    textXHR.send(null);
+};
+jsonXHR.onerror = function() {
+    testFailed('An error occurred while loading "' + jsonUrl + '"');
+    finishJSTest();
+};
+
+shouldBeNull('jsonXHR.response');
+jsonXHR.send(null);
+</script>
+<script src="../js/resources/js-test-post.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+</body>
+</html>
\ No newline at end of file
index 7f9da153473d6e6112a88bee4fb2bfebfcff18b0..1ac7d151a3a6389e26bb593a5b5e6019f627a5eb 100644 (file)
@@ -1,3 +1,19 @@
+2013-09-02  Ryosuke Niwa  <rniwa@webkit.org>
+
+        Support the "json" responseType and JSON response entity in XHR
+        https://bugs.webkit.org/show_bug.cgi?id=73648
+
+        Reviewed by Oliver Hunt.
+
+        Based on the patch written by Jarred Nicholls.
+
+        Add JSC::JSONParse. This function will be used in XMLHttpRequest.response of type 'json'.
+
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * runtime/JSONObject.cpp:
+        (JSC::JSONParse):
+        * runtime/JSONObject.h:
+
 2013-09-02  Filip Pizlo  <fpizlo@apple.com>
 
         CodeBlock::jettison() should be implicit
index 86c9d9e9c82bfff56b7ab6aeab2079c56a9e8c94..5905d8d8cad502a703b54df127cb3de7c40e6c10 100644 (file)
                A7E5AB3A1799E4B200D2833D /* X86Disassembler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7E5AB361799E4B200D2833D /* X86Disassembler.cpp */; };
                A7F2996B17A0BB670010417A /* FTLFail.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7F2996917A0BB670010417A /* FTLFail.cpp */; };
                A7F2996C17A0BB670010417A /* FTLFail.h in Headers */ = {isa = PBXBuildFile; fileRef = A7F2996A17A0BB670010417A /* FTLFail.h */; settings = {ATTRIBUTES = (Private, ); }; };
-               A7F9935F0FD7325100A0B2D0 /* JSONObject.h in Headers */ = {isa = PBXBuildFile; fileRef = A7F9935D0FD7325100A0B2D0 /* JSONObject.h */; };
+               A7F9935F0FD7325100A0B2D0 /* JSONObject.h in Headers */ = {isa = PBXBuildFile; fileRef = A7F9935D0FD7325100A0B2D0 /* JSONObject.h */; settings = {ATTRIBUTES = (Private, ); }; };
                A7F993600FD7325100A0B2D0 /* JSONObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7F9935E0FD7325100A0B2D0 /* JSONObject.cpp */; };
                A7FB60A4103F7DC20017A286 /* PropertyDescriptor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7FB60A3103F7DC20017A286 /* PropertyDescriptor.cpp */; };
                A7FB61001040C38B0017A286 /* PropertyDescriptor.h in Headers */ = {isa = PBXBuildFile; fileRef = A7FB604B103F5EAB0017A286 /* PropertyDescriptor.h */; settings = {ATTRIBUTES = (Private, ); }; };
index 2c2ccd8db2d261501d7ad334662503366c20fccd..678fa88ddc5c3f609cc3fe5358dd9e8d8cbf5568 100644 (file)
@@ -819,6 +819,19 @@ EncodedJSValue JSC_HOST_CALL JSONProtoFuncStringify(ExecState* exec)
     return JSValue::encode(result);
 }
 
+JSValue JSONParse(ExecState* exec, const String& json)
+{
+    LocalScope scope(exec->vm());
+
+    if (json.is8Bit()) {
+        LiteralParser<LChar> jsonParser(exec, json.characters8(), json.length(), StrictJSON);
+        return jsonParser.tryLiteralParse();
+    }
+
+    LiteralParser<UChar> jsonParser(exec, json.characters16(), json.length(), StrictJSON);
+    return jsonParser.tryLiteralParse();
+}
+
 String JSONStringify(ExecState* exec, JSValue value, unsigned indent)
 {
     LocalScope scope(exec->vm());
index 56fc3777c999179a8c53e02ae0682c3dc84c936a..59f19c15686bac5d50cddf0e95aab78e9f7a02f8 100644 (file)
@@ -60,6 +60,7 @@ namespace JSC {
 
     };
 
+    JS_EXPORT_PRIVATE JSValue JSONParse(ExecState*, const String&);
     String JSONStringify(ExecState*, JSValue, unsigned indent);
 
 } // namespace JSC
index 5abcdf03a90d1f6befb18bed75632dbf12fab320..34963658cb704c792eddcbc378c701435ba3c937 100644 (file)
@@ -1,3 +1,51 @@
+2013-09-02  Ryosuke Niwa  <rniwa@webkit.org>
+
+        Support the "json" responseType and JSON response entity in XHR
+        https://bugs.webkit.org/show_bug.cgi?id=73648
+
+        Reviewed by Oliver Hunt.
+
+        Based on the patch written by Jarred Nicholls.
+
+        Implement 'json' type for XMLHttpRequest.response. We cache the result on JSC side as a cached attribute
+        unlike other response types like 'document' and 'blob' for which the parsed response object is cached
+        in XMLHttpRequest itself. In the long run, we should do the same for other types of response types.
+
+        Also refactored the various code to share the code.
+
+        Tests: fast/xmlhttprequest/xmlhttprequest-responsetype-json-invalid.html
+               fast/xmlhttprequest/xmlhttprequest-responsetype-json-utf16.html
+               fast/xmlhttprequest/xmlhttprequest-responsetype-json-valid.html
+
+        * ForwardingHeaders/runtime/JSONObject.h: Added.
+
+        * bindings/js/JSXMLHttpRequestCustom.cpp:
+        (WebCore::JSXMLHttpRequest::visitChildren):
+        (WebCore::JSXMLHttpRequest::response): Use JSONParse to parse the response text and cache the result.
+        Call didCacheResponseJSON to set the cache status and clear the original response buffer.
+
+        * xml/XMLHttpRequest.cpp:
+        (WebCore::XMLHttpRequest::XMLHttpRequest): Added m_responseCacheIsValid to invalidate the cache of
+        a json response.
+        (WebCore::XMLHttpRequest::responseText):
+        (WebCore::XMLHttpRequest::didCacheResponseJSON): Added; Updates m_responseCacheIsValid and clears the
+        response buffer to save memory.
+        (WebCore::XMLHttpRequest::responseXML):
+        (WebCore::XMLHttpRequest::setResponseType):
+        (WebCore::XMLHttpRequest::responseType):
+        (WebCore::XMLHttpRequest::clearResponseBuffers):
+        (WebCore::XMLHttpRequest::didReceiveData):
+
+        * xml/XMLHttpRequest.h:
+        (WebCore::XMLHttpRequest::doneWithoutErrors): Extracted from responseXML.
+        (WebCore::XMLHttpRequest::responseTextIgnoringResponseType): Extracted from responseText.
+        (WebCore::XMLHttpRequest::responseCacheIsValid): Added.
+        (WebCore::XMLHttpRequest::shouldDecodeResponse): Extracted from didReceiveData.
+        Also modified to decode when the response type is ResponseTypeJSON.
+
+        * xml/XMLHttpRequest.idl: Added CachedAttribute IDL extention on response property. This cache is
+        used when the response type is 'json'.
+
 2013-09-03  Commit Queue  <commit-queue@webkit.org>
 
         Unreviewed, rolling out r154881.
diff --git a/Source/WebCore/ForwardingHeaders/runtime/JSONObject.h b/Source/WebCore/ForwardingHeaders/runtime/JSONObject.h
new file mode 100644 (file)
index 0000000..8a84c77
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef WebCore_FWD_JSONObject_h
+#define WebCore_FWD_JSONObject_h
+#include <JavaScriptCore/JSONObject.h>
+#endif
index 229aa0ebebd65ffef616e90ab6f12db0dd9190b0..bb737c44de5434218816674e0e27f3d53d2f19ad 100644 (file)
@@ -50,6 +50,7 @@
 #include <runtime/Error.h>
 #include <runtime/JSArrayBuffer.h>
 #include <runtime/JSArrayBufferView.h>
+#include <runtime/JSONObject.h>
 
 using namespace JSC;
 
@@ -75,6 +76,9 @@ void JSXMLHttpRequest::visitChildren(JSCell* cell, SlotVisitor& visitor)
     if (Blob* responseBlob = thisObject->m_impl->optionalResponseBlob())
         visitor.addOpaqueRoot(responseBlob);
 
+    if (thisObject->m_response)
+        visitor.append(&thisObject->m_response);
+
     thisObject->m_impl->visitJSEventListeners(visitor);
 }
 
@@ -168,6 +172,26 @@ JSValue JSXMLHttpRequest::response(ExecState* exec) const
     case XMLHttpRequest::ResponseTypeText:
         return responseText(exec);
 
+    case XMLHttpRequest::ResponseTypeJSON:
+        {
+            // FIXME: Use CachedAttribute for other types as well.
+            if (m_response && impl()->responseCacheIsValid())
+                return m_response.get();
+
+            if (!impl()->doneWithoutErrors())
+                return jsNull();
+
+            JSValue value = JSONParse(exec, impl()->responseTextIgnoringResponseType());
+            if (!value)
+                value = jsNull();
+            JSXMLHttpRequest* jsRequest = const_cast<JSXMLHttpRequest*>(this);
+            jsRequest->m_response.set(exec->vm(), jsRequest, value);
+
+            impl()->didCacheResponseJSON();
+
+            return value;
+        }
+
     case XMLHttpRequest::ResponseTypeDocument:
         {
             ExceptionCode ec = 0;
index db0b213f47c0985df614ca5edbdd0acc562d6a06..297abf2698022c63bd8810767bfe9d7ecc36d904 100644 (file)
@@ -192,6 +192,7 @@ XMLHttpRequest::XMLHttpRequest(ScriptExecutionContext* context)
     , m_exceptionCode(0)
     , m_progressEventThrottle(this)
     , m_responseTypeCode(ResponseTypeDefault)
+    , m_responseCacheIsValid(false)
 {
     initializeXMLHttpRequestStaticData();
 #ifndef NDEBUG
@@ -238,7 +239,14 @@ String XMLHttpRequest::responseText(ExceptionCode& ec)
         ec = INVALID_STATE_ERR;
         return "";
     }
-    return m_responseBuilder.toStringPreserveCapacity();
+    return responseTextIgnoringResponseType();
+}
+
+void XMLHttpRequest::didCacheResponseJSON()
+{
+    ASSERT(m_responseTypeCode == ResponseTypeJSON && doneWithoutErrors());
+    m_responseCacheIsValid = true;
+    m_responseBuilder.clear();
 }
 
 Document* XMLHttpRequest::responseXML(ExceptionCode& ec)
@@ -248,7 +256,7 @@ Document* XMLHttpRequest::responseXML(ExceptionCode& ec)
         return 0;
     }
 
-    if (m_error || m_state != DONE)
+    if (!doneWithoutErrors())
         return 0;
 
     if (!m_createdDocument) {
@@ -362,6 +370,8 @@ void XMLHttpRequest::setResponseType(const String& responseType, ExceptionCode&
         m_responseTypeCode = ResponseTypeDefault;
     else if (responseType == "text")
         m_responseTypeCode = ResponseTypeText;
+    else if (responseType == "json")
+        m_responseTypeCode = ResponseTypeJSON;
     else if (responseType == "document")
         m_responseTypeCode = ResponseTypeDocument;
     else if (responseType == "blob")
@@ -379,6 +389,8 @@ String XMLHttpRequest::responseType()
         return "";
     case ResponseTypeText:
         return "text";
+    case ResponseTypeJSON:
+        return "json";
     case ResponseTypeDocument:
         return "document";
     case ResponseTypeBlob:
@@ -887,6 +899,7 @@ void XMLHttpRequest::clearResponseBuffers()
     m_responseBlob = 0;
     m_binaryResponseBuilder.clear();
     m_responseArrayBuffer.clear();
+    m_responseCacheIsValid = false;
 }
 
 void XMLHttpRequest::clearRequest()
@@ -1189,7 +1202,7 @@ void XMLHttpRequest::didReceiveData(const char* data, int len)
     if (m_state < HEADERS_RECEIVED)
         changeState(HEADERS_RECEIVED);
 
-    bool useDecoder = m_responseTypeCode == ResponseTypeDefault || m_responseTypeCode == ResponseTypeText || m_responseTypeCode == ResponseTypeDocument;
+    bool useDecoder = shouldDecodeResponse();
 
     if (useDecoder && !m_decoder) {
         if (!m_responseEncoding.isEmpty())
index 41948ffdd86536e320e7e9d94457b87635425309..f90cfee737a53747546174a72383f1f6c17cdfef 100644 (file)
@@ -68,11 +68,15 @@ public:
     
     enum ResponseTypeCode {
         ResponseTypeDefault,
-        ResponseTypeText, 
+        ResponseTypeText,
+        ResponseTypeJSON,
         ResponseTypeDocument,
+
+        // Binary format
         ResponseTypeBlob,
         ResponseTypeArrayBuffer
     };
+    static const ResponseTypeCode FirstBinaryResponseType = ResponseTypeBlob;
 
 #if ENABLE(XHR_TIMEOUT)
     virtual void didTimeout();
@@ -101,9 +105,11 @@ public:
     void abort();
     void setRequestHeader(const AtomicString& name, const String& value, ExceptionCode&);
     void overrideMimeType(const String& override);
+    bool doneWithoutErrors() const { return !m_error && m_state == DONE; }
     String getAllResponseHeaders(ExceptionCode&) const;
     String getResponseHeader(const AtomicString& name, ExceptionCode&) const;
     String responseText(ExceptionCode&);
+    String responseTextIgnoringResponseType() const { return m_responseBuilder.toStringPreserveCapacity(); }
     Document* responseXML(ExceptionCode&);
     Document* optionalResponseXML() const { return m_responseDocument.get(); }
     Blob* responseBlob();
@@ -113,6 +119,9 @@ public:
     void setTimeout(unsigned long timeout, ExceptionCode&);
 #endif
 
+    bool responseCacheIsValid() const { return m_responseCacheIsValid; }
+    void didCacheResponseJSON();
+
     void sendFromInspector(PassRefPtr<FormData>, ExceptionCode&);
 
     // Expose HTTP validation methods for other untrusted requests.
@@ -200,6 +209,8 @@ private:
     void networkError();
     void abortError();
 
+    bool shouldDecodeResponse() const { return m_responseTypeCode < FirstBinaryResponseType; }
+
     OwnPtr<XMLHttpRequestUpload> m_upload;
 
     KURL m_url;
@@ -249,6 +260,7 @@ private:
 
     // An enum corresponding to the allowed string values for the responseType attribute.
     ResponseTypeCode m_responseTypeCode;
+    bool m_responseCacheIsValid;
 };
 
 } // namespace WebCore
index 5965121fc73324c3be23edaaa6b468241e7949fa..f0704feb78f402d9cee61d96fe4655599cfdec7c 100644 (file)
@@ -31,8 +31,7 @@ enum XMLHttpRequestResponseType {
     "arraybuffer",
     "blob",
     "document",
-//    FIXME: enable once support for json responseText is completed. (bug #73648)
-//    "json",
+    "json",
     "text"
 };
 
@@ -87,7 +86,7 @@ enum XMLHttpRequestResponseType {
     [GetterRaisesException] readonly attribute Document responseXML;
 
     [SetterRaisesException] attribute XMLHttpRequestResponseType responseType;
-    [GetterRaisesException, CustomGetter] readonly attribute Object response;
+    [GetterRaisesException, CachedAttribute, CustomGetter] readonly attribute Object response;
 
     [GetterRaisesException] readonly attribute unsigned short status;
     [GetterRaisesException] readonly attribute DOMString statusText;