- 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:
cbiesinger%web.de 2006-02-17 16:54:27 +00:00
Родитель d9118d9569
Коммит c23a1e9670
12 изменённых файлов: 142 добавлений и 16 удалений

Просмотреть файл

@ -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: