зеркало из https://github.com/mozilla/pjs.git
bug 325177 r=darin sr=bz
- add a "request" parameter to nsIContentSniffer - make the unknowndecoder implement nsIContentSniffer - make nsBaseChannel do type detection via nsIContentSniffer rather than a stream converter
This commit is contained in:
Родитель
d9118d9569
Коммит
c23a1e9670
|
@ -2286,7 +2286,7 @@ bookmarksFavIconLoadListener.prototype = {
|
|||
var sniffer = Components.classes[snifferCID].getService(nsIContentSniffer);
|
||||
|
||||
try {
|
||||
mimeType = sniffer.getMIMETypeFromContent (this.mBytes, this.mCountRead);
|
||||
mimeType = sniffer.getMIMETypeFromContent (aRequest, this.mBytes, this.mCountRead);
|
||||
} catch (e) {
|
||||
mimeType = null;
|
||||
// ignore
|
||||
|
|
|
@ -680,7 +680,7 @@ FaviconLoadListener::OnStopRequest(nsIRequest *aRequest, nsISupports *aContext,
|
|||
nsCOMPtr<nsIContentSniffer> sniffer = do_GetService(snifferCID.get(), &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
sniffer->GetMIMETypeFromContent(
|
||||
sniffer->GetMIMETypeFromContent(aRequest,
|
||||
NS_REINTERPRET_CAST(PRUint8*, NS_CONST_CAST(char*, mData.get())),
|
||||
mData.Length(), mimeType);
|
||||
// ignore errors: mime type will be left empty and we'll try the next sniffer
|
||||
|
|
|
@ -736,7 +736,10 @@ NS_IMETHODIMP imgLoader::SupportImageWithMimeType(const char* aMimeType, PRBool
|
|||
return reg->IsContractIDRegistered(decoderId.get(), _retval);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP imgLoader::GetMIMETypeFromContent(const PRUint8* aContents, PRUint32 aLength, nsACString& aContentType)
|
||||
NS_IMETHODIMP imgLoader::GetMIMETypeFromContent(nsIRequest* aRequest,
|
||||
const PRUint8* aContents,
|
||||
PRUint32 aLength,
|
||||
nsACString& aContentType)
|
||||
{
|
||||
return GetMimeTypeFromContent((const char*)aContents, aLength, aContentType);
|
||||
}
|
||||
|
|
|
@ -36,21 +36,32 @@
|
|||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIRequest;
|
||||
|
||||
/**
|
||||
* Content sniffer interface. Components implementing this interface can
|
||||
* determine a MIME type from a chunk of bytes.
|
||||
*/
|
||||
[scriptable, uuid(a5710331-74ec-45fb-aa85-ed3bc7c36924)]
|
||||
[scriptable, uuid(a5772d1b-fc63-495e-a169-96e8d3311af0)]
|
||||
interface nsIContentSniffer : nsISupports
|
||||
{
|
||||
/**
|
||||
* Given a chunk of data, determines a MIME type.
|
||||
* Given a chunk of data, determines a MIME type. Information from the given
|
||||
* request may be used in order to make a better decision.
|
||||
*
|
||||
* @param aRequest The request where this data came from. May be null.
|
||||
* @param aData Data to check
|
||||
* @param aLength Length of the data
|
||||
*
|
||||
* @return The content type
|
||||
*
|
||||
* @throw NS_ERROR_NOT_AVAILABLE if no MIME type could be determined.
|
||||
*
|
||||
* @note Implementations should consider the request read-only. Especially,
|
||||
* they should not attempt to set the content type property that subclasses of
|
||||
* nsIRequest might offer.
|
||||
*/
|
||||
ACString getMIMETypeFromContent([const,array,size_is(aLength)] in octet aData,
|
||||
ACString getMIMETypeFromContent(in nsIRequest aRequest,
|
||||
[const,array,size_is(aLength)] in octet aData,
|
||||
in unsigned long aLength);
|
||||
};
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include "nsIHttpChannel.h"
|
||||
#include "nsIChannelEventSink.h"
|
||||
#include "nsIStreamConverterService.h"
|
||||
#include "nsIContentSniffer.h"
|
||||
|
||||
// Determine if this URI is using a safe port.
|
||||
static nsresult
|
||||
|
@ -456,10 +457,14 @@ nsBaseChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt)
|
|||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
rv = NS_NewInputStreamPump(getter_AddRefs(mPump), stream, -1, -1, 0, 0,
|
||||
PR_TRUE);
|
||||
if (NS_FAILED(rv))
|
||||
mPump = new nsInputStreamPump();
|
||||
if (!mPump)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
rv = mPump->Init(stream, -1, -1, 0, 0, PR_TRUE);
|
||||
if (NS_FAILED(rv)) {
|
||||
mPump = nsnull;
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = mPump->AsyncRead(this, nsnull);
|
||||
if (NS_FAILED(rv)) {
|
||||
|
@ -525,13 +530,30 @@ nsBaseChannel::GetInterface(const nsIID &iid, void **result)
|
|||
//-----------------------------------------------------------------------------
|
||||
// nsBaseChannel::nsIRequestObserver
|
||||
|
||||
static void
|
||||
CallTypeSniffers(void *aClosure, const PRUint8 *aData, PRUint32 aCount)
|
||||
{
|
||||
nsIChannel *chan = NS_STATIC_CAST(nsIChannel*, aClosure);
|
||||
|
||||
nsCOMPtr<nsIContentSniffer> sniffer =
|
||||
do_CreateInstance(NS_GENERIC_CONTENT_SNIFFER);
|
||||
if (!sniffer)
|
||||
return;
|
||||
|
||||
nsCAutoString detected;
|
||||
nsresult rv = sniffer->GetMIMETypeFromContent(chan, aData, aCount, detected);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
chan->SetContentType(detected);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseChannel::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
|
||||
{
|
||||
// If our content type is unknown, then use the content type sniffer. If the
|
||||
// sniffer is not available for some reason, then we just keep going as-is.
|
||||
if (NS_SUCCEEDED(mStatus) && mContentType.EqualsLiteral(UNKNOWN_CONTENT_TYPE))
|
||||
PushStreamConverter(UNKNOWN_CONTENT_TYPE, "*/*", PR_FALSE);
|
||||
if (NS_SUCCEEDED(mStatus) && mContentType.EqualsLiteral(UNKNOWN_CONTENT_TYPE)) {
|
||||
mPump->PeekStream(CallTypeSniffers, NS_STATIC_CAST(nsIChannel*, this));
|
||||
}
|
||||
|
||||
return mListener->OnStartRequest(this, mListenerContext);
|
||||
}
|
||||
|
|
|
@ -39,11 +39,12 @@
|
|||
#define nsBaseChannel_h__
|
||||
|
||||
#include "nsString.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsHashPropertyBag.h"
|
||||
#include "nsInputStreamPump.h"
|
||||
|
||||
#include "nsIChannel.h"
|
||||
#include "nsIInputStreamPump.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsILoadGroup.h"
|
||||
|
@ -212,7 +213,7 @@ private:
|
|||
mQueriedProgressSink = PR_FALSE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStreamPump> mPump;
|
||||
nsRefPtr<nsInputStreamPump> mPump;
|
||||
nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
|
||||
nsCOMPtr<nsIProgressEventSink> mProgressSink;
|
||||
nsCOMPtr<nsIURI> mOriginalURI;
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include "nsITransport.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsEventQueueUtils.h"
|
||||
#include "nsNetSegmentUtils.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "prlog.h"
|
||||
|
||||
|
@ -80,6 +81,38 @@ nsInputStreamPump::~nsInputStreamPump()
|
|||
{
|
||||
}
|
||||
|
||||
struct PeekData {
|
||||
PeekData(nsInputStreamPump::PeekSegmentFun fun, void* closure)
|
||||
: mFunc(fun), mClosure(closure) {}
|
||||
|
||||
nsInputStreamPump::PeekSegmentFun mFunc;
|
||||
void* mClosure;
|
||||
};
|
||||
|
||||
static NS_METHOD
|
||||
CallPeekFunc(nsIInputStream *aInStream, void *aClosure,
|
||||
const char *aFromSegment, PRUint32 aToOffset, PRUint32 aCount,
|
||||
PRUint32 *aWriteCount)
|
||||
{
|
||||
NS_ASSERTION(aToOffset == 0, "Called more than once?");
|
||||
NS_ASSERTION(aCount > 0, "Called without data?");
|
||||
|
||||
PeekData* data = NS_STATIC_CAST(PeekData*, aClosure);
|
||||
data->mFunc(data->mClosure,
|
||||
NS_REINTERPRET_CAST(const PRUint8*, aFromSegment), aCount);
|
||||
return NS_BINDING_ABORTED;
|
||||
}
|
||||
|
||||
void
|
||||
nsInputStreamPump::PeekStream(PeekSegmentFun callback, void* closure)
|
||||
{
|
||||
NS_ASSERTION(mAsyncStream, "PeekStream called without stream");
|
||||
PeekData data(callback, closure);
|
||||
PRUint32 read;
|
||||
mAsyncStream->ReadSegments(CallPeekFunc, &data, NET_DEFAULT_SEGMENT_SIZE,
|
||||
&read);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsInputStreamPump::EnsureWaiting()
|
||||
{
|
||||
|
|
|
@ -61,6 +61,20 @@ public:
|
|||
nsInputStreamPump();
|
||||
~nsInputStreamPump();
|
||||
|
||||
typedef void (*PeekSegmentFun)(void *closure, const PRUint8 *buf,
|
||||
PRUint32 bufLen);
|
||||
/**
|
||||
* Peek into the first chunk of data that's in the stream. Note that this
|
||||
* method will not call the callback when there is no data in the stream.
|
||||
* The callback will be called at most once.
|
||||
*
|
||||
* The data from the stream will not be consumed, i.e. the pump's listener
|
||||
* can still read all the data.
|
||||
*
|
||||
* Do not call before asyncRead. Do not call after onStopRequest.
|
||||
*/
|
||||
NS_HIDDEN_(void) PeekStream(PeekSegmentFun callback, void *closure);
|
||||
|
||||
protected:
|
||||
|
||||
enum {
|
||||
|
|
|
@ -748,6 +748,14 @@
|
|||
{0xa1, 0x6c, 0x00, 0x50, 0x04, 0x1c, 0xaf, 0x44} \
|
||||
}
|
||||
|
||||
/**
|
||||
* General-purpose content sniffer component. Use with CreateInstance.
|
||||
*
|
||||
* Implements nsIContentSniffer
|
||||
*/
|
||||
#define NS_GENERIC_CONTENT_SNIFFER \
|
||||
"@mozilla.org/network/content-sniffer;1"
|
||||
|
||||
/******************************************************************************
|
||||
* Contracts that can be implemented by necko users.
|
||||
*/
|
||||
|
|
|
@ -841,6 +841,12 @@ static const nsModuleComponentInfo gNetModuleInfo[] = {
|
|||
CreateNewUnknownDecoderFactory
|
||||
},
|
||||
|
||||
{ "Unknown Content-Type Decoder",
|
||||
NS_UNKNOWNDECODER_CID,
|
||||
NS_GENERIC_CONTENT_SNIFFER,
|
||||
CreateNewUnknownDecoderFactory
|
||||
},
|
||||
|
||||
{ "Binary Detector",
|
||||
NS_BINARYDETECTOR_CID,
|
||||
NS_ISTREAMCONVERTER_KEY MAYBE_TEXT,
|
||||
|
|
|
@ -101,7 +101,8 @@ NS_INTERFACE_MAP_BEGIN(nsUnknownDecoder)
|
|||
NS_INTERFACE_MAP_ENTRY(nsIStreamConverter)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIContentSniffer)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIStreamListener)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
|
||||
|
@ -260,6 +261,28 @@ nsUnknownDecoder::OnStopRequest(nsIRequest* request, nsISupports *aCtxt,
|
|||
return rv;
|
||||
}
|
||||
|
||||
// ----
|
||||
//
|
||||
// nsIContentSniffer methods...
|
||||
//
|
||||
// ----
|
||||
NS_IMETHODIMP
|
||||
nsUnknownDecoder::GetMIMETypeFromContent(nsIRequest* aRequest,
|
||||
const PRUint8* aData,
|
||||
PRUint32 aLength,
|
||||
nsACString& type)
|
||||
{
|
||||
mBuffer = NS_CONST_CAST(char*, NS_REINTERPRET_CAST(const char*, aData));
|
||||
mBufferLen = aLength;
|
||||
DetermineContentType(aRequest);
|
||||
mBuffer = nsnull;
|
||||
mBufferLen = 0;
|
||||
type.Assign(mContentType);
|
||||
mContentType.Truncate();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
// Actual sniffing code
|
||||
|
||||
PRBool nsUnknownDecoder::AllowSniffing(nsIRequest* aRequest)
|
||||
|
@ -399,7 +422,8 @@ PRBool nsUnknownDecoder::TryContentSniffers(nsIRequest* aRequest)
|
|||
continue;
|
||||
}
|
||||
|
||||
rv = sniffer->GetMIMETypeFromContent((const PRUint8*)mBuffer, mBufferLen, mContentType);
|
||||
rv = sniffer->GetMIMETypeFromContent(aRequest, (const PRUint8*)mBuffer,
|
||||
mBufferLen, mContentType);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
|
||||
#include "nsIStreamConverter.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsIContentSniffer.h"
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsString.h"
|
||||
|
@ -53,7 +54,7 @@
|
|||
}
|
||||
|
||||
|
||||
class nsUnknownDecoder : public nsIStreamConverter
|
||||
class nsUnknownDecoder : public nsIStreamConverter, public nsIContentSniffer
|
||||
{
|
||||
public:
|
||||
// nsISupports methods
|
||||
|
@ -68,6 +69,9 @@ public:
|
|||
// nsIRequestObserver methods
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
|
||||
// nsIContentSniffer methods
|
||||
NS_DECL_NSICONTENTSNIFFER
|
||||
|
||||
nsUnknownDecoder();
|
||||
|
||||
protected:
|
||||
|
|
Загрузка…
Ссылка в новой задаче