From c23a1e9670f39bf7e3e12328cfdd3f4a5a26c261 Mon Sep 17 00:00:00 2001 From: "cbiesinger%web.de" Date: Fri, 17 Feb 2006 16:54:27 +0000 Subject: [PATCH] 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 --- .../components/bookmarks/content/bookmarks.js | 2 +- .../places/src/nsFaviconService.cpp | 2 +- modules/libpr0n/src/imgLoader.cpp | 5 ++- netwerk/base/public/nsIContentSniffer.idl | 17 ++++++++-- netwerk/base/src/nsBaseChannel.cpp | 32 +++++++++++++++--- netwerk/base/src/nsBaseChannel.h | 5 +-- netwerk/base/src/nsInputStreamPump.cpp | 33 +++++++++++++++++++ netwerk/base/src/nsInputStreamPump.h | 14 ++++++++ netwerk/build/nsNetCID.h | 8 +++++ netwerk/build/nsNetModule.cpp | 6 ++++ .../converters/nsUnknownDecoder.cpp | 28 ++++++++++++++-- .../streamconv/converters/nsUnknownDecoder.h | 6 +++- 12 files changed, 142 insertions(+), 16 deletions(-) diff --git a/browser/components/bookmarks/content/bookmarks.js b/browser/components/bookmarks/content/bookmarks.js index 1f3c3e09ac4..de8a9b72b7a 100644 --- a/browser/components/bookmarks/content/bookmarks.js +++ b/browser/components/bookmarks/content/bookmarks.js @@ -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 diff --git a/browser/components/places/src/nsFaviconService.cpp b/browser/components/places/src/nsFaviconService.cpp index 565739df925..717783d2525 100644 --- a/browser/components/places/src/nsFaviconService.cpp +++ b/browser/components/places/src/nsFaviconService.cpp @@ -680,7 +680,7 @@ FaviconLoadListener::OnStopRequest(nsIRequest *aRequest, nsISupports *aContext, nsCOMPtr 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 diff --git a/modules/libpr0n/src/imgLoader.cpp b/modules/libpr0n/src/imgLoader.cpp index f98f4615501..9136997e632 100644 --- a/modules/libpr0n/src/imgLoader.cpp +++ b/modules/libpr0n/src/imgLoader.cpp @@ -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); } diff --git a/netwerk/base/public/nsIContentSniffer.idl b/netwerk/base/public/nsIContentSniffer.idl index 9cac92f4769..965cbc1f2f3 100644 --- a/netwerk/base/public/nsIContentSniffer.idl +++ b/netwerk/base/public/nsIContentSniffer.idl @@ -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); }; diff --git a/netwerk/base/src/nsBaseChannel.cpp b/netwerk/base/src/nsBaseChannel.cpp index 22b21513fb3..3acf10897d4 100644 --- a/netwerk/base/src/nsBaseChannel.cpp +++ b/netwerk/base/src/nsBaseChannel.cpp @@ -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 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); } diff --git a/netwerk/base/src/nsBaseChannel.h b/netwerk/base/src/nsBaseChannel.h index ca241a1cf9a..4dfdcb01a61 100644 --- a/netwerk/base/src/nsBaseChannel.h +++ b/netwerk/base/src/nsBaseChannel.h @@ -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 mPump; + nsRefPtr mPump; nsCOMPtr mCallbacks; nsCOMPtr mProgressSink; nsCOMPtr mOriginalURI; diff --git a/netwerk/base/src/nsInputStreamPump.cpp b/netwerk/base/src/nsInputStreamPump.cpp index 3413aab5753..c018ecc1d53 100644 --- a/netwerk/base/src/nsInputStreamPump.cpp +++ b/netwerk/base/src/nsInputStreamPump.cpp @@ -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() { diff --git a/netwerk/base/src/nsInputStreamPump.h b/netwerk/base/src/nsInputStreamPump.h index af0253f7bf8..6b7f517a225 100644 --- a/netwerk/base/src/nsInputStreamPump.h +++ b/netwerk/base/src/nsInputStreamPump.h @@ -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 { diff --git a/netwerk/build/nsNetCID.h b/netwerk/build/nsNetCID.h index 2ea6942b9ee..a076e3b2caf 100644 --- a/netwerk/build/nsNetCID.h +++ b/netwerk/build/nsNetCID.h @@ -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. */ diff --git a/netwerk/build/nsNetModule.cpp b/netwerk/build/nsNetModule.cpp index 84352bb0456..4cdf5bff30f 100644 --- a/netwerk/build/nsNetModule.cpp +++ b/netwerk/build/nsNetModule.cpp @@ -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, diff --git a/netwerk/streamconv/converters/nsUnknownDecoder.cpp b/netwerk/streamconv/converters/nsUnknownDecoder.cpp index 41135675c54..ea612677e2c 100644 --- a/netwerk/streamconv/converters/nsUnknownDecoder.cpp +++ b/netwerk/streamconv/converters/nsUnknownDecoder.cpp @@ -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; } diff --git a/netwerk/streamconv/converters/nsUnknownDecoder.h b/netwerk/streamconv/converters/nsUnknownDecoder.h index 78461f511d7..61a5c4d431b 100644 --- a/netwerk/streamconv/converters/nsUnknownDecoder.h +++ b/netwerk/streamconv/converters/nsUnknownDecoder.h @@ -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: