Bug 1771423 - Set Content-Type to an empty string for an empty blob with no type. r=kershaw,smaug,necko-reviewers

Set the Content-Type to an empty string for an blob when the type was not
given. Ensure that the channel Content-Type is not overriden in the case
that it was previously set and the blob type is not valid.

Depends on D147568

Differential Revision: https://phabricator.services.mozilla.com/D147481
This commit is contained in:
Dan Robertson 2022-08-15 13:52:12 +00:00
parent c1aa98125a
commit 27907e8f9a
9 changed files with 51 additions and 14 deletions

View File

@ -1025,13 +1025,13 @@ FetchDriver::OnStartRequest(nsIRequest* aRequest) {
if (NS_SUCCEEDED(rv) && !contentCharset.IsEmpty()) {
contentType += ";charset="_ns + contentCharset;
}
IgnoredErrorResult result;
response->Headers()->Append("Content-Type"_ns, contentType, result);
MOZ_ASSERT(!result.Failed());
}
if (contentLength > 0) {
IgnoredErrorResult result;
response->Headers()->Append("Content-Type"_ns, contentType, result);
MOZ_ASSERT(!result.Failed());
if (contentLength >= 0) {
nsAutoCString contentLenStr;
contentLenStr.AppendInt(contentLength);

View File

@ -26,6 +26,18 @@ BlobURLChannel::BlobURLChannel(nsIURI* aURI, nsILoadInfo* aLoadInfo)
BlobURLChannel::~BlobURLChannel() = default;
NS_IMETHODIMP
BlobURLChannel::SetContentType(const nsACString& aContentType) {
// If the blob type is empty, set the content type of the channel to the
// empty string.
if (aContentType.IsEmpty()) {
mContentType.Truncate();
return NS_OK;
}
return nsBaseChannel::SetContentType(aContentType);
}
nsresult BlobURLChannel::OpenContentStream(bool aAsync,
nsIInputStream** aResult,
nsIChannel** aChannel) {

View File

@ -21,6 +21,8 @@ class BlobURLChannel final : public nsBaseChannel {
public:
BlobURLChannel(nsIURI* aURI, nsILoadInfo* aLoadInfo);
NS_IMETHOD SetContentType(const nsACString& aContentType) override;
private:
~BlobURLChannel() override;

View File

@ -13,6 +13,7 @@
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/IPCBlobUtils.h"
#include "nsStreamUtils.h"
#include "nsMimeTypes.h"
namespace mozilla::dom {
@ -461,9 +462,21 @@ nsresult BlobURLInputStream::StoreBlobImplStream(
already_AddRefed<BlobImpl> aBlobImpl, const MutexAutoLock& aProofOfLock) {
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread");
const RefPtr<BlobImpl> blobImpl = aBlobImpl;
nsAutoString contentType;
blobImpl->GetType(contentType);
mChannel->SetContentType(NS_ConvertUTF16toUTF8(contentType));
nsAutoString blobContentType;
nsAutoCString channelContentType;
blobImpl->GetType(blobContentType);
mChannel->GetContentType(channelContentType);
// A empty content type is the correct channel content type in the case of a
// fetch of a blob where the type was not set. It is invalid in others cases
// such as a XHR (See https://xhr.spec.whatwg.org/#response-mime-type). The
// XMLHttpRequestMainThread will set the channel content type to the correct
// fallback value before this point, so we need to be careful to only override
// it when the blob type is valid.
if (!blobContentType.IsEmpty() ||
channelContentType.EqualsLiteral(UNKNOWN_CONTENT_TYPE)) {
mChannel->SetContentType(NS_ConvertUTF16toUTF8(blobContentType));
}
auto cleanupOnExit = MakeScopeExit([&] { mChannel = nullptr; });

View File

@ -1888,7 +1888,7 @@ XMLHttpRequestMainThread::OnStartRequest(nsIRequest* request) {
// Fallback to 'application/octet-stream'
nsAutoCString type;
channel->GetContentType(type);
if (type.EqualsLiteral(UNKNOWN_CONTENT_TYPE)) {
if (type.IsEmpty() || type.EqualsLiteral(UNKNOWN_CONTENT_TYPE)) {
channel->SetContentType(nsLiteralCString(APPLICATION_OCTET_STREAM));
}

View File

@ -292,8 +292,6 @@ class nsBaseChannel
nsCOMPtr<nsISupports> mOwner;
nsCOMPtr<nsISupports> mSecurityInfo;
nsCOMPtr<nsIChannel> mRedirectChannel;
nsCString mContentType;
nsCString mContentCharset;
uint32_t mLoadFlags{LOAD_NORMAL};
bool mQueriedProgressSink{true};
bool mSynthProgressEvents{false};
@ -303,6 +301,8 @@ class nsBaseChannel
uint32_t mRedirectFlags{0};
protected:
nsCString mContentType;
nsCString mContentCharset;
nsCOMPtr<nsIURI> mURI;
nsCOMPtr<nsILoadGroup> mLoadGroup;
nsCOMPtr<nsILoadInfo> mLoadInfo;

View File

@ -246,7 +246,8 @@ class ParentProcessDocumentOpenInfo final : public nsDocumentOpenInfo,
// The one exception is nsUnknownDecoder, which works in the parent
// (and we need to know what the content type is before we can
// decide if it will be handled in the parent), so we run that here.
if (mContentType.LowerCaseEqualsASCII(UNKNOWN_CONTENT_TYPE)) {
if (mContentType.LowerCaseEqualsASCII(UNKNOWN_CONTENT_TYPE) ||
mContentType.IsEmpty()) {
return nsDocumentOpenInfo::TryStreamConversion(aChannel);
}

View File

@ -457,7 +457,8 @@ nsViewSourceChannel::GetContentType(nsACString& aContentType) {
// content decoder will then kick in automatically, and it
// will call our SetOriginalContentType method instead of our
// SetContentType method to set the type it determines.
if (!contentType.EqualsLiteral(UNKNOWN_CONTENT_TYPE)) {
if (!contentType.EqualsLiteral(UNKNOWN_CONTENT_TYPE) &&
!contentType.IsEmpty()) {
contentType = VIEWSOURCE_CONTENT_TYPE;
}

View File

@ -568,7 +568,15 @@ nsresult nsDocumentOpenInfo::ConvertData(nsIRequest* request,
nsresult nsDocumentOpenInfo::TryStreamConversion(nsIChannel* aChannel) {
constexpr auto anyType = "*/*"_ns;
nsresult rv = ConvertData(aChannel, m_contentListener, mContentType, anyType);
// A empty content type should be treated like the unknown content type.
nsCString srcContentType(mContentType);
if (srcContentType.IsEmpty()) {
srcContentType.AssignLiteral(UNKNOWN_CONTENT_TYPE);
}
nsresult rv =
ConvertData(aChannel, m_contentListener, srcContentType, anyType);
if (NS_FAILED(rv)) {
m_targetStreamListener = nullptr;
} else if (m_targetStreamListener) {