зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1218029 - Adds ScriptLoadHandler and implements OnIncrementalData callback. r=djvj
--HG-- extra : commitid : 7TyrlgQ2f2Z
This commit is contained in:
Родитель
66199890c4
Коммит
b984c50fec
|
@ -160,7 +160,7 @@ nsScriptLoader::~nsScriptLoader()
|
|||
}
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsScriptLoader, nsIIncrementalStreamLoaderObserver)
|
||||
NS_IMPL_ISUPPORTS(nsScriptLoader, nsISupports)
|
||||
|
||||
// Helper method for checking if the script element is an event-handler
|
||||
// This means that it has both a for-attribute and a event-attribute.
|
||||
|
@ -269,37 +269,6 @@ nsScriptLoader::ShouldLoadScript(nsIDocument* aDocument,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
class ContextMediator : public nsIIncrementalStreamLoaderObserver
|
||||
{
|
||||
public:
|
||||
explicit ContextMediator(nsScriptLoader *aScriptLoader, nsISupports *aContext)
|
||||
: mScriptLoader(aScriptLoader)
|
||||
, mContext(aContext) {}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIINCREMENTALSTREAMLOADEROBSERVER
|
||||
|
||||
private:
|
||||
virtual ~ContextMediator() {}
|
||||
RefPtr<nsScriptLoader> mScriptLoader;
|
||||
nsCOMPtr<nsISupports> mContext;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(ContextMediator, nsIIncrementalStreamLoaderObserver)
|
||||
|
||||
NS_IMETHODIMP
|
||||
ContextMediator::OnStreamComplete(nsIIncrementalStreamLoader* aLoader,
|
||||
nsISupports* aContext,
|
||||
nsresult aStatus,
|
||||
uint32_t aStringLen,
|
||||
const uint8_t* aString)
|
||||
{
|
||||
// pass arguments through except for the aContext,
|
||||
// we have to mediate and use mContext instead.
|
||||
return mScriptLoader->OnStreamComplete(aLoader, mContext, aStatus,
|
||||
aStringLen, aString);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsScriptLoader::StartLoad(nsScriptLoadRequest *aRequest, const nsAString &aType,
|
||||
bool aScriptFromHead)
|
||||
|
@ -383,10 +352,10 @@ nsScriptLoader::StartLoad(nsScriptLoadRequest *aRequest, const nsAString &aType,
|
|||
timedChannel->SetInitiatorType(NS_LITERAL_STRING("script"));
|
||||
}
|
||||
|
||||
RefPtr<ContextMediator> mediator = new ContextMediator(this, aRequest);
|
||||
RefPtr<nsScriptLoadHandler> handler = new nsScriptLoadHandler(this, aRequest);
|
||||
|
||||
nsCOMPtr<nsIIncrementalStreamLoader> loader;
|
||||
rv = NS_NewIncrementalStreamLoader(getter_AddRefs(loader), mediator);
|
||||
rv = NS_NewIncrementalStreamLoader(getter_AddRefs(loader), handler);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return channel->AsyncOpen2(loader);
|
||||
|
@ -1438,7 +1407,7 @@ nsScriptLoader::ConvertToUTF16(nsIChannel* aChannel, const uint8_t* aData,
|
|||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsresult
|
||||
nsScriptLoader::OnStreamComplete(nsIIncrementalStreamLoader* aLoader,
|
||||
nsISupports* aContext,
|
||||
nsresult aStatus,
|
||||
|
@ -1739,3 +1708,41 @@ nsScriptLoader::MaybeRemovedDeferRequests()
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
nsScriptLoadHandler::nsScriptLoadHandler(nsScriptLoader *aScriptLoader,
|
||||
nsScriptLoadRequest *aRequest)
|
||||
: mScriptLoader(aScriptLoader),
|
||||
mRequest(aRequest)
|
||||
{}
|
||||
|
||||
nsScriptLoadHandler::~nsScriptLoadHandler()
|
||||
{}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsScriptLoadHandler, nsIIncrementalStreamLoaderObserver)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsScriptLoadHandler::OnIncrementalData(nsIIncrementalStreamLoader* aLoader,
|
||||
nsISupports* aContext,
|
||||
uint32_t aDataLength,
|
||||
const uint8_t* aData,
|
||||
uint32_t *aConsumedLength)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsScriptLoadHandler::OnStreamComplete(nsIIncrementalStreamLoader* aLoader,
|
||||
nsISupports* aContext,
|
||||
nsresult aStatus,
|
||||
uint32_t aStringLen,
|
||||
const uint8_t* aString)
|
||||
{
|
||||
// pass arguments through except for the aContext,
|
||||
// we have to mediate and use mRequest instead.
|
||||
return mScriptLoader->OnStreamComplete(aLoader, mRequest, aStatus,
|
||||
aStringLen, aString);
|
||||
}
|
||||
|
|
|
@ -195,7 +195,7 @@ public:
|
|||
// Script loader implementation
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
class nsScriptLoader final : public nsIIncrementalStreamLoaderObserver
|
||||
class nsScriptLoader final : public nsISupports
|
||||
{
|
||||
class MOZ_STACK_CLASS AutoCurrentScriptUpdater
|
||||
{
|
||||
|
@ -223,7 +223,6 @@ public:
|
|||
explicit nsScriptLoader(nsIDocument* aDocument);
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIINCREMENTALSTREAMLOADEROBSERVER
|
||||
|
||||
/**
|
||||
* The loader maintains a weak reference to the document with
|
||||
|
@ -342,6 +341,17 @@ public:
|
|||
nsIDocument* aDocument,
|
||||
char16_t*& aBufOut, size_t& aLengthOut);
|
||||
|
||||
/**
|
||||
* Handle the completion of a stream. This is called by the
|
||||
* nsScriptLoadHandler object which observes the IncrementalStreamLoader
|
||||
* loading the script.
|
||||
*/
|
||||
nsresult OnStreamComplete(nsIIncrementalStreamLoader* aLoader,
|
||||
nsISupports* aContext,
|
||||
nsresult aStatus,
|
||||
uint32_t aStringLen,
|
||||
const uint8_t* aString);
|
||||
|
||||
/**
|
||||
* Processes any pending requests that are ready for processing.
|
||||
*/
|
||||
|
@ -538,6 +548,22 @@ private:
|
|||
bool mBlockingDOMContentLoaded;
|
||||
};
|
||||
|
||||
class nsScriptLoadHandler final : public nsIIncrementalStreamLoaderObserver
|
||||
{
|
||||
public:
|
||||
explicit nsScriptLoadHandler(nsScriptLoader* aScriptLoader,
|
||||
nsScriptLoadRequest *aRequest);
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIINCREMENTALSTREAMLOADEROBSERVER
|
||||
|
||||
private:
|
||||
virtual ~nsScriptLoadHandler();
|
||||
|
||||
RefPtr<nsScriptLoader> mScriptLoader;
|
||||
RefPtr<nsScriptLoadRequest> mRequest;
|
||||
};
|
||||
|
||||
class nsAutoScriptLoaderDisabler
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -325,6 +325,16 @@ class MOZ_STACK_CLASS AutoRejectPromise
|
|||
nsCOMPtr<nsIGlobalObject> mGlobalObject;
|
||||
};
|
||||
|
||||
NS_IMETHODIMP
|
||||
AsyncScriptLoader::OnIncrementalData(nsIIncrementalStreamLoader* aLoader,
|
||||
nsISupports* aContext,
|
||||
uint32_t aDataLength,
|
||||
const uint8_t* aData,
|
||||
uint32_t *aConsumedData)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AsyncScriptLoader::OnStreamComplete(nsIIncrementalStreamLoader* aLoader,
|
||||
nsISupports* aContext,
|
||||
|
@ -769,6 +779,16 @@ NotifyPrecompilationCompleteRunnable::Run(void)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ScriptPrecompiler::OnIncrementalData(nsIIncrementalStreamLoader* aLoader,
|
||||
nsISupports* aContext,
|
||||
uint32_t aDataLength,
|
||||
const uint8_t* aData,
|
||||
uint32_t *aConsumedData)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ScriptPrecompiler::OnStreamComplete(nsIIncrementalStreamLoader* aLoader,
|
||||
nsISupports* aContext,
|
||||
|
|
|
@ -8,9 +8,36 @@
|
|||
interface nsIRequest;
|
||||
interface nsIIncrementalStreamLoader;
|
||||
|
||||
[scriptable, uuid(2143eaad-674e-4613-87f8-359d4c40f590)]
|
||||
[scriptable, uuid(07c3d2cc-5454-4618-9f4f-cd93de9504a4)]
|
||||
interface nsIIncrementalStreamLoaderObserver : nsISupports
|
||||
{
|
||||
/**
|
||||
* Called when new data has arrived on the stream.
|
||||
*
|
||||
* @param loader the stream loader that loaded the stream.
|
||||
* @param ctxt the context parameter of the underlying channel
|
||||
* @param dataLength the length of the new data received
|
||||
* @param data the contents of the new data received.
|
||||
*
|
||||
* This method will always be called asynchronously by the
|
||||
* nsIIncrementalStreamLoader involved, on the thread that called the
|
||||
* loader's init() method.
|
||||
*
|
||||
* If the observer wants to not accumulate all or portional of the data in
|
||||
* the internal buffer, the consumedLength shall be set to the value of
|
||||
* the dataLength or less. By default the consumedLength value is assumed 0.
|
||||
* The data and dataLength reflect the non-consumed data and will be
|
||||
* accumulated if consumedLength is not set.
|
||||
*
|
||||
* In comparison with onStreamComplete(), the data buffer cannot be
|
||||
* adopted if this method returns NS_SUCCESS_ADOPTED_DATA.
|
||||
*/
|
||||
void onIncrementalData(in nsIIncrementalStreamLoader loader,
|
||||
in nsISupports ctxt,
|
||||
in unsigned long dataLength,
|
||||
[const,array,size_is(dataLength)] in octet data,
|
||||
inout unsigned long consumedLength);
|
||||
|
||||
/**
|
||||
* Called when the entire stream has been loaded.
|
||||
*
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include <limits>
|
||||
|
||||
nsIncrementalStreamLoader::nsIncrementalStreamLoader()
|
||||
: mData()
|
||||
: mData(), mBytesConsumed(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -49,7 +49,7 @@ NS_IMPL_ISUPPORTS(nsIncrementalStreamLoader, nsIIncrementalStreamLoader,
|
|||
NS_IMETHODIMP
|
||||
nsIncrementalStreamLoader::GetNumBytesRead(uint32_t* aNumBytes)
|
||||
{
|
||||
*aNumBytes = mData.length();
|
||||
*aNumBytes = mBytesConsumed + mData.length();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -121,11 +121,66 @@ nsIncrementalStreamLoader::WriteSegmentFun(nsIInputStream *inStr,
|
|||
{
|
||||
nsIncrementalStreamLoader *self = (nsIncrementalStreamLoader *) closure;
|
||||
|
||||
const uint8_t *data = reinterpret_cast<const uint8_t *>(fromSegment);
|
||||
uint32_t consumedCount = 0;
|
||||
nsresult rv;
|
||||
if (self->mData.empty()) {
|
||||
// Shortcut when observer wants to keep the listener's buffer empty.
|
||||
rv = self->mObserver->OnIncrementalData(self, self->mContext,
|
||||
count, data, &consumedCount);
|
||||
|
||||
if (rv != NS_OK) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (consumedCount > count) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (consumedCount < count) {
|
||||
if (!self->mData.append(fromSegment + consumedCount,
|
||||
count - consumedCount)) {
|
||||
self->mData.clearAndFree();
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// We have some non-consumed data from previous OnIncrementalData call,
|
||||
// appending new data and reporting combined data.
|
||||
if (!self->mData.append(fromSegment, count)) {
|
||||
self->mData.clearAndFree();
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
size_t length = self->mData.length();
|
||||
uint32_t reportCount = length > UINT32_MAX ? UINT32_MAX : (uint32_t)length;
|
||||
uint8_t* elems = self->mData.extractRawBuffer();
|
||||
|
||||
rv = self->mObserver->OnIncrementalData(self, self->mContext,
|
||||
reportCount, elems, &consumedCount);
|
||||
|
||||
// We still own elems, freeing its memory when exiting scope.
|
||||
if (rv != NS_OK) {
|
||||
free(elems);
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (consumedCount > reportCount) {
|
||||
free(elems);
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (consumedCount == length) {
|
||||
free(elems); // good case -- fully consumed data
|
||||
} else {
|
||||
// Adopting elems back (at least its portion).
|
||||
self->mData.replaceRawBuffer(elems, length);
|
||||
if (consumedCount > 0) {
|
||||
self->mData.erase(self->mData.begin() + consumedCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self->mBytesConsumed += consumedCount;
|
||||
*writeCount = count;
|
||||
|
||||
return NS_OK;
|
||||
|
@ -136,8 +191,14 @@ nsIncrementalStreamLoader::OnDataAvailable(nsIRequest* request, nsISupports *ctx
|
|||
nsIInputStream *inStr,
|
||||
uint64_t sourceOffset, uint32_t count)
|
||||
{
|
||||
if (mObserver) {
|
||||
// provide nsIIncrementalStreamLoader::request during call to OnStreamComplete
|
||||
mRequest = request;
|
||||
}
|
||||
uint32_t countRead;
|
||||
return inStr->ReadSegments(WriteSegmentFun, this, count, &countRead);
|
||||
nsresult rv = inStr->ReadSegments(WriteSegmentFun, this, count, &countRead);
|
||||
mRequest = 0;
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -46,6 +46,9 @@ protected:
|
|||
// Buffer to accumulate incoming data. We preallocate if contentSize is
|
||||
// available.
|
||||
mozilla::Vector<uint8_t, 0> mData;
|
||||
|
||||
// Number of consumed bytes from the mData.
|
||||
size_t mBytesConsumed;
|
||||
};
|
||||
|
||||
#endif // nsIncrementalStreamLoader_h__
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
var tests = [
|
||||
{data: '', chunks: [], status: Cr.NS_OK, consume: [],
|
||||
dataChunks: ['']},
|
||||
{data: 'TWO-PARTS', chunks: [4, 5], status: Cr.NS_OK, consume: [4, 5],
|
||||
dataChunks: ['TWO-', 'PARTS', '']},
|
||||
{data: 'TWO-PARTS', chunks: [4, 5], status: Cr.NS_OK, consume: [0, 0],
|
||||
dataChunks: ['TWO-', 'TWO-PARTS', 'TWO-PARTS']},
|
||||
{data: '3-PARTS', chunks: [1, 1, 5], status: Cr.NS_OK, consume: [0, 2, 5],
|
||||
dataChunks: ['3', '3-', 'PARTS', '']},
|
||||
{data: 'ALL-AT-ONCE', chunks: [11], status: Cr.NS_OK, consume: [0],
|
||||
dataChunks: ['ALL-AT-ONCE', 'ALL-AT-ONCE']},
|
||||
{data: 'ALL-AT-ONCE', chunks: [11], status: Cr.NS_OK, consume: [11],
|
||||
dataChunks: ['ALL-AT-ONCE', '']},
|
||||
{data: 'ERROR', chunks: [1], status: Cr.NS_ERROR_OUT_OF_MEMORY, consume: [0],
|
||||
dataChunks: ['E', 'E']}
|
||||
];
|
||||
|
||||
/**
|
||||
* @typedef TestData
|
||||
* @property {string} data - data for the test.
|
||||
* @property {Array} chunks - lengths of the chunks that are incrementally sent
|
||||
* to the loader.
|
||||
* @property {number} status - final status sent on onStopRequest.
|
||||
* @property {Array} consume - lengths of consumed data that is reported at
|
||||
* the onIncrementalData callback.
|
||||
* @property {Array} dataChunks - data chunks that are reported at the
|
||||
* onIncrementalData and onStreamComplete callbacks.
|
||||
*/
|
||||
|
||||
function execute_test(test) {
|
||||
let stream = Cc["@mozilla.org/io/string-input-stream;1"].
|
||||
createInstance(Ci.nsIStringInputStream);
|
||||
stream.data = test.data;
|
||||
|
||||
let channel = {
|
||||
contentLength: -1,
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIChannel])
|
||||
};
|
||||
|
||||
let chunkIndex = 0;
|
||||
|
||||
let observer = {
|
||||
onStreamComplete: function(loader, context, status, length, data) {
|
||||
equal(chunkIndex, test.dataChunks.length - 1);
|
||||
var expectedChunk = test.dataChunks[chunkIndex];
|
||||
equal(length, expectedChunk.length);
|
||||
equal(String.fromCharCode.apply(null, data), expectedChunk);
|
||||
|
||||
equal(status, test.status);
|
||||
},
|
||||
onIncrementalData: function (loader, context, length, data, consumed) {
|
||||
ok(chunkIndex < test.dataChunks.length - 1);
|
||||
var expectedChunk = test.dataChunks[chunkIndex];
|
||||
equal(length, expectedChunk.length);
|
||||
equal(String.fromCharCode.apply(null, data), expectedChunk);
|
||||
|
||||
consumed.value = test.consume[chunkIndex];
|
||||
chunkIndex++;
|
||||
},
|
||||
QueryInterface:
|
||||
XPCOMUtils.generateQI([Ci.nsIIncrementalStreamLoaderObserver])
|
||||
};
|
||||
|
||||
let listener = Cc["@mozilla.org/network/incremental-stream-loader;1"]
|
||||
.createInstance(Ci.nsIIncrementalStreamLoader);
|
||||
listener.init(observer);
|
||||
|
||||
listener.onStartRequest(channel, null);
|
||||
var offset = 0;
|
||||
test.chunks.forEach(function (chunkLength) {
|
||||
listener.onDataAvailable(channel, null, stream, offset, chunkLength);
|
||||
offset += chunkLength;
|
||||
});
|
||||
listener.onStopRequest(channel, null, test.status);
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
tests.forEach(execute_test);
|
||||
}
|
|
@ -169,6 +169,7 @@ skip-if = os == "android"
|
|||
skip-if = bits != 32
|
||||
[test_bug935499.js]
|
||||
[test_bug1064258.js]
|
||||
[test_bug1218029.js]
|
||||
[test_udpsocket.js]
|
||||
[test_doomentry.js]
|
||||
[test_cacheflags.js]
|
||||
|
|
Загрузка…
Ссылка в новой задаче