зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1365519 - Make nsUnknownDecoder nsIThreadRetargetableStreamListener. r=mayhemer
This commit is contained in:
Родитель
062ca88ee0
Коммит
da6f218076
|
@ -74,8 +74,15 @@ nsUnknownDecoder::ConvertedStreamListener::
|
|||
uint32_t count)
|
||||
{
|
||||
uint32_t read;
|
||||
return stream->ReadSegments(AppendDataToString, &mDecoder->mDecodedData, count,
|
||||
&read);
|
||||
nsAutoCString decodedData;
|
||||
nsresult rv = stream->ReadSegments(AppendDataToString, &decodedData, count,
|
||||
&read);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
MutexAutoLock lock(mDecoder->mMutex);
|
||||
mDecoder->mDecodedData = decodedData;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -90,6 +97,7 @@ nsUnknownDecoder::nsUnknownDecoder()
|
|||
: mBuffer(nullptr)
|
||||
, mBufferLen(0)
|
||||
, mRequireHTMLsuffix(false)
|
||||
, mMutex("nsUnknownDecoder")
|
||||
, mDecodedData("")
|
||||
{
|
||||
nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
|
||||
|
@ -122,6 +130,7 @@ NS_INTERFACE_MAP_BEGIN(nsUnknownDecoder)
|
|||
NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIContentSniffer)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIThreadRetargetableStreamListener)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIStreamListener)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
|
@ -153,6 +162,8 @@ nsUnknownDecoder::AsyncConvertData(const char *aFromType,
|
|||
// hook up our final listener. this guy gets the various On*() calls we want to throw
|
||||
// at him.
|
||||
//
|
||||
|
||||
MutexAutoLock lock(mMutex);
|
||||
mNextListener = aListener;
|
||||
return (aListener) ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -172,9 +183,15 @@ nsUnknownDecoder::OnDataAvailable(nsIRequest* request,
|
|||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
if (!mNextListener) return NS_ERROR_FAILURE;
|
||||
bool contentTypeEmpty;
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
if (!mNextListener) return NS_ERROR_FAILURE;
|
||||
|
||||
if (mContentType.IsEmpty()) {
|
||||
contentTypeEmpty = mContentType.IsEmpty();
|
||||
}
|
||||
|
||||
if (contentTypeEmpty) {
|
||||
uint32_t count, len;
|
||||
|
||||
// If the buffer has not been allocated by now, just fail...
|
||||
|
@ -185,7 +202,7 @@ nsUnknownDecoder::OnDataAvailable(nsIRequest* request,
|
|||
// sniffer buffer...
|
||||
//
|
||||
if (mBufferLen + aCount >= MAX_BUFFER_SIZE) {
|
||||
count = MAX_BUFFER_SIZE-mBufferLen;
|
||||
count = MAX_BUFFER_SIZE - mBufferLen;
|
||||
} else {
|
||||
count = aCount;
|
||||
}
|
||||
|
@ -213,8 +230,13 @@ nsUnknownDecoder::OnDataAvailable(nsIRequest* request,
|
|||
|
||||
// Must not fire ODA again if it failed once
|
||||
if (aCount && NS_SUCCEEDED(rv)) {
|
||||
NS_ASSERTION(!mContentType.IsEmpty(),
|
||||
"Content type should be known by now.");
|
||||
#ifdef DEBUG
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
NS_ASSERTION(!mContentType.IsEmpty(),
|
||||
"Content type should be known by now.");
|
||||
}
|
||||
#endif
|
||||
|
||||
nsCOMPtr<nsIDivertableChannel> divertable = do_QueryInterface(request);
|
||||
if (divertable) {
|
||||
|
@ -225,8 +247,14 @@ nsUnknownDecoder::OnDataAvailable(nsIRequest* request,
|
|||
return rv;
|
||||
}
|
||||
}
|
||||
rv = mNextListener->OnDataAvailable(request, aCtxt, aStream,
|
||||
aSourceOffset, aCount);
|
||||
|
||||
nsCOMPtr<nsIStreamListener> listener;
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
listener = mNextListener;
|
||||
}
|
||||
rv = listener->OnDataAvailable(request, aCtxt, aStream,
|
||||
aSourceOffset, aCount);
|
||||
}
|
||||
|
||||
return rv;
|
||||
|
@ -243,7 +271,10 @@ nsUnknownDecoder::OnStartRequest(nsIRequest* request, nsISupports *aCtxt)
|
|||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
if (!mNextListener) return NS_ERROR_FAILURE;
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
if (!mNextListener) return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Allocate the sniffer buffer...
|
||||
if (NS_SUCCEEDED(rv) && !mBuffer) {
|
||||
|
@ -269,13 +300,19 @@ nsUnknownDecoder::OnStopRequest(nsIRequest* request, nsISupports *aCtxt,
|
|||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
if (!mNextListener) return NS_ERROR_FAILURE;
|
||||
bool contentTypeEmpty;
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
if (!mNextListener) return NS_ERROR_FAILURE;
|
||||
|
||||
contentTypeEmpty = mContentType.IsEmpty();
|
||||
}
|
||||
|
||||
//
|
||||
// The total amount of data is less than the size of the sniffer buffer.
|
||||
// Analyze the buffer now...
|
||||
//
|
||||
if (mContentType.IsEmpty()) {
|
||||
if (contentTypeEmpty) {
|
||||
DetermineContentType(request);
|
||||
|
||||
// Make sure channel listeners see channel as pending while we call
|
||||
|
@ -298,8 +335,13 @@ nsUnknownDecoder::OnStopRequest(nsIRequest* request, nsISupports *aCtxt,
|
|||
}
|
||||
}
|
||||
|
||||
rv = mNextListener->OnStopRequest(request, aCtxt, aStatus);
|
||||
mNextListener = nullptr;
|
||||
nsCOMPtr<nsIStreamListener> listener;
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
listener = mNextListener;
|
||||
mNextListener = nullptr;
|
||||
}
|
||||
rv = listener->OnStopRequest(request, aCtxt, aStatus);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
@ -315,6 +357,9 @@ nsUnknownDecoder::GetMIMETypeFromContent(nsIRequest* aRequest,
|
|||
uint32_t aLength,
|
||||
nsACString& type)
|
||||
{
|
||||
// This is only used by sniffer, therefore we do not need to lock anything
|
||||
// here.
|
||||
|
||||
mBuffer = const_cast<char*>(reinterpret_cast<const char*>(aData));
|
||||
mBufferLen = aLength;
|
||||
DetermineContentType(aRequest);
|
||||
|
@ -388,20 +433,29 @@ uint32_t nsUnknownDecoder::sSnifferEntryNum =
|
|||
|
||||
void nsUnknownDecoder::DetermineContentType(nsIRequest* aRequest)
|
||||
{
|
||||
NS_ASSERTION(mContentType.IsEmpty(), "Content type is already known.");
|
||||
if (!mContentType.IsEmpty()) return;
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
NS_ASSERTION(mContentType.IsEmpty(), "Content type is already known.");
|
||||
if (!mContentType.IsEmpty()) return;
|
||||
}
|
||||
|
||||
const char* testData = mBuffer;
|
||||
uint32_t testDataLen = mBufferLen;
|
||||
// Check if data are compressed.
|
||||
nsCOMPtr<nsIHttpChannel> channel(do_QueryInterface(aRequest));
|
||||
nsAutoCString decodedData;
|
||||
|
||||
if (channel) {
|
||||
// ConvertEncodedData is always called only on a single thread for each
|
||||
// instance of an object.
|
||||
nsresult rv = ConvertEncodedData(aRequest, mBuffer, mBufferLen);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (!mDecodedData.IsEmpty()) {
|
||||
testData = mDecodedData.get();
|
||||
testDataLen = std::min(mDecodedData.Length(), MAX_BUFFER_SIZE);
|
||||
}
|
||||
MutexAutoLock lock(mMutex);
|
||||
decodedData = mDecodedData;
|
||||
}
|
||||
if (!decodedData.IsEmpty()) {
|
||||
testData = decodedData.get();
|
||||
testDataLen = std::min(decodedData.Length(), MAX_BUFFER_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -419,42 +473,60 @@ void nsUnknownDecoder::DetermineContentType(nsIRequest* aRequest)
|
|||
"Both a type string and a type sniffing function set;"
|
||||
" using type string");
|
||||
if (sSnifferEntries[i].mMimeType) {
|
||||
MutexAutoLock lock(mMutex);
|
||||
mContentType = sSnifferEntries[i].mMimeType;
|
||||
NS_ASSERTION(!mContentType.IsEmpty(),
|
||||
"Content type should be known by now.");
|
||||
return;
|
||||
}
|
||||
if ((this->*(sSnifferEntries[i].mContentTypeSniffer))(aRequest)) {
|
||||
#ifdef DEBUG
|
||||
MutexAutoLock lock(mMutex);
|
||||
NS_ASSERTION(!mContentType.IsEmpty(),
|
||||
"Content type should be known by now.");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsAutoCString sniffedType;
|
||||
NS_SniffContent(NS_DATA_SNIFFER_CATEGORY, aRequest,
|
||||
(const uint8_t*)testData, testDataLen, mContentType);
|
||||
if (!mContentType.IsEmpty()) {
|
||||
return;
|
||||
(const uint8_t*)testData, testDataLen, sniffedType);
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
mContentType = sniffedType;
|
||||
if (!mContentType.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (SniffForHTML(aRequest)) {
|
||||
#ifdef DEBUG
|
||||
MutexAutoLock lock(mMutex);
|
||||
NS_ASSERTION(!mContentType.IsEmpty(),
|
||||
"Content type should be known by now.");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
// We don't know what this is yet. Before we just give up, try
|
||||
// the URI from the request.
|
||||
if (SniffURI(aRequest)) {
|
||||
#ifdef DEBUG
|
||||
MutexAutoLock lock(mMutex);
|
||||
NS_ASSERTION(!mContentType.IsEmpty(),
|
||||
"Content type should be known by now.");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
LastDitchSniff(aRequest);
|
||||
#ifdef DEBUG
|
||||
MutexAutoLock lock(mMutex);
|
||||
NS_ASSERTION(!mContentType.IsEmpty(),
|
||||
"Content type should be known by now.");
|
||||
#endif
|
||||
}
|
||||
|
||||
bool nsUnknownDecoder::SniffForHTML(nsIRequest* aRequest)
|
||||
|
@ -468,6 +540,8 @@ bool nsUnknownDecoder::SniffForHTML(nsIRequest* aRequest)
|
|||
return false;
|
||||
}
|
||||
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
||||
// Now look for HTML.
|
||||
const char* str;
|
||||
const char* end;
|
||||
|
@ -553,6 +627,7 @@ bool nsUnknownDecoder::SniffForXML(nsIRequest* aRequest)
|
|||
// First see whether we can glean anything from the uri...
|
||||
if (!SniffURI(aRequest)) {
|
||||
// Oh well; just generic XML will have to do
|
||||
MutexAutoLock lock(mMutex);
|
||||
mContentType = TEXT_XML;
|
||||
}
|
||||
|
||||
|
@ -571,6 +646,7 @@ bool nsUnknownDecoder::SniffURI(nsIRequest* aRequest)
|
|||
nsAutoCString type;
|
||||
result = mimeService->GetTypeFromURI(uri, type);
|
||||
if (NS_SUCCEEDED(result)) {
|
||||
MutexAutoLock lock(mMutex);
|
||||
mContentType = type;
|
||||
return true;
|
||||
}
|
||||
|
@ -592,6 +668,8 @@ bool nsUnknownDecoder::LastDitchSniff(nsIRequest* aRequest)
|
|||
// All we can do now is try to guess whether this is text/plain or
|
||||
// application/octet-stream
|
||||
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
||||
const char* testData;
|
||||
uint32_t testDataLen;
|
||||
if (mDecodedData.IsEmpty()) {
|
||||
|
@ -642,18 +720,26 @@ nsresult nsUnknownDecoder::FireListenerNotifications(nsIRequest* request,
|
|||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
if (!mNextListener) return NS_ERROR_FAILURE;
|
||||
nsCOMPtr<nsIStreamListener> listener;
|
||||
nsAutoCString contentType;
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
if (!mNextListener) return NS_ERROR_FAILURE;
|
||||
|
||||
if (!mContentType.IsEmpty()) {
|
||||
listener = mNextListener;
|
||||
contentType = mContentType;
|
||||
}
|
||||
|
||||
if (!contentType.IsEmpty()) {
|
||||
nsCOMPtr<nsIViewSourceChannel> viewSourceChannel =
|
||||
do_QueryInterface(request);
|
||||
if (viewSourceChannel) {
|
||||
rv = viewSourceChannel->SetOriginalContentType(mContentType);
|
||||
rv = viewSourceChannel->SetOriginalContentType(contentType);
|
||||
} else {
|
||||
nsCOMPtr<nsIChannel> channel = do_QueryInterface(request, &rv);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// Set the new content type on the channel...
|
||||
rv = channel->SetContentType(mContentType);
|
||||
rv = channel->SetContentType(contentType);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -663,7 +749,7 @@ nsresult nsUnknownDecoder::FireListenerNotifications(nsIRequest* request,
|
|||
// Cancel the request to make sure it has the correct status if
|
||||
// mNextListener looks at it.
|
||||
request->Cancel(rv);
|
||||
mNextListener->OnStartRequest(request, aCtxt);
|
||||
listener->OnStartRequest(request, aCtxt);
|
||||
|
||||
nsCOMPtr<nsIDivertableChannel> divertable = do_QueryInterface(request);
|
||||
if (divertable) {
|
||||
|
@ -675,7 +761,7 @@ nsresult nsUnknownDecoder::FireListenerNotifications(nsIRequest* request,
|
|||
}
|
||||
|
||||
// Fire the OnStartRequest(...)
|
||||
rv = mNextListener->OnStartRequest(request, aCtxt);
|
||||
rv = listener->OnStartRequest(request, aCtxt);
|
||||
|
||||
nsCOMPtr<nsIDivertableChannel> divertable = do_QueryInterface(request);
|
||||
if (divertable) {
|
||||
|
@ -692,10 +778,12 @@ nsresult nsUnknownDecoder::FireListenerNotifications(nsIRequest* request,
|
|||
// install stream converter if required
|
||||
nsCOMPtr<nsIEncodedChannel> encodedChannel = do_QueryInterface(request);
|
||||
if (encodedChannel) {
|
||||
nsCOMPtr<nsIStreamListener> listener;
|
||||
rv = encodedChannel->DoApplyContentConversions(mNextListener, getter_AddRefs(listener), aCtxt);
|
||||
if (NS_SUCCEEDED(rv) && listener) {
|
||||
mNextListener = listener;
|
||||
nsCOMPtr<nsIStreamListener> listenerNew;
|
||||
rv = encodedChannel->DoApplyContentConversions(listener, getter_AddRefs(listenerNew), aCtxt);
|
||||
if (NS_SUCCEEDED(rv) && listenerNew) {
|
||||
MutexAutoLock lock(mMutex);
|
||||
mNextListener = listenerNew;
|
||||
listener = listenerNew;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -722,7 +810,7 @@ nsresult nsUnknownDecoder::FireListenerNotifications(nsIRequest* request,
|
|||
rv = out->Write(mBuffer, mBufferLen, &len);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (len == mBufferLen) {
|
||||
rv = mNextListener->OnDataAvailable(request, aCtxt, in, 0, len);
|
||||
rv = listener->OnDataAvailable(request, aCtxt, in, 0, len);
|
||||
} else {
|
||||
NS_ERROR("Unable to write all the data into the pipe.");
|
||||
rv = NS_ERROR_FAILURE;
|
||||
|
@ -746,7 +834,10 @@ nsUnknownDecoder::ConvertEncodedData(nsIRequest* request,
|
|||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
mDecodedData = "";
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
mDecodedData = "";
|
||||
}
|
||||
nsCOMPtr<nsIEncodedChannel> encodedChannel(do_QueryInterface(request));
|
||||
if (encodedChannel) {
|
||||
|
||||
|
@ -783,6 +874,24 @@ nsUnknownDecoder::ConvertEncodedData(nsIRequest* request,
|
|||
return rv;
|
||||
}
|
||||
|
||||
//
|
||||
// nsIThreadRetargetableStreamListener methods
|
||||
//
|
||||
NS_IMETHODIMP
|
||||
nsUnknownDecoder::CheckListenerChain()
|
||||
{
|
||||
nsCOMPtr<nsIThreadRetargetableStreamListener> listener;
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
listener = do_QueryInterface(mNextListener);
|
||||
}
|
||||
if (!listener) {
|
||||
return NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
|
||||
return listener->CheckListenerChain();
|
||||
}
|
||||
|
||||
void
|
||||
nsBinaryDetector::DetermineContentType(nsIRequest* aRequest)
|
||||
{
|
||||
|
@ -823,8 +932,9 @@ nsBinaryDetector::DetermineContentType(nsIRequest* aRequest)
|
|||
if (!contentEncoding.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
LastDitchSniff(aRequest);
|
||||
MutexAutoLock lock(mMutex);
|
||||
if (mContentType.Equals(APPLICATION_OCTET_STREAM)) {
|
||||
// We want to guess at it instead
|
||||
mContentType = APPLICATION_GUESS_FROM_EXT;
|
||||
|
|
|
@ -7,7 +7,10 @@
|
|||
#define nsUnknownDecoder_h__
|
||||
|
||||
#include "nsIStreamConverter.h"
|
||||
#include "nsIThreadRetargetableStreamListener.h"
|
||||
#include "nsIContentSniffer.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsString.h"
|
||||
|
@ -21,7 +24,9 @@
|
|||
}
|
||||
|
||||
|
||||
class nsUnknownDecoder : public nsIStreamConverter, public nsIContentSniffer
|
||||
class nsUnknownDecoder : public nsIStreamConverter
|
||||
, public nsIContentSniffer
|
||||
, public nsIThreadRetargetableStreamListener
|
||||
{
|
||||
public:
|
||||
// nsISupports methods
|
||||
|
@ -39,6 +44,9 @@ public:
|
|||
// nsIContentSniffer methods
|
||||
NS_DECL_NSICONTENTSNIFFER
|
||||
|
||||
// nsIThreadRetargetableStreamListener methods
|
||||
NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
|
||||
|
||||
nsUnknownDecoder();
|
||||
|
||||
protected:
|
||||
|
@ -119,13 +127,18 @@ protected:
|
|||
|
||||
static nsSnifferEntry sSnifferEntries[];
|
||||
static uint32_t sSnifferEntryNum;
|
||||
|
||||
char *mBuffer;
|
||||
uint32_t mBufferLen;
|
||||
bool mRequireHTMLsuffix;
|
||||
|
||||
// We guarantee in order delivery of OnStart, OnStop and OnData, therefore
|
||||
// we do not need proper locking for mBuffer.
|
||||
mozilla::Atomic<char *>mBuffer;
|
||||
mozilla::Atomic<uint32_t> mBufferLen;
|
||||
mozilla::Atomic<bool> mRequireHTMLsuffix;
|
||||
|
||||
nsCString mContentType;
|
||||
|
||||
// This mutex syncs: mContentType, mDecodedData and mNextListener.
|
||||
mutable mozilla::Mutex mMutex;
|
||||
|
||||
protected:
|
||||
nsresult ConvertEncodedData(nsIRequest* request, const char* data,
|
||||
uint32_t length);
|
||||
|
|
Загрузка…
Ссылка в новой задаче