diff --git a/content/base/src/nsXMLHttpRequest.cpp b/content/base/src/nsXMLHttpRequest.cpp index 5b8395f17214..77e7d4b8fb9c 100644 --- a/content/base/src/nsXMLHttpRequest.cpp +++ b/content/base/src/nsXMLHttpRequest.cpp @@ -426,7 +426,8 @@ nsXMLHttpRequest::nsXMLHttpRequest() mErrorLoad(PR_FALSE), mTimerIsActive(PR_FALSE), mProgressEventWasDelayed(PR_FALSE), mLoadLengthComputable(PR_FALSE), mLoadTotal(0), - mFirstStartRequestSeen(PR_FALSE) + mFirstStartRequestSeen(PR_FALSE), + mResultArrayBuffer(nsnull) { mResponseBodyUnicode.SetIsVoid(PR_TRUE); nsLayoutStatics::AddRef(); @@ -450,6 +451,12 @@ nsXMLHttpRequest::~nsXMLHttpRequest() nsLayoutStatics::Release(); } +void +nsXMLHttpRequest::RootResultArrayBuffer() +{ + nsContentUtils::PreserveWrapper(static_cast(this), this); +} + /** * This Init method is called from the factory constructor. */ @@ -572,9 +579,9 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXMLHttpRequest, nsIXMLHttpRequestUpload) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END - NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsXMLHttpRequest, nsXHREventTarget) + tmp->mResultArrayBuffer = nsnull; NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mContext) NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mChannel) NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mReadRequest) @@ -592,6 +599,14 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsXMLHttpRequest, NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mUpload) NS_IMPL_CYCLE_COLLECTION_UNLINK_END +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(nsXMLHttpRequest, + nsXHREventTarget) + if(tmp->mResultArrayBuffer) { + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_CALLBACK(tmp->mResultArrayBuffer, + "mResultArrayBuffer") + } +NS_IMPL_CYCLE_COLLECTION_TRACE_END + DOMCI_DATA(XMLHttpRequest, nsXMLHttpRequest) // QueryInterface implementation for nsXMLHttpRequest @@ -839,27 +854,20 @@ NS_IMETHODIMP nsXMLHttpRequest::GetResponseText(nsAString& aResponseText) return rv; } -nsresult nsXMLHttpRequest::GetResponseArrayBuffer(jsval *aResult) +nsresult nsXMLHttpRequest::CreateResponseArrayBuffer(JSContext *aCx) { - JSContext *cx = nsContentUtils::GetCurrentJSContext(); - if (!cx) + if (!aCx) return NS_ERROR_FAILURE; - if (!(mState & (XML_HTTP_REQUEST_DONE | - XML_HTTP_REQUEST_LOADING))) { - *aResult = JSVAL_NULL; - return NS_OK; - } - PRInt32 dataLen = mResponseBody.Length(); - JSObject *obj = js_CreateArrayBuffer(cx, dataLen); - if (!obj) + RootResultArrayBuffer(); + mResultArrayBuffer = js_CreateArrayBuffer(aCx, dataLen); + if (!mResultArrayBuffer) { return NS_ERROR_FAILURE; - - *aResult = OBJECT_TO_JSVAL(obj); + } if (dataLen > 0) { - js::ArrayBuffer *abuf = js::ArrayBuffer::fromJSObject(obj); + js::ArrayBuffer *abuf = js::ArrayBuffer::fromJSObject(mResultArrayBuffer); NS_ASSERTION(abuf, "What happened?"); memcpy(abuf->data, mResponseBody.BeginReading(), dataLen); } @@ -954,7 +962,11 @@ NS_IMETHODIMP nsXMLHttpRequest::GetResponse(JSContext *aCx, jsval *aResult) case XML_HTTP_RESPONSE_TYPE_ARRAYBUFFER: if (mState & XML_HTTP_REQUEST_DONE) { - rv = GetResponseArrayBuffer(aResult); + if (!mResultArrayBuffer) { + rv = CreateResponseArrayBuffer(aCx); + NS_ENSURE_SUCCESS(rv, rv); + } + *aResult = OBJECT_TO_JSVAL(mResultArrayBuffer); } else { *aResult = JSVAL_NULL; } @@ -1073,7 +1085,8 @@ nsXMLHttpRequest::Abort() mResponseBodyUnicode.SetIsVoid(PR_TRUE); mResponseBlob = nsnull; mState |= XML_HTTP_REQUEST_ABORTED; - + mResultArrayBuffer = nsnull; + if (!(mState & (XML_HTTP_REQUEST_UNSENT | XML_HTTP_REQUEST_OPENED | XML_HTTP_REQUEST_DONE))) { diff --git a/content/base/src/nsXMLHttpRequest.h b/content/base/src/nsXMLHttpRequest.h index 2ab09881ed2d..8ee3039d738c 100644 --- a/content/base/src/nsXMLHttpRequest.h +++ b/content/base/src/nsXMLHttpRequest.h @@ -208,11 +208,11 @@ public: void SetRequestObserver(nsIRequestObserver* aObserver); - NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsXMLHttpRequest, + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(nsXMLHttpRequest, nsXHREventTarget) - PRBool AllowUploadProgress(); - + void RootResultArrayBuffer(); + protected: friend class nsMultipartProxyListener; @@ -224,7 +224,7 @@ protected: PRUint32 toOffset, PRUint32 count, PRUint32 *writeCount); - nsresult GetResponseArrayBuffer(jsval *aResult); + nsresult CreateResponseArrayBuffer(JSContext* aCx); void CreateResponseBlob(nsIRequest *request); // Change the state of the object with this. The broadcast argument // determines if the onreadystatechange listener should be called. @@ -345,6 +345,8 @@ protected: nsCOMPtr mRedirectCallback; nsCOMPtr mNewRedirectChannel; + + JSObject* mResultArrayBuffer; }; // helper class to expose a progress DOM Event diff --git a/content/base/test/test_XHR.html b/content/base/test/test_XHR.html index 9052729e6b53..4f370b34969c 100644 --- a/content/base/test/test_XHR.html +++ b/content/base/test/test_XHR.html @@ -134,6 +134,16 @@ ab = xhr.response; ok(ab != null, "should have a non-null arraybuffer"); arraybuffer_equals_to(ab, "\xaa\xee\0\x03\xff\xff\xff\xff\xbb\xbb\xbb\xbb"); +// test array buffer GetResult returns the same object +xhr = new XMLHttpRequest(); +xhr.open("GET", 'file_XHR_binary1.bin', false); +xhr.responseType = 'arraybuffer'; +xhr.send(null) +is(xhr.status, 200, "wrong status"); +checkResponseTextAccessThrows(xhr); +checkResponseXMLAccessThrows(xhr); +is(xhr.response, xhr.response, "returns the same ArrayBuffer"); + // test response (responseType='blob') var onloadCount = 0; function checkOnloadCount() { diff --git a/xpcom/glue/nsCycleCollectionParticipant.h b/xpcom/glue/nsCycleCollectionParticipant.h index 22d8308a5783..02e1b77fe66c 100644 --- a/xpcom/glue/nsCycleCollectionParticipant.h +++ b/xpcom/glue/nsCycleCollectionParticipant.h @@ -436,6 +436,20 @@ public: "not the nsISupports pointer we expect"); \ _class *tmp = Downcast(s); +#define NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(_class, _base_class) \ + void \ + NS_CYCLE_COLLECTION_CLASSNAME(_class)::Trace(void *p, \ + TraceCallback aCallback, \ + void *aClosure) \ + { \ + nsISupports *s = static_cast(p); \ + NS_ASSERTION(CheckForRightISupports(s), \ + "not the nsISupports pointer we expect"); \ + _class *tmp = static_cast<_class*>(Downcast(s)); \ + NS_CYCLE_COLLECTION_CLASSNAME(_base_class)::Trace(s, \ + aCallback, \ + aClosure); + #define NS_IMPL_CYCLE_COLLECTION_TRACE_NATIVE_BEGIN(_class) \ void \ NS_CYCLE_COLLECTION_CLASSNAME(_class)::Trace(void *p, \