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
+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.
--- /dev/null
+{
+ "a": ["b", 1, {"c": "d"}],
+ "e": 2,
+ "f": "g"
+}
--- /dev/null
+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
+
--- /dev/null
+<!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>
--- /dev/null
+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
+
--- /dev/null
+<!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>
--- /dev/null
+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
+
--- /dev/null
+<!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
+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
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, ); }; };
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());
};
+ JS_EXPORT_PRIVATE JSValue JSONParse(ExecState*, const String&);
String JSONStringify(ExecState*, JSValue, unsigned indent);
} // namespace JSC
+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.
--- /dev/null
+#ifndef WebCore_FWD_JSONObject_h
+#define WebCore_FWD_JSONObject_h
+#include <JavaScriptCore/JSONObject.h>
+#endif
#include <runtime/Error.h>
#include <runtime/JSArrayBuffer.h>
#include <runtime/JSArrayBufferView.h>
+#include <runtime/JSONObject.h>
using namespace JSC;
if (Blob* responseBlob = thisObject->m_impl->optionalResponseBlob())
visitor.addOpaqueRoot(responseBlob);
+ if (thisObject->m_response)
+ visitor.append(&thisObject->m_response);
+
thisObject->m_impl->visitJSEventListeners(visitor);
}
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;
, m_exceptionCode(0)
, m_progressEventThrottle(this)
, m_responseTypeCode(ResponseTypeDefault)
+ , m_responseCacheIsValid(false)
{
initializeXMLHttpRequestStaticData();
#ifndef NDEBUG
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)
return 0;
}
- if (m_error || m_state != DONE)
+ if (!doneWithoutErrors())
return 0;
if (!m_createdDocument) {
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")
return "";
case ResponseTypeText:
return "text";
+ case ResponseTypeJSON:
+ return "json";
case ResponseTypeDocument:
return "document";
case ResponseTypeBlob:
m_responseBlob = 0;
m_binaryResponseBuilder.clear();
m_responseArrayBuffer.clear();
+ m_responseCacheIsValid = false;
}
void XMLHttpRequest::clearRequest()
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())
enum ResponseTypeCode {
ResponseTypeDefault,
- ResponseTypeText,
+ ResponseTypeText,
+ ResponseTypeJSON,
ResponseTypeDocument,
+
+ // Binary format
ResponseTypeBlob,
ResponseTypeArrayBuffer
};
+ static const ResponseTypeCode FirstBinaryResponseType = ResponseTypeBlob;
#if ENABLE(XHR_TIMEOUT)
virtual void didTimeout();
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();
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.
void networkError();
void abortError();
+ bool shouldDecodeResponse() const { return m_responseTypeCode < FirstBinaryResponseType; }
+
OwnPtr<XMLHttpRequestUpload> m_upload;
KURL m_url;
// An enum corresponding to the allowed string values for the responseType attribute.
ResponseTypeCode m_responseTypeCode;
+ bool m_responseCacheIsValid;
};
} // namespace WebCore
"arraybuffer",
"blob",
"document",
-// FIXME: enable once support for json responseText is completed. (bug #73648)
-// "json",
+ "json",
"text"
};
[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;