Make setting contentType or contentCharset act as hints if done before channel

open; use this in the CSSLoader to hint that we want text/css data.  Bug
120789, r=dougt, sr=darin
This commit is contained in:
bzbarsky%mit.edu 2003-06-23 21:00:46 +00:00
parent 97601586ac
commit f75f9017d9
18 changed files with 189 additions and 104 deletions

View File

@ -1359,6 +1359,10 @@ CSSLoaderImpl::LoadSheet(SheetLoadData* aLoadData, StyleSheetState aSheetState)
}
}
// Now tell the channel we expect text/css data back.... We do
// this before opening it, so it's only treated as a hint.
channel->SetContentType(NS_LITERAL_CSTRING("text/css"));
// We don't have to hold on to the stream loader. The ownership
// model is: Necko owns the stream loader, which owns the load data,
// which owns us

View File

@ -1359,6 +1359,10 @@ CSSLoaderImpl::LoadSheet(SheetLoadData* aLoadData, StyleSheetState aSheetState)
}
}
// Now tell the channel we expect text/css data back.... We do
// this before opening it, so it's only treated as a hint.
channel->SetContentType(NS_LITERAL_CSTRING("text/css"));
// We don't have to hold on to the stream loader. The ownership
// model is: Necko owns the stream loader, which owns the load data,
// which owns us

View File

