зеркало из https://github.com/mozilla/pjs.git
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:
Родитель
71d602e83f
Коммит
6a6ea55213
|
@ -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));
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче