forked from mirrors/gecko-dev
Bug 1771423 - Set Content-Type to an empty string for an blob with no type. r=kershaw,smaug,Gijs
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. Differential Revision: https://phabricator.services.mozilla.com/D147481
This commit is contained in:
parent
680803f101
commit
d349734f89
10 changed files with 55 additions and 70 deletions
|
|
@ -1057,13 +1057,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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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; });
|
||||
|
||||
|
|
|
|||
|
|
@ -1889,7 +1889,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));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -292,8 +292,6 @@ class nsBaseChannel
|
|||
nsCOMPtr<nsISupports> mOwner;
|
||||
nsCOMPtr<nsITransportSecurityInfo> 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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -471,7 +471,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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,54 +0,0 @@
|
|||
[scheme-blob.sub.any.worker.html]
|
||||
expected:
|
||||
if (os == "android") and fission: [OK, TIMEOUT]
|
||||
[Fetching URL.createObjectURL(empty_blob) is OK]
|
||||
expected: FAIL
|
||||
|
||||
[Fetching URL.createObjectURL(empty_type_blob) is OK]
|
||||
expected: FAIL
|
||||
|
||||
[Fetching URL.createObjectURL(empty_data_blob) is OK]
|
||||
expected: FAIL
|
||||
|
||||
[Blob content is not sniffed for a content type [image/png\]]
|
||||
expected: FAIL
|
||||
|
||||
[Blob content is not sniffed for a content type [text/xml\]]
|
||||
expected: FAIL
|
||||
|
||||
[Set content type to the empty string for slice with invalid content type]
|
||||
expected: FAIL
|
||||
|
||||
[Set content type to the empty string for slice with no content type ]
|
||||
expected: FAIL
|
||||
|
||||
[Blob.slice should not sniff the content for a content type]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[scheme-blob.sub.any.html]
|
||||
expected:
|
||||
if (os == "android") and fission: [OK, TIMEOUT]
|
||||
[Fetching URL.createObjectURL(empty_blob) is OK]
|
||||
expected: FAIL
|
||||
|
||||
[Fetching URL.createObjectURL(empty_type_blob) is OK]
|
||||
expected: FAIL
|
||||
|
||||
[Fetching URL.createObjectURL(empty_data_blob) is OK]
|
||||
expected: FAIL
|
||||
|
||||
[Blob content is not sniffed for a content type [image/png\]]
|
||||
expected: FAIL
|
||||
|
||||
[Blob content is not sniffed for a content type [text/xml\]]
|
||||
expected: FAIL
|
||||
|
||||
[Set content type to the empty string for slice with invalid content type]
|
||||
expected: FAIL
|
||||
|
||||
[Set content type to the empty string for slice with no content type ]
|
||||
expected: FAIL
|
||||
|
||||
[Blob.slice should not sniff the content for a content type]
|
||||
expected: FAIL
|
||||
|
|
@ -273,7 +273,9 @@ nsresult nsDocumentOpenInfo::DispatchContent(nsIRequest* request) {
|
|||
// Check if this is a PDF which should be opened internally. We also handle
|
||||
// octet-streams that look like they might be PDFs based on their extension.
|
||||
bool isPDF = mContentType.LowerCaseEqualsASCII(APPLICATION_PDF);
|
||||
if (!isPDF && mContentType.LowerCaseEqualsASCII(APPLICATION_OCTET_STREAM)) {
|
||||
if (!isPDF &&
|
||||
(mContentType.LowerCaseEqualsASCII(APPLICATION_OCTET_STREAM) ||
|
||||
mContentType.IsEmpty())) {
|
||||
nsAutoString flname;
|
||||
aChannel->GetContentDispositionFilename(flname);
|
||||
isPDF = StringEndsWith(flname, u".pdf"_ns);
|
||||
|
|
@ -475,7 +477,7 @@ nsresult nsDocumentOpenInfo::DispatchContent(nsIRequest* request) {
|
|||
request->SetLoadFlags(loadFlags | nsIChannel::LOAD_RETARGETED_DOCUMENT_URI |
|
||||
nsIChannel::LOAD_TARGETED);
|
||||
|
||||
if (isGuessFromExt) {
|
||||
if (isGuessFromExt || mContentType.IsEmpty()) {
|
||||
mContentType = APPLICATION_GUESS_FROM_EXT;
|
||||
aChannel->SetContentType(nsLiteralCString(APPLICATION_GUESS_FROM_EXT));
|
||||
}
|
||||
|
|
@ -568,7 +570,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) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue