From 33e6d54872c3a6165029309b12a8f3f18cfc7082 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Sat, 30 Apr 2022 01:24:47 +0000 Subject: [PATCH] Bug 1757604 - Make content-type on JAR channels behave the same as HTTP channels. r=Gijs That is, treat it as a hint if called before open, and as an override if called after. Override the hint on open. This is a less invasive change that is green on try and also fixes the issue. Differential Revision: https://phabricator.services.mozilla.com/D145098 --- modules/libjar/nsJARChannel.cpp | 83 ++++++++++--------- modules/libjar/nsJARChannel.h | 11 ++- .../tests/browser/browser_xpcom_graph_wait.js | 1 + 3 files changed, 55 insertions(+), 40 deletions(-) diff --git a/modules/libjar/nsJARChannel.cpp b/modules/libjar/nsJARChannel.cpp index 9cfd931a5afe..6506ee33bd90 100644 --- a/modules/libjar/nsJARChannel.cpp +++ b/modules/libjar/nsJARChannel.cpp @@ -391,7 +391,7 @@ nsresult nsJARChannel::OpenLocalFile() { if (mLoadGroup) { mLoadGroup->AddRequest(this, nullptr); } - mOpened = true; + SetOpened(); if (mPreCachedJarReader || !mEnableOMT) { RefPtr input; @@ -719,53 +719,53 @@ nsJARChannel::GetSecurityInfo(nsISupports** aSecurityInfo) { return NS_OK; } +bool nsJARChannel::GetContentTypeGuess(nsACString& aResult) const { + const char *ext = nullptr, *fileName = mJarEntry.get(); + int32_t len = mJarEntry.Length(); + + // check if we're displaying a directory + // mJarEntry will be empty if we're trying to display + // the topmost directory in a zip, e.g. jar:foo.zip!/ + if (ENTRY_IS_DIRECTORY(mJarEntry)) { + aResult.AssignLiteral(APPLICATION_HTTP_INDEX_FORMAT); + return true; + } + + // Not a directory, take a guess by its extension + for (int32_t i = len - 1; i >= 0; i--) { + if (fileName[i] == '.') { + ext = &fileName[i + 1]; + break; + } + } + if (!ext) { + return false; + } + nsIMIMEService* mimeServ = gJarHandler->MimeService(); + if (!mimeServ) { + return false; + } + mimeServ->GetTypeFromExtension(nsDependentCString(ext), aResult); + return !aResult.IsEmpty(); +} + NS_IMETHODIMP -nsJARChannel::GetContentType(nsACString& result) { +nsJARChannel::GetContentType(nsACString& aResult) { // If the Jar file has not been open yet, // We return application/x-unknown-content-type if (!mOpened) { - result.AssignLiteral(UNKNOWN_CONTENT_TYPE); + aResult.AssignLiteral(UNKNOWN_CONTENT_TYPE); return NS_OK; } - if (mContentType.IsEmpty()) { - // - // generate content type and set it - // - const char *ext = nullptr, *fileName = mJarEntry.get(); - int32_t len = mJarEntry.Length(); - - // check if we're displaying a directory - // mJarEntry will be empty if we're trying to display - // the topmost directory in a zip, e.g. jar:foo.zip!/ - if (ENTRY_IS_DIRECTORY(mJarEntry)) { - mContentType.AssignLiteral(APPLICATION_HTTP_INDEX_FORMAT); - } else { - // not a directory, take a guess by its extension - for (int32_t i = len - 1; i >= 0; i--) { - if (fileName[i] == '.') { - ext = &fileName[i + 1]; - break; - } - } - if (ext) { - nsIMIMEService* mimeServ = gJarHandler->MimeService(); - if (mimeServ) - mimeServ->GetTypeFromExtension(nsDependentCString(ext), mContentType); - } - if (mContentType.IsEmpty()) - mContentType.AssignLiteral(UNKNOWN_CONTENT_TYPE); - } - } - result = mContentType; + aResult = mContentType; return NS_OK; } 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. - + // We behave like HTTP channels (treat this as a hint if called before open, + // and override the charset if called after open). // mContentCharset is unchanged if not parsed NS_ParseResponseContentType(aContentType, mContentType, mContentCharset); return NS_OK; @@ -1035,11 +1035,20 @@ nsJARChannel::Open(nsIInputStream** aStream) { if (NS_FAILED(rv)) return rv; input.forget(aStream); - mOpened = true; + SetOpened(); return NS_OK; } +void nsJARChannel::SetOpened() { + MOZ_ASSERT(!mOpened, "Opening channel twice?"); + mOpened = true; + // Compute the content type now. + if (!GetContentTypeGuess(mContentType)) { + mContentType.Assign(UNKNOWN_CONTENT_TYPE); + } +} + NS_IMETHODIMP nsJARChannel::AsyncOpen(nsIStreamListener* aListener) { LOG(("nsJARChannel::AsyncOpen [this=%p]\n", this)); diff --git a/modules/libjar/nsJARChannel.h b/modules/libjar/nsJARChannel.h index 7480abd8429d..59fcd4ee7c32 100644 --- a/modules/libjar/nsJARChannel.h +++ b/modules/libjar/nsJARChannel.h @@ -66,10 +66,15 @@ class nsJARChannel final : public nsIJARChannel, void NotifyError(nsresult aError); void FireOnProgress(uint64_t aProgress); + // Returns false if we don't know the content type of this channel, in which + // case we should use the content-type hint. + bool GetContentTypeGuess(nsACString&) const; + void SetOpened(); + nsCString mSpec; bool mOpened; - Atomic mCanceled; + mozilla::Atomic mCanceled; bool mOnDataCalled = false; RefPtr mJarHandler; @@ -86,14 +91,14 @@ class nsJARChannel final : public nsIJARChannel, nsCString mContentCharset; int64_t mContentLength; uint32_t mLoadFlags; - Atomic mStatus; + mozilla::Atomic mStatus; bool mIsPending; // the AsyncOpen is in progress. bool mEnableOMT; // |Cancel()|, |Suspend()|, and |Resume()| might be called during AsyncOpen. struct { bool isCanceled; - Atomic suspendCount; + mozilla::Atomic suspendCount; } mPendingEvent; nsCOMPtr mPump; diff --git a/toolkit/components/backgroundtasks/tests/browser/browser_xpcom_graph_wait.js b/toolkit/components/backgroundtasks/tests/browser/browser_xpcom_graph_wait.js index f3d657e3973d..32f81c4187ba 100644 --- a/toolkit/components/backgroundtasks/tests/browser/browser_xpcom_graph_wait.js +++ b/toolkit/components/backgroundtasks/tests/browser/browser_xpcom_graph_wait.js @@ -100,6 +100,7 @@ const backgroundtaskPhases = { }, "@mozilla.org/xpcom/debug;1", "@mozilla.org/xre/app-info;1", + "@mozilla.org/mime;1", ], }, },