summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--netwerk/streamconv/converters/nsHTTPCompressConv.cpp735
-rw-r--r--netwerk/streamconv/converters/nsHTTPCompressConv.h136
2 files changed, 466 insertions, 405 deletions
diff --git a/netwerk/streamconv/converters/nsHTTPCompressConv.cpp b/netwerk/streamconv/converters/nsHTTPCompressConv.cpp
index 37b4b28b0..c35b0dcac 100644
--- a/netwerk/streamconv/converters/nsHTTPCompressConv.cpp
+++ b/netwerk/streamconv/converters/nsHTTPCompressConv.cpp
@@ -20,7 +20,7 @@
// brotli headers
#include "state.h"
-#include "decode.h"
+#include "brotli/decode.h"
namespace mozilla {
namespace net {
@@ -33,7 +33,8 @@ NS_IMPL_ISUPPORTS(nsHTTPCompressConv,
nsIStreamConverter,
nsIStreamListener,
nsIRequestObserver,
- nsICompressConvStats)
+ nsICompressConvStats,
+ nsIThreadRetargetableStreamListener)
// nsFTPDirListingConv methods
nsHTTPCompressConv::nsHTTPCompressConv()
@@ -45,11 +46,14 @@ nsHTTPCompressConv::nsHTTPCompressConv()
, mCheckHeaderDone(false)
, mStreamEnded(false)
, mStreamInitialized(false)
+ , mDummyStreamInitialised(false)
+ , d_stream{}
, mLen(0)
, hMode(0)
, mSkipCount(0)
, mFlags(0)
, mDecodedDataLength(0)
+ , mMutex("nsHTTPCompressConv")
{
LOG(("nsHttpCompresssConv %p ctor\n", this));
if (NS_IsMainThread()) {
@@ -60,8 +64,7 @@ nsHTTPCompressConv::nsHTTPCompressConv()
}
}
-nsHTTPCompressConv::~nsHTTPCompressConv()
-{
+nsHTTPCompressConv::~nsHTTPCompressConv() {
LOG(("nsHttpCompresssConv %p dtor\n", this));
if (mInpBuffer) {
free(mInpBuffer);
@@ -74,63 +77,64 @@ nsHTTPCompressConv::~nsHTTPCompressConv()
// For some reason we are not getting Z_STREAM_END. But this was also seen
// for mozilla bug 198133. Need to handle this case.
if (mStreamInitialized && !mStreamEnded) {
- inflateEnd (&d_stream);
+ inflateEnd(&d_stream);
}
}
NS_IMETHODIMP
-nsHTTPCompressConv::GetDecodedDataLength(uint64_t *aDecodedDataLength)
-{
- *aDecodedDataLength = mDecodedDataLength;
- return NS_OK;
+nsHTTPCompressConv::GetDecodedDataLength(uint64_t* aDecodedDataLength) {
+ *aDecodedDataLength = mDecodedDataLength;
+ return NS_OK;
}
NS_IMETHODIMP
-nsHTTPCompressConv::AsyncConvertData(const char *aFromType,
- const char *aToType,
- nsIStreamListener *aListener,
- nsISupports *aCtxt)
-{
- if (!PL_strncasecmp(aFromType, HTTP_COMPRESS_TYPE, sizeof(HTTP_COMPRESS_TYPE)-1) ||
- !PL_strncasecmp(aFromType, HTTP_X_COMPRESS_TYPE, sizeof(HTTP_X_COMPRESS_TYPE)-1)) {
+nsHTTPCompressConv::AsyncConvertData(const char* aFromType, const char* aToType,
+ nsIStreamListener* aListener,
+ nsISupports* aCtxt) {
+ if (!PL_strncasecmp(aFromType, HTTP_COMPRESS_TYPE, sizeof(HTTP_COMPRESS_TYPE) - 1) ||
+ !PL_strncasecmp(aFromType, HTTP_X_COMPRESS_TYPE, sizeof(HTTP_X_COMPRESS_TYPE) - 1)) {
mMode = HTTP_COMPRESS_COMPRESS;
- } else if (!PL_strncasecmp(aFromType, HTTP_GZIP_TYPE, sizeof(HTTP_GZIP_TYPE)-1) ||
- !PL_strncasecmp(aFromType, HTTP_X_GZIP_TYPE, sizeof(HTTP_X_GZIP_TYPE)-1)) {
+ } else if (!PL_strncasecmp(aFromType, HTTP_GZIP_TYPE, sizeof(HTTP_GZIP_TYPE) - 1) ||
+ !PL_strncasecmp(aFromType, HTTP_X_GZIP_TYPE, sizeof(HTTP_X_GZIP_TYPE) - 1)) {
mMode = HTTP_COMPRESS_GZIP;
- } else if (!PL_strncasecmp(aFromType, HTTP_DEFLATE_TYPE, sizeof(HTTP_DEFLATE_TYPE)-1)) {
+ } else if (!PL_strncasecmp(aFromType, HTTP_DEFLATE_TYPE, sizeof(HTTP_DEFLATE_TYPE) - 1)) {
mMode = HTTP_COMPRESS_DEFLATE;
- } else if (!PL_strncasecmp(aFromType, HTTP_BROTLI_TYPE, sizeof(HTTP_BROTLI_TYPE)-1)) {
+ } else if (!PL_strncasecmp(aFromType, HTTP_BROTLI_TYPE, sizeof(HTTP_BROTLI_TYPE) - 1)) {
mMode = HTTP_COMPRESS_BROTLI;
}
- LOG(("nsHttpCompresssConv %p AsyncConvertData %s %s mode %d\n",
- this, aFromType, aToType, mMode));
+ LOG(("nsHttpCompresssConv %p AsyncConvertData %s %s mode %d\n", this,
+ aFromType, aToType, (CompressMode)mMode));
+ MutexAutoLock lock(mMutex);
// hook ourself up with the receiving listener.
mListener = aListener;
- mAsyncConvContext = aCtxt;
return NS_OK;
}
NS_IMETHODIMP
-nsHTTPCompressConv::OnStartRequest(nsIRequest* request, nsISupports *aContext)
-{
+nsHTTPCompressConv::OnStartRequest(nsIRequest* request, nsISupports* aContext) {
LOG(("nsHttpCompresssConv %p onstart\n", this));
- return mListener->OnStartRequest(request, aContext);
+ nsCOMPtr<nsIStreamListener> listener;
+ {
+ MutexAutoLock lock(mMutex);
+ listener = mListener;
+ }
+ return listener->OnStartRequest(request, aContext);
}
NS_IMETHODIMP
-nsHTTPCompressConv::OnStopRequest(nsIRequest* request, nsISupports *aContext,
- nsresult aStatus)
-{
+nsHTTPCompressConv::OnStopRequest(nsIRequest* request, nsISupports* aContext,
+ nsresult aStatus) {
nsresult status = aStatus;
- LOG(("nsHttpCompresssConv %p onstop %x\n", this, aStatus));
-
+ LOG(("nsHttpCompresssConv %p onstop %" PRIx32 "\n", this,
+ static_cast<uint32_t>(aStatus)));
+
// Framing integrity is enforced for content-encoding: gzip, but not for
// content-encoding: deflate. Note that gzip vs deflate is NOT determined
// by content sniffing but only via header.
if (!mStreamEnded && NS_SUCCEEDED(status) &&
- (mFailUncleanStops && (mMode == HTTP_COMPRESS_GZIP)) ) {
+ (mFailUncleanStops && (mMode == HTTP_COMPRESS_GZIP))) {
// This is not a clean end of gzip stream: the transfer is incomplete.
status = NS_ERROR_NET_PARTIAL_TRANSFER;
LOG(("nsHttpCompresssConv %p onstop partial gzip\n", this));
@@ -144,31 +148,40 @@ nsHTTPCompressConv::OnStopRequest(nsIRequest* request, nsISupports *aContext,
if (fpChannel && !isPending) {
fpChannel->ForcePending(true);
}
- if (mBrotli && (mBrotli->mTotalOut == 0) && !BrotliStateIsStreamEnd(&mBrotli->mState)) {
+ if (mBrotli && (mBrotli->mTotalOut == 0) && !mBrotli->mBrotliStateIsStreamEnd) {
status = NS_ERROR_INVALID_CONTENT_ENCODING;
}
- LOG(("nsHttpCompresssConv %p onstop brotlihandler rv %x\n", this, status));
+ LOG(("nsHttpCompresssConv %p onstop brotlihandler rv %" PRIx32 "\n", this,
+ static_cast<uint32_t>(status)));
if (fpChannel && !isPending) {
fpChannel->ForcePending(false);
}
}
- return mListener->OnStopRequest(request, aContext, status);
-}
+ nsCOMPtr<nsIStreamListener> listener;
+ {
+ MutexAutoLock lock(mMutex);
+ listener = mListener;
+ }
+ return listener->OnStopRequest(request, aContext, status);
+}
-/* static */ nsresult
-nsHTTPCompressConv::BrotliHandler(nsIInputStream *stream, void *closure, const char *dataIn,
- uint32_t, uint32_t aAvail, uint32_t *countRead)
-{
+/* static */
+nsresult nsHTTPCompressConv::BrotliHandler(nsIInputStream* stream,
+ void* closure,
+ const char* dataIn,
+ uint32_t,
+ uint32_t aAvail,
+ uint32_t* countRead) {
MOZ_ASSERT(stream);
- nsHTTPCompressConv *self = static_cast<nsHTTPCompressConv *>(closure);
+ nsHTTPCompressConv* self = static_cast<nsHTTPCompressConv*>(closure);
*countRead = 0;
- const size_t kOutSize = 128 * 1024; // just a chunk size, we call in a loop
- uint8_t *outPtr;
+ const size_t kOutSize = 128 * 1024; // just a chunk size, we call in a loop
+ uint8_t* outPtr;
size_t outSize;
size_t avail = aAvail;
- BrotliResult res;
+ BrotliDecoderResult res;
if (!self->mBrotli) {
*countRead = aAvail;
@@ -186,15 +199,21 @@ nsHTTPCompressConv::BrotliHandler(nsIInputStream *stream, void *closure, const c
outPtr = outBuffer.get();
// brotli api is documented in brotli/dec/decode.h and brotli/dec/decode.c
- LOG(("nsHttpCompresssConv %p brotlihandler decompress %d\n", self, avail));
- res = ::BrotliDecompressStream(
- &avail, reinterpret_cast<const unsigned char **>(&dataIn),
- &outSize, &outPtr, &self->mBrotli->mTotalOut, &self->mBrotli->mState);
+ LOG(("nsHttpCompresssConv %p brotlihandler decompress %zu\n", self, avail));
+ size_t totalOut = self->mBrotli->mTotalOut;
+ res = ::BrotliDecoderDecompressStream(
+ &self->mBrotli->mState, &avail,
+ reinterpret_cast<const unsigned char**>(&dataIn), &outSize, &outPtr,
+ &totalOut);
outSize = kOutSize - outSize;
- LOG(("nsHttpCompresssConv %p brotlihandler decompress rv=%x out=%d\n",
- self, res, outSize));
-
- if (res == BROTLI_RESULT_ERROR) {
+ self->mBrotli->mTotalOut = totalOut;
+ self->mBrotli->mBrotliStateIsStreamEnd =
+ BrotliDecoderIsFinished(&self->mBrotli->mState);
+ LOG(("nsHttpCompresssConv %p brotlihandler decompress rv=%" PRIx32
+ " out=%zu\n",
+ self, static_cast<uint32_t>(res), outSize));
+
+ if (res == BROTLI_DECODER_RESULT_ERROR) {
LOG(("nsHttpCompressConv %p marking invalid encoding", self));
self->mBrotli->mStatus = NS_ERROR_INVALID_CONTENT_ENCODING;
return self->mBrotli->mStatus;
@@ -202,7 +221,7 @@ nsHTTPCompressConv::BrotliHandler(nsIInputStream *stream, void *closure, const c
// in 'the current implementation' brotli must consume everything before
// asking for more input
- if (res == BROTLI_RESULT_NEEDS_MORE_INPUT) {
+ if (res == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT) {
MOZ_ASSERT(!avail);
if (avail) {
LOG(("nsHttpCompressConv %p did not consume all input", self));
@@ -214,22 +233,23 @@ nsHTTPCompressConv::BrotliHandler(nsIInputStream *stream, void *closure, const c
nsresult rv = self->do_OnDataAvailable(self->mBrotli->mRequest,
self->mBrotli->mContext,
self->mBrotli->mSourceOffset,
- reinterpret_cast<const char *>(outBuffer.get()),
+ reinterpret_cast<const char*>(outBuffer.get()),
outSize);
- LOG(("nsHttpCompressConv %p BrotliHandler ODA rv=%x", self, rv));
+ LOG(("nsHttpCompressConv %p BrotliHandler ODA rv=%" PRIx32, self,
+ static_cast<uint32_t>(rv)));
if (NS_FAILED(rv)) {
self->mBrotli->mStatus = rv;
return self->mBrotli->mStatus;
}
}
- if (res == BROTLI_RESULT_SUCCESS ||
- res == BROTLI_RESULT_NEEDS_MORE_INPUT) {
+ if (res == BROTLI_DECODER_RESULT_SUCCESS ||
+ res == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT) {
*countRead = aAvail;
return NS_OK;
}
- MOZ_ASSERT (res == BROTLI_RESULT_NEEDS_MORE_OUTPUT);
- } while (res == BROTLI_RESULT_NEEDS_MORE_OUTPUT);
+ MOZ_ASSERT(res == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT);
+ } while (res == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT);
self->mBrotli->mStatus = NS_ERROR_UNEXPECTED;
return self->mBrotli->mStatus;
@@ -237,11 +257,10 @@ nsHTTPCompressConv::BrotliHandler(nsIInputStream *stream, void *closure, const c
NS_IMETHODIMP
nsHTTPCompressConv::OnDataAvailable(nsIRequest* request,
- nsISupports *aContext,
- nsIInputStream *iStr,
+ nsISupports* aContext,
+ nsIInputStream* iStr,
uint64_t aSourceOffset,
- uint32_t aCount)
-{
+ uint32_t aCount) {
nsresult rv = NS_ERROR_INVALID_CONTENT_ENCODING;
uint32_t streamLen = aCount;
LOG(("nsHttpCompressConv %p OnDataAvailable %d", this, aCount));
@@ -260,206 +279,216 @@ nsHTTPCompressConv::OnDataAvailable(nsIRequest* request,
}
switch (mMode) {
- case HTTP_COMPRESS_GZIP:
- streamLen = check_header(iStr, streamLen, &rv);
+ case HTTP_COMPRESS_GZIP:
+ streamLen = check_header(iStr, streamLen, &rv);
- if (rv != NS_OK) {
- return rv;
- }
+ if (rv != NS_OK) {
+ return rv;
+ }
- if (streamLen == 0) {
- return NS_OK;
- }
+ if (streamLen == 0) {
+ return NS_OK;
+ }
- MOZ_FALLTHROUGH;
+ MOZ_FALLTHROUGH;
- case HTTP_COMPRESS_DEFLATE:
+ case HTTP_COMPRESS_DEFLATE:
- if (mInpBuffer != nullptr && streamLen > mInpBufferLen) {
- mInpBuffer = (unsigned char *) realloc(mInpBuffer, mInpBufferLen = streamLen);
+ if (mInpBuffer != nullptr && streamLen > mInpBufferLen) {
+ unsigned char* originalInpBuffer = mInpBuffer;
+ if (!(mInpBuffer = (unsigned char*)realloc(originalInpBuffer, mInpBufferLen = streamLen))) {
+ free(originalInpBuffer);
+ }
+
+ if (mOutBufferLen < streamLen * 2) {
+ unsigned char* originalOutBuffer = mOutBuffer;
+ if (!(mOutBuffer = (unsigned char*)realloc(mOutBuffer, mOutBufferLen = streamLen * 3))) {
+ free(originalOutBuffer);
+ }
+ }
- if (mOutBufferLen < streamLen * 2) {
- mOutBuffer = (unsigned char *) realloc(mOutBuffer, mOutBufferLen = streamLen * 3);
+ if (mInpBuffer == nullptr || mOutBuffer == nullptr) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
}
- if (mInpBuffer == nullptr || mOutBuffer == nullptr) {
- return NS_ERROR_OUT_OF_MEMORY;
+ if (mInpBuffer == nullptr) {
+ mInpBuffer = (unsigned char*)malloc(mInpBufferLen = streamLen);
}
- }
- if (mInpBuffer == nullptr) {
- mInpBuffer = (unsigned char *) malloc(mInpBufferLen = streamLen);
- }
+ if (mOutBuffer == nullptr) {
+ mOutBuffer = (unsigned char*)malloc(mOutBufferLen = streamLen * 3);
+ }
- if (mOutBuffer == nullptr) {
- mOutBuffer = (unsigned char *) malloc(mOutBufferLen = streamLen * 3);
- }
+ if (mInpBuffer == nullptr || mOutBuffer == nullptr) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
- if (mInpBuffer == nullptr || mOutBuffer == nullptr) {
- return NS_ERROR_OUT_OF_MEMORY;
- }
+ uint32_t unused;
+ iStr->Read((char*)mInpBuffer, streamLen, &unused);
- uint32_t unused;
- iStr->Read((char *)mInpBuffer, streamLen, &unused);
+ if (mMode == HTTP_COMPRESS_DEFLATE) {
+ if (!mStreamInitialized) {
+ memset(&d_stream, 0, sizeof(d_stream));
- if (mMode == HTTP_COMPRESS_DEFLATE) {
- if (!mStreamInitialized) {
- memset(&d_stream, 0, sizeof (d_stream));
+ if (inflateInit(&d_stream) != Z_OK) {
+ return NS_ERROR_FAILURE;
+ }
- if (inflateInit(&d_stream) != Z_OK) {
- return NS_ERROR_FAILURE;
+ mStreamInitialized = true;
}
-
- mStreamInitialized = true;
- }
- d_stream.next_in = mInpBuffer;
- d_stream.avail_in = (uInt)streamLen;
-
- mDummyStreamInitialised = false;
- for (;;) {
- d_stream.next_out = mOutBuffer;
- d_stream.avail_out = (uInt)mOutBufferLen;
-
- int code = inflate(&d_stream, Z_NO_FLUSH);
- unsigned bytesWritten = (uInt)mOutBufferLen - d_stream.avail_out;
-
- if (code == Z_STREAM_END) {
- if (bytesWritten) {
- rv = do_OnDataAvailable(request, aContext, aSourceOffset, (char *)mOutBuffer, bytesWritten);
- if (NS_FAILED (rv)) {
- return rv;
+ d_stream.next_in = mInpBuffer;
+ d_stream.avail_in = (uInt)streamLen;
+
+ mDummyStreamInitialised = false;
+ for (;;) {
+ d_stream.next_out = mOutBuffer;
+ d_stream.avail_out = (uInt)mOutBufferLen;
+
+ int code = inflate(&d_stream, Z_NO_FLUSH);
+ unsigned bytesWritten = (uInt)mOutBufferLen - d_stream.avail_out;
+
+ if (code == Z_STREAM_END) {
+ if (bytesWritten) {
+ rv = do_OnDataAvailable(request, aContext, aSourceOffset, (char*)mOutBuffer, bytesWritten);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
}
- }
- inflateEnd(&d_stream);
- mStreamEnded = true;
- break;
- } else if (code == Z_OK) {
- if (bytesWritten) {
- rv = do_OnDataAvailable(request, aContext, aSourceOffset, (char *)mOutBuffer, bytesWritten);
- if (NS_FAILED (rv)) {
- return rv;
+ inflateEnd(&d_stream);
+ mStreamEnded = true;
+ break;
+ } else if (code == Z_OK) {
+ if (bytesWritten) {
+ rv = do_OnDataAvailable(request, aContext, aSourceOffset, (char*)mOutBuffer, bytesWritten);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
}
- }
- } else if (code == Z_BUF_ERROR) {
- if (bytesWritten) {
- rv = do_OnDataAvailable(request, aContext, aSourceOffset, (char *)mOutBuffer, bytesWritten);
- if (NS_FAILED (rv)) {
- return rv;
+ } else if (code == Z_BUF_ERROR) {
+ if (bytesWritten) {
+ rv = do_OnDataAvailable(request, aContext, aSourceOffset, (char*)mOutBuffer, bytesWritten);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
}
- }
- break;
- } else if (code == Z_DATA_ERROR) {
- // some servers (notably Apache with mod_deflate) don't generate zlib headers
- // insert a dummy header and try again
- static char dummy_head[2] =
- {
- 0x8 + 0x7 * 0x10,
- (((0x8 + 0x7 * 0x10) * 0x100 + 30) / 31 * 31) & 0xFF,
+ break;
+ } else if (code == Z_DATA_ERROR) {
+ // some servers (notably Apache with mod_deflate) don't generate
+ // zlib headers insert a dummy header and try again
+ static char dummy_head[2] = {
+ 0x8 + 0x7 * 0x10,
+ (((0x8 + 0x7 * 0x10) * 0x100 + 30) / 31 * 31) & 0xFF,
};
- inflateReset(&d_stream);
- d_stream.next_in = (Bytef*) dummy_head;
- d_stream.avail_in = sizeof(dummy_head);
+ inflateReset(&d_stream);
+ d_stream.next_in = (Bytef*)dummy_head;
+ d_stream.avail_in = sizeof(dummy_head);
- code = inflate(&d_stream, Z_NO_FLUSH);
- if (code != Z_OK) {
- return NS_ERROR_FAILURE;
- }
+ code = inflate(&d_stream, Z_NO_FLUSH);
+ if (code != Z_OK) {
+ return NS_ERROR_FAILURE;
+ }
- // stop an endless loop caused by non-deflate data being labelled as deflate
- if (mDummyStreamInitialised) {
- NS_WARNING("endless loop detected"
- " - invalid deflate");
+ // stop an endless loop caused by non-deflate data being labelled as
+ // deflate
+ if (mDummyStreamInitialised) {
+ NS_WARNING(
+ "endless loop detected"
+ " - invalid deflate");
+ return NS_ERROR_INVALID_CONTENT_ENCODING;
+ }
+ mDummyStreamInitialised = true;
+ // reset stream pointers to our original data
+ d_stream.next_in = mInpBuffer;
+ d_stream.avail_in = (uInt)streamLen;
+ } else {
return NS_ERROR_INVALID_CONTENT_ENCODING;
}
- mDummyStreamInitialised = true;
- // reset stream pointers to our original data
- d_stream.next_in = mInpBuffer;
- d_stream.avail_in = (uInt)streamLen;
- } else {
- return NS_ERROR_INVALID_CONTENT_ENCODING;
- }
- } /* for */
- } else {
- if (!mStreamInitialized) {
- memset(&d_stream, 0, sizeof (d_stream));
+ } /* for */
+ } else {
+ if (!mStreamInitialized) {
+ memset(&d_stream, 0, sizeof(d_stream));
- if (inflateInit2(&d_stream, -MAX_WBITS) != Z_OK) {
- return NS_ERROR_FAILURE;
- }
+ if (inflateInit2(&d_stream, -MAX_WBITS) != Z_OK) {
+ return NS_ERROR_FAILURE;
+ }
- mStreamInitialized = true;
- }
+ mStreamInitialized = true;
+ }
- d_stream.next_in = mInpBuffer;
- d_stream.avail_in = (uInt)streamLen;
+ d_stream.next_in = mInpBuffer;
+ d_stream.avail_in = (uInt)streamLen;
- for (;;) {
- d_stream.next_out = mOutBuffer;
- d_stream.avail_out = (uInt)mOutBufferLen;
+ for (;;) {
+ d_stream.next_out = mOutBuffer;
+ d_stream.avail_out = (uInt)mOutBufferLen;
- int code = inflate (&d_stream, Z_NO_FLUSH);
- unsigned bytesWritten = (uInt)mOutBufferLen - d_stream.avail_out;
+ int code = inflate(&d_stream, Z_NO_FLUSH);
+ unsigned bytesWritten = (uInt)mOutBufferLen - d_stream.avail_out;
- if (code == Z_STREAM_END) {
- if (bytesWritten) {
- rv = do_OnDataAvailable(request, aContext, aSourceOffset, (char *)mOutBuffer, bytesWritten);
- if (NS_FAILED (rv)) {
- return rv;
+ if (code == Z_STREAM_END) {
+ if (bytesWritten) {
+ rv = do_OnDataAvailable(request, aContext, aSourceOffset, (char*)mOutBuffer, bytesWritten);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
}
- }
- inflateEnd(&d_stream);
- mStreamEnded = true;
- break;
- } else if (code == Z_OK) {
- if (bytesWritten) {
- rv = do_OnDataAvailable(request, aContext, aSourceOffset, (char *)mOutBuffer, bytesWritten);
- if (NS_FAILED (rv)) {
- return rv;
+ inflateEnd(&d_stream);
+ mStreamEnded = true;
+ break;
+ } else if (code == Z_OK) {
+ if (bytesWritten) {
+ rv = do_OnDataAvailable(request, aContext, aSourceOffset, (char*)mOutBuffer, bytesWritten);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
}
- }
- } else if (code == Z_BUF_ERROR) {
- if (bytesWritten) {
- rv = do_OnDataAvailable(request, aContext, aSourceOffset, (char *)mOutBuffer, bytesWritten);
- if (NS_FAILED (rv)) {
- return rv;
+ } else if (code == Z_BUF_ERROR) {
+ if (bytesWritten) {
+ rv = do_OnDataAvailable(request, aContext, aSourceOffset, (char*)mOutBuffer, bytesWritten);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
}
+ break;
+ } else {
+ return NS_ERROR_INVALID_CONTENT_ENCODING;
}
- break;
- } else {
- return NS_ERROR_INVALID_CONTENT_ENCODING;
- }
- } /* for */
- } /* gzip */
- break;
+ } /* for */
+ } /* gzip */
+ break;
- case HTTP_COMPRESS_BROTLI:
- {
- if (!mBrotli) {
- mBrotli = new BrotliWrapper();
- }
+ case HTTP_COMPRESS_BROTLI: {
+ if (!mBrotli) {
+ mBrotli = new BrotliWrapper();
+ }
- mBrotli->mRequest = request;
- mBrotli->mContext = aContext;
- mBrotli->mSourceOffset = aSourceOffset;
+ mBrotli->mRequest = request;
+ mBrotli->mContext = nullptr;
+ mBrotli->mSourceOffset = aSourceOffset;
- uint32_t countRead;
- rv = iStr->ReadSegments(BrotliHandler, this, streamLen, &countRead);
- if (NS_SUCCEEDED(rv)) {
- rv = mBrotli->mStatus;
- }
- if (NS_FAILED(rv)) {
- return rv;
- }
- }
- break;
+ uint32_t countRead;
+ rv = iStr->ReadSegments(BrotliHandler, this, streamLen, &countRead);
+ if (NS_SUCCEEDED(rv)) {
+ rv = mBrotli->mStatus;
+ }
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ } break;
- default:
- rv = mListener->OnDataAvailable(request, aContext, iStr, aSourceOffset, aCount);
- if (NS_FAILED (rv)) {
- return rv;
- }
+ default:
+ nsCOMPtr<nsIStreamListener> listener;
+ {
+ MutexAutoLock lock(mMutex);
+ listener = mListener;
+ }
+ rv = listener->OnDataAvailable(request, aContext, iStr, aSourceOffset, aCount);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
} /* switch */
return NS_OK;
@@ -468,20 +497,19 @@ nsHTTPCompressConv::OnDataAvailable(nsIRequest* request,
// XXX/ruslan: need to implement this too
NS_IMETHODIMP
-nsHTTPCompressConv::Convert(nsIInputStream *aFromStream,
- const char *aFromType,
- const char *aToType,
- nsISupports *aCtxt,
- nsIInputStream **_retval)
-{
+nsHTTPCompressConv::Convert(nsIInputStream* aFromStream,
+ const char* aFromType,
+ const char* aToType,
+ nsISupports* aCtxt,
+ nsIInputStream** _retval) {
return NS_ERROR_NOT_IMPLEMENTED;
}
-nsresult
-nsHTTPCompressConv::do_OnDataAvailable(nsIRequest* request,
- nsISupports *context, uint64_t offset,
- const char *buffer, uint32_t count)
-{
+nsresult nsHTTPCompressConv::do_OnDataAvailable(nsIRequest* request,
+ nsISupports* context,
+ uint64_t offset,
+ const char* buffer,
+ uint32_t count) {
if (!mStream) {
mStream = do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID);
NS_ENSURE_STATE(mStream);
@@ -489,8 +517,12 @@ nsHTTPCompressConv::do_OnDataAvailable(nsIRequest* request,
mStream->ShareData(buffer, count);
- nsresult rv = mListener->OnDataAvailable(request, context, mStream,
- offset, count);
+ nsCOMPtr<nsIStreamListener> listener;
+ {
+ MutexAutoLock lock(mMutex);
+ listener = mListener;
+ }
+ nsresult rv = listener->OnDataAvailable(request, context, mStream, offset, count);
// Make sure the stream no longer references |buffer| in case our listener
// is crazy enough to try to read from |mStream| after ODA.
@@ -500,19 +532,27 @@ nsHTTPCompressConv::do_OnDataAvailable(nsIRequest* request,
return rv;
}
-#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
-#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
-#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
-#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
-#define COMMENT 0x10 /* bit 4 set: file comment present */
-#define RESERVED 0xE0 /* bits 5..7: reserved */
+#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
+#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
+#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
+#define COMMENT 0x10 /* bit 4 set: file comment present */
+#define RESERVED 0xE0 /* bits 5..7: reserved */
static unsigned gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
-uint32_t
-nsHTTPCompressConv::check_header(nsIInputStream *iStr, uint32_t streamLen, nsresult *rs)
-{
- enum { GZIP_INIT = 0, GZIP_OS, GZIP_EXTRA0, GZIP_EXTRA1, GZIP_EXTRA2, GZIP_ORIG, GZIP_COMMENT, GZIP_CRC };
+uint32_t nsHTTPCompressConv::check_header(nsIInputStream* iStr,
+ uint32_t streamLen, nsresult* rs) {
+ enum {
+ GZIP_INIT = 0,
+ GZIP_OS,
+ GZIP_EXTRA0,
+ GZIP_EXTRA1,
+ GZIP_EXTRA2,
+ GZIP_ORIG,
+ GZIP_COMMENT,
+ GZIP_CRC
+ };
char c;
*rs = NS_OK;
@@ -523,134 +563,147 @@ nsHTTPCompressConv::check_header(nsIInputStream *iStr, uint32_t streamLen, nsres
while (streamLen) {
switch (hMode) {
- case GZIP_INIT:
- uint32_t unused;
- iStr->Read(&c, 1, &unused);
- streamLen--;
-
- if (mSkipCount == 0 && ((unsigned)c & 0377) != gz_magic[0]) {
- *rs = NS_ERROR_INVALID_CONTENT_ENCODING;
- return 0;
- }
-
- if (mSkipCount == 1 && ((unsigned)c & 0377) != gz_magic[1]) {
- *rs = NS_ERROR_INVALID_CONTENT_ENCODING;
- return 0;
- }
+ case GZIP_INIT:
+ uint32_t unused;
+ iStr->Read(&c, 1, &unused);
+ streamLen--;
- if (mSkipCount == 2 && ((unsigned)c & 0377) != Z_DEFLATED) {
- *rs = NS_ERROR_INVALID_CONTENT_ENCODING;
- return 0;
- }
+ if (mSkipCount == 0 && ((unsigned)c & 0377) != gz_magic[0]) {
+ *rs = NS_ERROR_INVALID_CONTENT_ENCODING;
+ return 0;
+ }
- mSkipCount++;
- if (mSkipCount == 4) {
- mFlags = (unsigned) c & 0377;
- if (mFlags & RESERVED) {
+ if (mSkipCount == 1 && ((unsigned)c & 0377) != gz_magic[1]) {
*rs = NS_ERROR_INVALID_CONTENT_ENCODING;
return 0;
}
- hMode = GZIP_OS;
- mSkipCount = 0;
- }
- break;
- case GZIP_OS:
- iStr->Read(&c, 1, &unused);
- streamLen--;
- mSkipCount++;
+ if (mSkipCount == 2 && ((unsigned)c & 0377) != Z_DEFLATED) {
+ *rs = NS_ERROR_INVALID_CONTENT_ENCODING;
+ return 0;
+ }
- if (mSkipCount == 6) {
- hMode = GZIP_EXTRA0;
- }
- break;
+ mSkipCount++;
+ if (mSkipCount == 4) {
+ mFlags = (unsigned)c & 0377;
+ if (mFlags & RESERVED) {
+ *rs = NS_ERROR_INVALID_CONTENT_ENCODING;
+ return 0;
+ }
+ hMode = GZIP_OS;
+ mSkipCount = 0;
+ }
+ break;
- case GZIP_EXTRA0:
- if (mFlags & EXTRA_FIELD) {
+ case GZIP_OS:
iStr->Read(&c, 1, &unused);
streamLen--;
- mLen = (uInt) c & 0377;
- hMode = GZIP_EXTRA1;
- } else {
- hMode = GZIP_ORIG;
- }
- break;
+ mSkipCount++;
- case GZIP_EXTRA1:
- iStr->Read(&c, 1, &unused);
- streamLen--;
- mLen |= ((uInt) c & 0377) << 8;
- mSkipCount = 0;
- hMode = GZIP_EXTRA2;
- break;
+ if (mSkipCount == 6) {
+ hMode = GZIP_EXTRA0;
+ }
+ break;
+
+ case GZIP_EXTRA0:
+ if (mFlags & EXTRA_FIELD) {
+ iStr->Read(&c, 1, &unused);
+ streamLen--;
+ mLen = (uInt)c & 0377;
+ hMode = GZIP_EXTRA1;
+ } else {
+ hMode = GZIP_ORIG;
+ }
+ break;
- case GZIP_EXTRA2:
- if (mSkipCount == mLen) {
- hMode = GZIP_ORIG;
- } else {
+ case GZIP_EXTRA1:
iStr->Read(&c, 1, &unused);
streamLen--;
- mSkipCount++;
- }
- break;
+ mLen |= ((uInt)c & 0377) << 8;
+ mSkipCount = 0;
+ hMode = GZIP_EXTRA2;
+ break;
- case GZIP_ORIG:
- if (mFlags & ORIG_NAME) {
- iStr->Read(&c, 1, &unused);
- streamLen--;
- if (c == 0)
- hMode = GZIP_COMMENT;
- } else {
- hMode = GZIP_COMMENT;
- }
- break;
+ case GZIP_EXTRA2:
+ if (mSkipCount == mLen) {
+ hMode = GZIP_ORIG;
+ } else {
+ iStr->Read(&c, 1, &unused);
+ streamLen--;
+ mSkipCount++;
+ }
+ break;
- case GZIP_COMMENT:
- if (mFlags & COMMENT) {
- iStr->Read(&c, 1, &unused);
- streamLen--;
- if (c == 0) {
+ case GZIP_ORIG:
+ if (mFlags & ORIG_NAME) {
+ iStr->Read(&c, 1, &unused);
+ streamLen--;
+ if (c == 0) hMode = GZIP_COMMENT;
+ } else {
+ hMode = GZIP_COMMENT;
+ }
+ break;
+
+ case GZIP_COMMENT:
+ if (mFlags & COMMENT) {
+ iStr->Read(&c, 1, &unused);
+ streamLen--;
+ if (c == 0) {
+ hMode = GZIP_CRC;
+ mSkipCount = 0;
+ }
+ } else {
hMode = GZIP_CRC;
mSkipCount = 0;
}
- } else {
- hMode = GZIP_CRC;
- mSkipCount = 0;
- }
- break;
-
- case GZIP_CRC:
- if (mFlags & HEAD_CRC) {
- iStr->Read(&c, 1, &unused);
- streamLen--;
- mSkipCount++;
- if (mSkipCount == 2) {
+ break;
+
+ case GZIP_CRC:
+ if (mFlags & HEAD_CRC) {
+ iStr->Read(&c, 1, &unused);
+ streamLen--;
+ mSkipCount++;
+ if (mSkipCount == 2) {
+ mCheckHeaderDone = true;
+ return streamLen;
+ }
+ } else {
mCheckHeaderDone = true;
return streamLen;
}
- } else {
- mCheckHeaderDone = true;
- return streamLen;
- }
- break;
+ break;
}
}
return streamLen;
}
-} // namespace net
-} // namespace mozilla
+NS_IMETHODIMP
+nsHTTPCompressConv::CheckListenerChain() {
+ nsCOMPtr<nsIThreadRetargetableStreamListener> listener;
+ {
+ MutexAutoLock lock(mMutex);
+ listener = do_QueryInterface(mListener);
+ }
-nsresult
-NS_NewHTTPCompressConv(mozilla::net::nsHTTPCompressConv **aHTTPCompressConv)
-{
- NS_PRECONDITION(aHTTPCompressConv != nullptr, "null ptr");
+ if (!listener) {
+ return NS_ERROR_NO_INTERFACE;
+ }
+
+ return listener->CheckListenerChain();
+}
+
+} // namespace net
+} // namespace mozilla
+
+nsresult NS_NewHTTPCompressConv(
+ mozilla::net::nsHTTPCompressConv** aHTTPCompressConv) {
+ MOZ_ASSERT(aHTTPCompressConv != nullptr, "null ptr");
if (!aHTTPCompressConv) {
return NS_ERROR_NULL_POINTER;
}
RefPtr<mozilla::net::nsHTTPCompressConv> outVal =
- new mozilla::net::nsHTTPCompressConv();
+ new mozilla::net::nsHTTPCompressConv();
if (!outVal) {
return NS_ERROR_OUT_OF_MEMORY;
}
diff --git a/netwerk/streamconv/converters/nsHTTPCompressConv.h b/netwerk/streamconv/converters/nsHTTPCompressConv.h
index 38889a8f7..6721a1e34 100644
--- a/netwerk/streamconv/converters/nsHTTPCompressConv.h
+++ b/netwerk/streamconv/converters/nsHTTPCompressConv.h
@@ -4,13 +4,16 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-#if !defined (__nsHTTPCompressConv__h__)
-#define __nsHTTPCompressConv__h__ 1
+#if !defined(__nsHTTPCompressConv__h__)
+#define __nsHTTPCompressConv__h__ 1
#include "nsIStreamConverter.h"
#include "nsICompressConvStats.h"
+#include "nsIThreadRetargetableStreamListener.h"
#include "nsCOMPtr.h"
#include "nsAutoPtr.h"
+#include "mozilla/Atomics.h"
+#include "mozilla/Mutex.h"
#include "zlib.h"
@@ -30,20 +33,19 @@ class nsIStringInputStream;
{0xab, 0xf4, 0x07, 0x98, 0x61, 0x51, 0x02, 0x2d} \
}
-
-#define HTTP_DEFLATE_TYPE "deflate"
-#define HTTP_GZIP_TYPE "gzip"
-#define HTTP_X_GZIP_TYPE "x-gzip"
-#define HTTP_COMPRESS_TYPE "compress"
-#define HTTP_X_COMPRESS_TYPE "x-compress"
-#define HTTP_BROTLI_TYPE "br"
-#define HTTP_IDENTITY_TYPE "identity"
-#define HTTP_UNCOMPRESSED_TYPE "uncompressed"
+#define HTTP_DEFLATE_TYPE "deflate"
+#define HTTP_GZIP_TYPE "gzip"
+#define HTTP_X_GZIP_TYPE "x-gzip"
+#define HTTP_COMPRESS_TYPE "compress"
+#define HTTP_X_COMPRESS_TYPE "x-compress"
+#define HTTP_BROTLI_TYPE "br"
+#define HTTP_IDENTITY_TYPE "identity"
+#define HTTP_UNCOMPRESSED_TYPE "uncompressed"
namespace mozilla {
namespace net {
-typedef enum {
+typedef enum {
HTTP_COMPRESS_GZIP,
HTTP_COMPRESS_DEFLATE,
HTTP_COMPRESS_COMPRESS,
@@ -51,82 +53,88 @@ typedef enum {
HTTP_COMPRESS_IDENTITY
} CompressMode;
-class BrotliWrapper
-{
+class BrotliWrapper {
public:
BrotliWrapper()
- : mTotalOut(0)
- , mStatus(NS_OK)
- {
- BrotliStateInit(&mState);
- }
- ~BrotliWrapper()
- {
- BrotliStateCleanup(&mState);
+ : mTotalOut(0),
+ mStatus(NS_OK),
+ mBrotliStateIsStreamEnd(false),
+ mRequest(nullptr),
+ mContext(nullptr),
+ mSourceOffset(0) {
+ BrotliDecoderStateInit(&mState, 0, 0, 0);
}
+ ~BrotliWrapper() { BrotliDecoderStateCleanup(&mState); }
- BrotliState mState;
- size_t mTotalOut;
- nsresult mStatus;
+ BrotliDecoderState mState;
+ Atomic<size_t, Relaxed> mTotalOut;
+ nsresult mStatus;
+ Atomic<bool, Relaxed> mBrotliStateIsStreamEnd;
- nsIRequest *mRequest;
- nsISupports *mContext;
- uint64_t mSourceOffset;
+ nsIRequest* mRequest;
+ nsISupports* mContext;
+ uint64_t mSourceOffset;
};
-class nsHTTPCompressConv
- : public nsIStreamConverter
- , public nsICompressConvStats
-{
- public:
+class nsHTTPCompressConv : public nsIStreamConverter,
+ public nsICompressConvStats,
+ public nsIThreadRetargetableStreamListener {
+public:
// nsISupports methods
- NS_DECL_THREADSAFE_ISUPPORTS
- NS_DECL_NSIREQUESTOBSERVER
- NS_DECL_NSISTREAMLISTENER
- NS_DECL_NSICOMPRESSCONVSTATS
+ NS_DECL_THREADSAFE_ISUPPORTS
+ NS_DECL_NSIREQUESTOBSERVER
+ NS_DECL_NSISTREAMLISTENER
+ NS_DECL_NSICOMPRESSCONVSTATS
+ NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
// nsIStreamConverter methods
- NS_DECL_NSISTREAMCONVERTER
+ NS_DECL_NSISTREAMCONVERTER
- nsHTTPCompressConv ();
+ nsHTTPCompressConv();
private:
- virtual ~nsHTTPCompressConv ();
+ virtual ~nsHTTPCompressConv();
+
+ nsCOMPtr<nsIStreamListener> mListener; // this guy gets the converted data via his OnDataAvailable ()
+ Atomic<CompressMode, Relaxed> mMode;
- nsCOMPtr<nsIStreamListener> mListener; // this guy gets the converted data via his OnDataAvailable ()
- CompressMode mMode;
+ unsigned char* mOutBuffer;
+ unsigned char* mInpBuffer;
- unsigned char *mOutBuffer;
- unsigned char *mInpBuffer;
+ uint32_t mOutBufferLen;
+ uint32_t mInpBufferLen;
- uint32_t mOutBufferLen;
- uint32_t mInpBufferLen;
+ nsAutoPtr<BrotliWrapper> mBrotli;
- nsAutoPtr<BrotliWrapper> mBrotli;
+ nsCOMPtr<nsIStringInputStream> mStream;
- nsCOMPtr<nsISupports> mAsyncConvContext;
- nsCOMPtr<nsIStringInputStream> mStream;
+ static nsresult BrotliHandler(nsIInputStream* stream,
+ void* closure,
+ const char* dataIn,
+ uint32_t,
+ uint32_t avail,
+ uint32_t* countRead);
- static nsresult
- BrotliHandler(nsIInputStream *stream, void *closure, const char *dataIn,
- uint32_t, uint32_t avail, uint32_t *countRead);
+ nsresult do_OnDataAvailable(nsIRequest* request,
+ nsISupports* aContext,
+ uint64_t aSourceOffset,
+ const char* buffer,
+ uint32_t aCount);
- nsresult do_OnDataAvailable (nsIRequest *request, nsISupports *aContext,
- uint64_t aSourceOffset, const char *buffer,
- uint32_t aCount);
+ bool mCheckHeaderDone;
+ Atomic<bool> mStreamEnded;
+ bool mStreamInitialized;
+ bool mDummyStreamInitialised;
+ bool mFailUncleanStops;
- bool mCheckHeaderDone;
- bool mStreamEnded;
- bool mStreamInitialized;
- bool mDummyStreamInitialised;
- bool mFailUncleanStops;
+ z_stream d_stream;
+ unsigned mLen, hMode, mSkipCount, mFlags;
- z_stream d_stream;
- unsigned mLen, hMode, mSkipCount, mFlags;
+ uint32_t check_header(nsIInputStream* iStr, uint32_t streamLen, nsresult* rv);
- uint32_t check_header (nsIInputStream *iStr, uint32_t streamLen, nsresult *rv);
+ Atomic<uint32_t, Relaxed> mDecodedDataLength;
- uint32_t mDecodedDataLength;
+ mutable mozilla::Mutex mMutex;
};
} // namespace net