@ -507,6 +507,9 @@ nsJARChannel::GetContentType(nsACString &result)
NS_IMETHODIMP
nsJARChannel::SetContentType(const nsACString &aContentType)
{
// If someone gives us a type hint we should just use that type instead of
// doing our guessing. So we don't care when this is being called.
// mContentCharset is unchanged if not parsed
NS_ParseContentType(aContentType, mContentType, mContentCharset);
return NS_OK;
@ -515,6 +518,8 @@ nsJARChannel::SetContentType(const nsACString &aContentType)
NS_IMETHODIMP
nsJARChannel::GetContentCharset(nsACString &aContentCharset)
{
// If someone gives us a charset hint we should just use that charset.
// So we don't care when this is being called.
aContentCharset = mContentCharset;
return NS_OK;
}

View File

@ -107,7 +107,17 @@ interface nsIChannel : nsIRequest
*
* NOTE: the content type can often be wrongly specified (e.g., wrong file
* extension, wrong MIME type, wrong document type stored on a server, etc.),
* and the caller most likely wants to verify with the actual data.
* and the caller most likely wants to verify with the actual data.
*
* Setting contentType before the channel has been opened provides a hint
* to the channel as to what the MIME type is. The channel may ignore this
* hint in deciding on the actual MIME type that it will report.
*
* Setting contentType after onStartRequest has been fired or after open()
* is called will override the type determined by the channel.
*
* Setting contentType between the time that asyncOpen() is called and the
* time when onStartRequest is fired has undefined behavior at this time.
*/
attribute ACString contentType;

View File

@ -240,6 +240,9 @@ nsInputStreamChannel::GetContentType(nsACString &aContentType)
NS_IMETHODIMP
nsInputStreamChannel::SetContentType(const nsACString &aContentType)
{
// If someone gives us a type hint we should just use that type.
// So we don't care when this is being called.
// mContentCharset is unchanged if not parsed
NS_ParseContentType(aContentType, mContentType, mContentCharset);
return NS_OK;
@ -255,6 +258,8 @@ nsInputStreamChannel::GetContentCharset(nsACString &aContentCharset)
NS_IMETHODIMP
nsInputStreamChannel::SetContentCharset(const nsACString &aContentCharset)
{
// If someone gives us a charset hint we should just use that charset.
// So we don't care when this is being called.
mContentCharset = aContentCharset;
return NS_OK;
}

View File

@ -56,10 +56,12 @@ static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
// nsDataChannel methods
nsDataChannel::nsDataChannel() {
mStatus = NS_OK;
mContentLength = -1;
mLoadFlags = nsIRequest::LOAD_NORMAL;
nsDataChannel::nsDataChannel() :
mStatus(NS_OK),
mLoadFlags(nsIRequest::LOAD_NORMAL),
mContentLength(-1),
mOpened(PR_FALSE)
{
}
nsDataChannel::~nsDataChannel() {
@ -362,6 +364,7 @@ nsDataChannel::Open(nsIInputStream **_retval)
{
NS_ENSURE_ARG_POINTER(_retval);
NS_ADDREF(*_retval = mDataStream);
mOpened = PR_TRUE;
return NS_OK;
}
@ -386,6 +389,7 @@ nsDataChannel::AsyncOpen(nsIStreamListener *aListener, nsISupports *ctxt)
// Hold onto the real consumer...
mListener = aListener;
mOpened = PR_TRUE;
// Add the request to the loadgroup (if available)
if (mLoadGroup) {
@ -437,7 +441,10 @@ nsDataChannel::GetContentType(nsACString &aContentType)
NS_IMETHODIMP
nsDataChannel::SetContentType(const nsACString &aContentType)
{
mContentType = aContentType;
// Ignore content-type hints
if (mOpened) {
mContentType = aContentType;
}
return NS_OK;
}
@ -451,7 +458,10 @@ nsDataChannel::GetContentCharset(nsACString &aContentCharset)
NS_IMETHODIMP
nsDataChannel::SetContentCharset(const nsACString &aContentCharset)
{
mContentCharset = aContentCharset;
// Ignore content-charset hints
if (mOpened) {
mContentCharset = aContentCharset;
}
return NS_OK;
}

View File

@ -84,6 +84,7 @@ protected:
PRInt32 mContentLength;
nsCOMPtr<nsISupports> mOwner;
nsCOMPtr<nsIStreamListener> mListener;
PRBool mOpened;
};
#endif /* nsFTPChannel_h___ */
#endif /* nsDataChannel_h___ */

View File

@ -312,6 +312,9 @@ nsFileChannel::GetContentType(nsACString &aContentType)
NS_IMETHODIMP
nsFileChannel::SetContentType(const nsACString &aContentType)
{
// If someone gives us a type hint we should just use that type instead of
// doing our guessing. So we don't care when this is being called.
// mContentCharset is unchanged if not parsed
NS_ParseContentType(aContentType, mContentType, mContentCharset);
return NS_OK;
@ -327,6 +330,8 @@ nsFileChannel::GetContentCharset(nsACString &aContentCharset)
NS_IMETHODIMP
nsFileChannel::SetContentCharset(const nsACString &aContentCharset)
{
// If someone gives us a charset hint we should just use that charset.
// So we don't care when this is being called.
mContentCharset = aContentCharset;
return NS_OK;
}

View File

@ -411,6 +411,8 @@ nsFTPChannel::GetContentType(nsACString &aContentType)
NS_IMETHODIMP
nsFTPChannel::SetContentType(const nsACString &aContentType)
{
// If someone gives us a type hint we should just use that type instead of
// doing our guessing. So we don't care when this is being called.
nsAutoLock lock(mLock);
NS_ParseContentType(aContentType, mContentType, mContentCharset);
return NS_OK;
@ -426,6 +428,8 @@ nsFTPChannel::GetContentCharset(nsACString &aContentCharset)
NS_IMETHODIMP
nsFTPChannel::SetContentCharset(const nsACString &aContentCharset)
{
// If someone gives us a charset hint we should just use that charset.
// So we don't care when this is being called.
mContentCharset = aContentCharset;
return NS_OK;
}

View File

@ -389,8 +389,13 @@ nsGopherChannel::GetContentType(nsACString &aContentType)
aContentType = NS_LITERAL_CSTRING(TEXT_PLAIN);
break;
default:
NS_WARNING("Unknown gopher type");
aContentType = NS_LITERAL_CSTRING(UNKNOWN_CONTENT_TYPE);
if (!mContentTypeHint.IsEmpty()) {
aContentType = mContentTypeHint;
} else {
NS_WARNING("Unknown gopher type");
aContentType = NS_LITERAL_CSTRING(UNKNOWN_CONTENT_TYPE);
}
break;
}
PR_LOG(gGopherLog,PR_LOG_DEBUG,
@ -403,8 +408,17 @@ nsGopherChannel::GetContentType(nsACString &aContentType)
NS_IMETHODIMP
nsGopherChannel::SetContentType(const nsACString &aContentType)
{
// only changes mContentCharset if a charset is parsed
NS_ParseContentType(aContentType, mContentType, mContentCharset);
if (mIsPending) {
// only changes mContentCharset if a charset is parsed
NS_ParseContentType(aContentType, mContentType, mContentCharset);
} else {
// We are being given a content-type hint. Since we have no ways of
// determining a charset on our own, just set mContentCharset from the
// charset part of this.
nsCAutoString charsetBuf;
NS_ParseContentType(aContentType, mContentTypeHint, mContentCharset);
}
return NS_OK;
}
@ -418,6 +432,8 @@ nsGopherChannel::GetContentCharset(nsACString &aContentCharset)
NS_IMETHODIMP
nsGopherChannel::SetContentCharset(const nsACString &aContentCharset)
{
// If someone gives us a charset hint we should just use that charset.
// So we don't care when this is being called.
mContentCharset = aContentCharset;
return NS_OK;
}

View File

@ -76,6 +76,7 @@ protected:
nsCOMPtr<nsILoadGroup> mLoadGroup;
nsCString mContentType;
nsCString mContentCharset;
nsCString mContentTypeHint;
PRInt32 mContentLength;
nsCOMPtr<nsISupports> mOwner;
PRUint32 mListFormat;

View File

@ -586,28 +586,35 @@ nsresult
nsHttpChannel::CallOnStartRequest()
{
if (mResponseHead && mResponseHead->ContentType().IsEmpty()) {
// Uh-oh. We had better find out what type we are!
if (!mContentTypeHint.IsEmpty())
mResponseHead->SetContentType(mContentTypeHint);
else {
// Uh-oh. We had better find out what type we are!
// XXX This does not work with content-encodings... but
// neither does applying the conversion from the URILoader
// XXX This does not work with content-encodings... but
// neither does applying the conversion from the URILoader
nsCOMPtr<nsIStreamConverterService> serv;
nsresult rv = gHttpHandler->
nsCOMPtr<nsIStreamConverterService> serv;
nsresult rv = gHttpHandler->
GetStreamConverterService(getter_AddRefs(serv));
// If we failed, we just fall through to the "normal" case
if (NS_SUCCEEDED(rv)) {
NS_ConvertASCIItoUCS2 from(UNKNOWN_CONTENT_TYPE);
nsCOMPtr<nsIStreamListener> converter;
rv = serv->AsyncConvertData(from.get(),
NS_LITERAL_STRING("*/*").get(),
mListener,
mListenerContext,
getter_AddRefs(converter));
// If we failed, we just fall through to the "normal" case
if (NS_SUCCEEDED(rv)) {
mListener = converter;
NS_ConvertASCIItoUCS2 from(UNKNOWN_CONTENT_TYPE);
nsCOMPtr<nsIStreamListener> converter;
rv = serv->AsyncConvertData(from.get(),
NS_LITERAL_STRING("*/*").get(),
mListener,
mListenerContext,
getter_AddRefs(converter));
if (NS_SUCCEEDED(rv)) {
mListener = converter;
}
}
}
}
if (mResponseHead && mResponseHead->ContentCharset().IsEmpty())
mResponseHead->SetContentCharset(mContentCharsetHint);
LOG((" calling mListener->OnStartRequest\n"));
nsresult rv = mListener->OnStartRequest(this, mListenerContext);
@ -2562,17 +2569,24 @@ nsHttpChannel::GetContentType(nsACString &value)
NS_IMETHODIMP
nsHttpChannel::SetContentType(const nsACString &value)
{
if (!mResponseHead)
return NS_ERROR_NOT_AVAILABLE;
if (mIsPending) {
if (!mResponseHead)
return NS_ERROR_NOT_AVAILABLE;
nsCAutoString contentTypeBuf, charsetBuf;
NS_ParseContentType(value, contentTypeBuf, charsetBuf);
nsCAutoString contentTypeBuf, charsetBuf;
NS_ParseContentType(value, contentTypeBuf, charsetBuf);
mResponseHead->SetContentType(contentTypeBuf);
mResponseHead->SetContentType(contentTypeBuf);
// take care not to stomp on an existing charset
if (!charsetBuf.IsEmpty())
mResponseHead->SetContentCharset(charsetBuf);
// take care not to stomp on an existing charset
if (!charsetBuf.IsEmpty())
mResponseHead->SetContentCharset(charsetBuf);
} else {
// We are being given a content-type hint.
nsCAutoString charsetBuf;
NS_ParseContentType(value, mContentTypeHint, mContentCharsetHint);
}
return NS_OK;
}
@ -2589,10 +2603,15 @@ nsHttpChannel::GetContentCharset(nsACString &value)
NS_IMETHODIMP
nsHttpChannel::SetContentCharset(const nsACString &value)
{
if (!mResponseHead)
return NS_ERROR_NOT_AVAILABLE;
if (mIsPending) {
if (!mResponseHead)
return NS_ERROR_NOT_AVAILABLE;
mResponseHead->SetContentCharset(value);
mResponseHead->SetContentCharset(value);
} else {
// Charset hint
mContentCharsetHint = value;
}
return NS_OK;
}

View File

@ -190,6 +190,9 @@ private:
PRUint32 mLogicalOffset;
PRUint8 mCaps;
nsCString mContentTypeHint;
nsCString mContentCharsetHint;
// cache specific data
nsCOMPtr<nsICacheEntryDescriptor> mCacheEntry;
nsCOMPtr<nsIInputStreamPump> mCachePump;

View File

@ -507,6 +507,9 @@ nsJARChannel::GetContentType(nsACString &result)
NS_IMETHODIMP
nsJARChannel::SetContentType(const nsACString &aContentType)
{
// If someone gives us a type hint we should just use that type instead of
// doing our guessing. So we don't care when this is being called.
// mContentCharset is unchanged if not parsed
NS_ParseContentType(aContentType, mContentType, mContentCharset);
return NS_OK;
@ -515,6 +518,8 @@ nsJARChannel::SetContentType(const nsACString &aContentType)
NS_IMETHODIMP
nsJARChannel::GetContentCharset(nsACString &aContentCharset)
{
// If someone gives us a charset hint we should just use that charset.
// So we don't care when this is being called.
aContentCharset = mContentCharset;
return NS_OK;
}

View File

@ -1,4 +1,4 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
@ -32,7 +32,9 @@
#include "nsNetUtil.h"
// nsViewSourceChannel methods
nsViewSourceChannel::nsViewSourceChannel() : mIsDocument(PR_FALSE)
nsViewSourceChannel::nsViewSourceChannel() :
mIsDocument(PR_FALSE),
mOpened(PR_FALSE)
{
}
@ -50,15 +52,15 @@ NS_IMPL_THREADSAFE_RELEASE(nsViewSourceChannel)
This seems like a better approach than writing out the whole QI by hand.
*/
NS_INTERFACE_MAP_BEGIN(nsViewSourceChannel)
NS_INTERFACE_MAP_ENTRY(nsIViewSourceChannel)
NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIHttpChannel, mHttpChannel)
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsICachingChannel, mCachingChannel)
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIUploadChannel, mUploadChannel)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIRequest, nsIViewSourceChannel)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIChannel, nsIViewSourceChannel)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIViewSourceChannel)
NS_INTERFACE_MAP_ENTRY(nsIViewSourceChannel)
NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIHttpChannel, mHttpChannel)
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsICachingChannel, mCachingChannel)
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIUploadChannel, mUploadChannel)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIRequest, nsIViewSourceChannel)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIChannel, nsIViewSourceChannel)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIViewSourceChannel)
NS_INTERFACE_MAP_END_THREADSAFE
nsresult
@ -194,7 +196,12 @@ nsViewSourceChannel::Open(nsIInputStream **_retval)
{
NS_ENSURE_TRUE(mChannel, NS_ERROR_FAILURE);
return mChannel->Open(_retval);
nsresult rv = mChannel->Open(_retval);
if (NS_SUCCEEDED(rv)) {
mOpened = PR_TRUE;
}
return rv;
}
NS_IMETHODIMP
@ -223,6 +230,10 @@ nsViewSourceChannel::AsyncOpen(nsIStreamListener *aListener, nsISupports *ctxt)
this),
nsnull, rv);
if (NS_SUCCEEDED(rv)) {
mOpened = PR_TRUE;
}
return rv;
}
@ -330,6 +341,11 @@ nsViewSourceChannel::SetContentType(const nsACString &aContentType)
// content type, such as, text/html and everything is kosher from
// then on.
if (!mOpened) {
// We do not take hints
return NS_ERROR_NOT_AVAILABLE;
}
mContentType = aContentType;
return NS_OK;
}
@ -434,12 +450,12 @@ nsViewSourceChannel::GetOriginalContentType(nsACString &aContentType)
NS_IMETHODIMP
nsViewSourceChannel::SetOriginalContentType(const nsACString &aContentType)
{
NS_ENSURE_TRUE(mChannel, NS_ERROR_FAILURE);
NS_ENSURE_TRUE(mChannel, NS_ERROR_FAILURE);
// clear our cached content-type value
mContentType.Truncate();
// clear our cached content-type value
mContentType.Truncate();
return mChannel->SetContentType(aContentType);
return mChannel->SetContentType(aContentType);
}
// nsIRequestObserver methods

View File

@ -1,4 +1,4 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
@ -88,6 +88,7 @@ protected:
nsCOMPtr<nsIURI> mOriginalURI;
nsCString mContentType;
PRBool mIsDocument; // keeps track of the LOAD_DOCUMENT_URI flag
PRBool mOpened;
};
#endif /* nsViewSourceChannel_h___ */

View File

@ -501,65 +501,42 @@ nsBinHexDecoder::OnStartRequest(nsIRequest* request, nsISupports *aCtxt)
return rv;
}
// Given the current request and the fileName we discovered inside the bin hex decoding,
// figure out the content type and set it on the channel associated with the request.
nsresult nsBinHexDecoder::SetContentType(nsIRequest * aRequest, const char * fileName)
// Given the fileName we discovered inside the bin hex decoding, figure out the
// content type and set it on the channel associated with the request. If the
// filename tells us nothing useful, just report an unknown type and let the
// unknown decoder handle things.
nsresult nsBinHexDecoder::SetContentType(nsIRequest* aRequest,
const char * fileName)
{
nsresult rv = NS_OK;
nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
if (!channel)
{
NS_WARNING("QI failed");
return NS_ERROR_FAILURE;
if (!fileName || !*fileName) {
// Nothing to do here.
return NS_OK;
}
nsCOMPtr<nsIMIMEService> mimeService (do_GetService("@mozilla.org/mime;1", &rv));
nsresult rv;
nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest, &rv));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIMIMEService> mimeService(do_GetService("@mozilla.org/mime;1", &rv));
NS_ENSURE_SUCCESS(rv, rv);
nsXPIDLCString contentType;
if (fileName)
{
// extract the extension from fileName and look it up.
const char * fileExt = PL_strrchr(fileName, '.');
if (fileExt)
mimeService->GetTypeFromExtension(fileExt, getter_Copies(contentType));
mContentType = contentType;
// extract the extension from fileName and look it up.
const char * fileExt = strrchr(fileName, '.');
if (!fileExt) {
return NS_OK;
}
if (mContentType.IsEmpty())
{
// get the url for the channel.....
nsCOMPtr<nsIURI> uri;
channel->GetURI(getter_AddRefs(uri));
if (uri)
{
nsCOMPtr<nsIURL> url = do_QueryInterface(uri);
if (url)
{
nsCAutoString fileExt;
rv = url->GetFileExtension(fileExt);
if (NS_SUCCEEDED(rv) && !fileExt.IsEmpty())
{
rv = mimeService->GetTypeFromExtension(fileExt.get(), getter_Copies(contentType));
if (NS_SUCCEEDED(rv) && *(contentType.get()))
mContentType = contentType;
}
}
}
} // if the content type is empty
mimeService->GetTypeFromExtension(fileExt, getter_Copies(contentType));
// if we STILL don't have a content type....say the content type is unknown...
// AND to avoid a recursive loop, if after extracting the data fork, we didn't get a valid
// content type and still think it's mac binhex, then reset to unknown.
if (mContentType.IsEmpty() || mContentType.Equals("application/mac-binhex40"))
{
mContentType = NS_LITERAL_CSTRING(UNKNOWN_CONTENT_TYPE);
// Only set the type if it's not empty and, to prevent recursive loops, not the binhex type
if (!contentType.IsEmpty() && !contentType.Equals(APPLICATION_BINHEX)) {
channel->SetContentType(contentType);
} else {
channel->SetContentType(NS_LITERAL_CSTRING(UNKNOWN_CONTENT_TYPE));
}
// now set the content type on the channel.
channel->SetContentType(mContentType);
return NS_OK;
}

View File

@ -117,7 +117,6 @@ protected:
nsresult SetContentType(nsIRequest * aRequest, const char * fileName);
protected:
nsCString mContentType;
nsCOMPtr<nsIStreamListener> mNextListener;
// the input and output streams form a pipe...they need to be passed around together..