Make <object> do the same text/plain sniffing that <iframe> does, and use the

content type hint if the type comes back as application/octet-stream or
sniffed-binary.  Bug 389677, r+sr=biesi, a=sicking
This commit is contained in:
bzbarsky%mit.edu 2007-08-21 03:26:13 +00:00
Родитель 71d602e83f
Коммит 6a6ea55213
7 изменённых файлов: 128 добавлений и 91 удалений

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

@ -75,6 +75,7 @@
#include "nsThreadUtils.h"
#include "nsNetUtil.h"
#include "nsPresShellIterator.h"
#include "nsMimeTypes.h"
// Concrete classes
#include "nsFrameLoader.h"
@ -373,9 +374,25 @@ nsObjectLoadingContent::OnStartRequest(nsIRequest *aRequest, nsISupports *aConte
// change the order of the declarations!
AutoFallback fallback(this, &rv);
rv = chan->GetContentType(mContentType);
nsCString channelType;
rv = chan->GetContentType(channelType);
NS_ENSURE_SUCCESS(rv, rv);
if (channelType.EqualsASCII(APPLICATION_GUESS_FROM_EXT)) {
channelType = APPLICATION_OCTET_STREAM;
chan->SetContentType(channelType);
}
if (mContentType.IsEmpty() ||
!channelType.EqualsASCII(APPLICATION_OCTET_STREAM)) {
mContentType = channelType;
} else {
// Set the type we'll use for dispatch on the channel. Otherwise we could
// end up trying to dispatch to a nsFrameLoader, which will complain that
// it couldn't find a way to handle application/octet-stream
chan->SetContentType(mContentType);
}
// Now find out what type the content is
// UnloadContent will set our type to null; need to be sure to only set it to
// the real value on success
@ -1071,7 +1088,8 @@ nsObjectLoadingContent::LoadObject(nsIURI* aURI,
nsCOMPtr<nsILoadGroup> group = doc->GetDocumentLoadGroup();
nsCOMPtr<nsIChannel> chan;
rv = NS_NewChannel(getter_AddRefs(chan), aURI, nsnull, group, this);
rv = NS_NewChannel(getter_AddRefs(chan), aURI, nsnull, group, this,
nsIChannel::LOAD_CALL_CONTENT_SNIFFERS);
NS_ENSURE_SUCCESS(rv, rv);
// Referrer

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

@ -784,6 +784,14 @@
#define NS_GENERIC_CONTENT_SNIFFER \
"@mozilla.org/network/content-sniffer;1"
/**
* Detector that can act as either an nsIStreamConverter or an
* nsIContentSniffer to decide whether text/plain data is "really" text/plain
* or APPLICATION_GUESS_FROM_EXT. Use with CreateInstance.
*/
#define NS_BINARYDETECTOR_CONTRACTID \
"@mozilla.org/network/binary-detector;1"
/******************************************************************************
* netwerk/system classes
*/

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

@ -301,7 +301,6 @@ nsresult NS_NewStreamConv(nsStreamConverterService **aStreamConv);
#define MULTI_MIXED "?from=multipart/mixed&to=*/*"
#define MULTI_BYTERANGES "?from=multipart/byteranges&to=*/*"
#define UNKNOWN_CONTENT "?from=" UNKNOWN_CONTENT_TYPE "&to=*/*"
#define MAYBE_TEXT "?from=" APPLICATION_MAYBE_TEXT "&to=*/*"
#define GZIP_TO_UNCOMPRESSED "?from=gzip&to=uncompressed"
#define XGZIP_TO_UNCOMPRESSED "?from=x-gzip&to=uncompressed"
#define COMPRESS_TO_UNCOMPRESSED "?from=compress&to=uncompressed"
@ -321,7 +320,6 @@ static const char *const sStreamConverterArray[] = {
MULTI_MIXED,
MULTI_BYTERANGES,
UNKNOWN_CONTENT,
MAYBE_TEXT,
GZIP_TO_UNCOMPRESSED,
XGZIP_TO_UNCOMPRESSED,
COMPRESS_TO_UNCOMPRESSED,
@ -855,8 +853,9 @@ static const nsModuleComponentInfo gNetModuleInfo[] = {
{ "Binary Detector",
NS_BINARYDETECTOR_CID,
NS_ISTREAMCONVERTER_KEY MAYBE_TEXT,
CreateNewBinaryDetectorFactory
NS_BINARYDETECTOR_CONTRACTID,
CreateNewBinaryDetectorFactory,
nsBinaryDetector::Register
},
{ "HttpCompressConverter",

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

@ -191,7 +191,6 @@
#define UNKNOWN_CONTENT_TYPE "application/x-unknown-content-type"
#define APPLICATION_GUESS_FROM_EXT "application/x-vnd.mozilla.guess-from-ext"
#define APPLICATION_MAYBE_TEXT "application/x-vnd.mozilla.maybe-text"
#define VIEWSOURCE_CONTENT_TYPE "application/x-view-source"
#define APPLICATION_DIRECTORY "application/directory" /* text/x-vcard is synonym */

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

@ -56,17 +56,12 @@
#include "nsIMIMEService.h"
#include "nsIViewSourceChannel.h"
#include "nsIHttpChannel.h"
#include "nsNetCID.h"
#include "prcpucfg.h" // To get IS_LITTLE_ENDIAN / IS_BIG_ENDIAN
#define MAX_BUFFER_SIZE 1024
#if defined WORDS_BIGENDIAN || defined IS_BIG_ENDIAN
#define LITTLE_TO_NATIVE16(x) ((((x) & 0xFF) << 8) | ((x) >> 8))
#else
#define LITTLE_TO_NATIVE16(x) x
#endif
nsUnknownDecoder::nsUnknownDecoder()
: mBuffer(nsnull)
, mBufferLen(0)
@ -187,8 +182,6 @@ nsUnknownDecoder::OnDataAvailable(nsIRequest* request,
DetermineContentType(request);
NS_ASSERTION(!mContentType.IsEmpty(),
"Content type should be known by now.");
rv = FireListenerNotifications(request, aCtxt);
}
}
@ -246,8 +239,6 @@ nsUnknownDecoder::OnStopRequest(nsIRequest* request, nsISupports *aCtxt,
if (mContentType.IsEmpty()) {
DetermineContentType(request);
NS_ASSERTION(!mContentType.IsEmpty(),
"Content type should be known by now.");
rv = FireListenerNotifications(request, aCtxt);
if (NS_FAILED(rv)) {
@ -364,29 +355,41 @@ void nsUnknownDecoder::DetermineContentType(nsIRequest* aRequest)
" using type string");
if (sSnifferEntries[i].mMimeType) {
mContentType = sSnifferEntries[i].mMimeType;
NS_ASSERTION(!mContentType.IsEmpty(),
"Content type should be known by now.");
return;
}
else if ((this->*(sSnifferEntries[i].mContentTypeSniffer))(aRequest)) {
if ((this->*(sSnifferEntries[i].mContentTypeSniffer))(aRequest)) {
NS_ASSERTION(!mContentType.IsEmpty(),
"Content type should be known by now.");
return;
}
}
}
if (TryContentSniffers(aRequest)) {
NS_ASSERTION(!mContentType.IsEmpty(),
"Content type should be known by now.");
return;
}
if (SniffForHTML(aRequest)) {
NS_ASSERTION(!mContentType.IsEmpty(),
"Content type should be known by now.");
return;
}
// We don't know what this is yet. Before we just give up, try
// the URI from the request.
if (SniffURI(aRequest)) {
NS_ASSERTION(!mContentType.IsEmpty(),
"Content type should be known by now.");
return;
}
LastDitchSniff(aRequest);
NS_ASSERTION(!mContentType.IsEmpty(),
"Content type should be known by now.");
}
PRBool nsUnknownDecoder::TryContentSniffers(nsIRequest* aRequest)
@ -600,24 +603,28 @@ nsresult nsUnknownDecoder::FireListenerNotifications(nsIRequest* request,
if (!mNextListener) return NS_ERROR_FAILURE;
nsCOMPtr<nsIViewSourceChannel> viewSourceChannel = do_QueryInterface(request);
if (viewSourceChannel) {
rv = viewSourceChannel->SetOriginalContentType(mContentType);
} else {
nsCOMPtr<nsIChannel> channel = do_QueryInterface(request, &rv);
if (NS_SUCCEEDED(rv)) {
// Set the new content type on the channel...
rv = channel->SetContentType(mContentType);
if (!mContentType.IsEmpty()) {
nsCOMPtr<nsIViewSourceChannel> viewSourceChannel =
do_QueryInterface(request);
if (viewSourceChannel) {
rv = viewSourceChannel->SetOriginalContentType(mContentType);
} else {
nsCOMPtr<nsIChannel> channel = do_QueryInterface(request, &rv);
if (NS_SUCCEEDED(rv)) {
// Set the new content type on the channel...
rv = channel->SetContentType(mContentType);
}
}
}
NS_ASSERTION(NS_SUCCEEDED(rv), "Unable to set content type on channel!");
if (NS_FAILED(rv)) {
// Cancel the request to make sure it has the correct status if
// mNextListener looks at it.
request->Cancel(rv);
mNextListener->OnStartRequest(request, aCtxt);
return rv;
NS_ASSERTION(NS_SUCCEEDED(rv), "Unable to set content type on channel!");
if (NS_FAILED(rv)) {
// Cancel the request to make sure it has the correct status if
// mNextListener looks at it.
request->Cancel(rv);
mNextListener->OnStartRequest(request, aCtxt);
return rv;
}
}
// Fire the OnStartRequest(...)
@ -664,9 +671,63 @@ nsresult nsUnknownDecoder::FireListenerNotifications(nsIRequest* request,
void
nsBinaryDetector::DetermineContentType(nsIRequest* aRequest)
{
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aRequest);
if (!httpChannel) {
return;
}
// It's an HTTP channel. Check for the text/plain mess
nsCAutoString contentTypeHdr;
httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("Content-Type"),
contentTypeHdr);
nsCAutoString contentType;
httpChannel->GetContentType(contentType);
// Make sure to do a case-sensitive exact match comparison here. Apache
// 1.x just sends text/plain for "unknown", while Apache 2.x sends
// text/plain with a ISO-8859-1 charset. Debian's Apache version, just to
// be different, sends text/plain with iso-8859-1 charset. Don't do
// general case-insensitive comparison, since we really want to apply this
// crap as rarely as we can.
if (!contentType.EqualsLiteral("text/plain") ||
(!contentTypeHdr.EqualsLiteral("text/plain") &&
!contentTypeHdr.EqualsLiteral("text/plain; charset=ISO-8859-1") &&
!contentTypeHdr.EqualsLiteral("text/plain; charset=iso-8859-1"))) {
return;
}
// Check whether we have content-encoding. If we do, don't try to
// detect the type.
// XXXbz we could improve this by doing a local decompress if we
// wanted, I'm sure.
nsCAutoString contentEncoding;
httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("Content-Encoding"),
contentEncoding);
if (!contentEncoding.IsEmpty()) {
return;
}
LastDitchSniff(aRequest);
if (mContentType.Equals(APPLICATION_OCTET_STREAM)) {
// We want to guess at it instead
mContentType = APPLICATION_GUESS_FROM_EXT;
}
}
NS_METHOD
nsBinaryDetector::Register(nsIComponentManager* compMgr, nsIFile* path,
const char* registryLocation,
const char* componentType,
const nsModuleComponentInfo *info)
{
nsresult rv;
nsCOMPtr<nsICategoryManager> catman =
do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv);
if (NS_FAILED(rv))
return rv;
return catman->AddCategoryEntry(NS_CONTENT_SNIFFER_CATEGORY,
"Binary Detector",
NS_BINARYDETECTOR_CONTRACTID,
PR_TRUE, PR_TRUE, nsnull);
}

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

@ -41,6 +41,7 @@
#include "nsIStreamConverter.h"
#include "nsIChannel.h"
#include "nsIContentSniffer.h"
#include "nsIGenericFactory.h"
#include "nsCOMPtr.h"
#include "nsString.h"
@ -158,6 +159,12 @@ protected:
*/
class nsBinaryDetector : public nsUnknownDecoder
{
public:
static NS_METHOD Register(nsIComponentManager* compMgr, nsIFile* path,
const char* registryLocation,
const char* componentType,
const nsModuleComponentInfo *info);
protected:
virtual void DetermineContentType(nsIRequest* aRequest);
};

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

@ -277,62 +277,7 @@ NS_IMETHODIMP nsDocumentOpenInfo::OnStartRequest(nsIRequest *request, nsISupport
return NS_OK;
}
if (httpChannel && mContentType.IsEmpty()) {
// This is our initial dispatch, and this is an HTTP channel. Check for
// the text/plain mess.
nsCAutoString contentTypeHdr;
httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("Content-Type"),
contentTypeHdr);
nsCAutoString contentType;
httpChannel->GetContentType(contentType);
// Make sure to do a case-sensitive exact match comparison here. Apache
// 1.x just sends text/plain for "unknown", while Apache 2.x sends
// text/plain with a ISO-8859-1 charset. Debian's Apache version, just to
// be different, sends text/plain with iso-8859-1 charset. Don't do
// general case-insensitive comparison, since we really want to apply this
// crap as rarely as we can.
if (contentType.EqualsLiteral("text/plain") &&
(contentTypeHdr.EqualsLiteral("text/plain") ||
contentTypeHdr.Equals(
NS_LITERAL_CSTRING("text/plain; charset=ISO-8859-1")) ||
contentTypeHdr.Equals(
NS_LITERAL_CSTRING("text/plain; charset=iso-8859-1")))) {
// Check whether we have content-encoding. If we do, don't try to detect
// the type, since that will lead to the content being automatically
// decompressed....
nsCAutoString contentEncoding;
httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("Content-Encoding"),
contentEncoding);
if (contentEncoding.IsEmpty()) {
// OK, this is initial dispatch of an HTTP response and its Content-Type
// header is exactly "text/plain". We need to check whether this is
// really text.... Note that some of our listeners will actually
// accept all types, including the APPLICATION_MAYBE_TEXT internal
// type, so we need to call ConvertData here manually instead of
// relying on DispatchContent to do it.
LOG((" Possibly bogus text/plain; trying to sniff for real type"));
rv = ConvertData(request, m_contentListener,
NS_LITERAL_CSTRING(APPLICATION_MAYBE_TEXT),
NS_LITERAL_CSTRING("*/*"));
if (NS_FAILED(rv)) {
// We failed to convert. Just go ahead and handle as the original
// type. If ConvertData happened to set our m_targetStreamListener,
// we don't want it!
m_targetStreamListener = nsnull;
}
else {
LOG((APPLICATION_MAYBE_TEXT " converter taking over now"));
}
}
}
}
// If we sniffed text/plain above, m_targetStreamListener may already be
// non-null.
if (!m_targetStreamListener) {
rv = DispatchContent(request, aCtxt);
}
rv = DispatchContent(request, aCtxt);
LOG((" After dispatch, m_targetStreamListener: 0x%p, rv: 0x%08X", m_targetStreamListener.get(), rv));