Enhance PDF handling by introducing DISPOSITION_FORCE_INLINE and updating content disposition logic

This commit is contained in:
ownedbywuigi 2026-03-31 11:46:59 +01:00
commit 257ddfa48d
6 changed files with 63 additions and 7 deletions

View file

@ -871,6 +871,11 @@ PdfStreamConverter.prototype = {
aRequest.setResponseHeader("Refresh", "", false);
}
// The document will be loaded via the stream converter as html, but we
// may have come here via a download/attachment path. Force inline so we
// don't get redirected back to the external helper service.
aRequest.contentDisposition = Ci.nsIChannel.DISPOSITION_FORCE_INLINE;
// Creating storage for PDF data
var contentLength = aRequest.contentLength;
this.dataListener = new PdfDataListener(contentLength);

View file

@ -293,10 +293,14 @@ interface nsIChannel : nsIRequest
* if available and if applicable. This allows determining inline versus
* attachment.
*
* Setting contentDisposition provides a hint to the channel about the
* disposition. If a normal Content-Disposition header is present its
* value will always be used. If it is missing the hinted value will
* be used if set.
* Setting contentDisposition provides a hint to the channel about the
* disposition. If the hint is DISPOSITION_ATTACHMENT and a normal
* Content-Disposition header is present, the hinted value will always be
* used. If the hint is DISPOSITION_FORCE_INLINE then the disposition is
* inline and the header is not used. The value from Content-Disposition
* header is only used when the hinted value is not DISPOSITION_INLINE or
* DISPOSITION_FORCE_INLINE.
* If the header is missing the hinted value will be used if set.
*
* Implementations should throw NS_ERROR_NOT_AVAILABLE if the header either
* doesn't exist for this type of channel or is empty, and return
@ -305,6 +309,7 @@ interface nsIChannel : nsIRequest
attribute unsigned long contentDisposition;
const unsigned long DISPOSITION_INLINE = 0;
const unsigned long DISPOSITION_ATTACHMENT = 1;
const unsigned long DISPOSITION_FORCE_INLINE = 2;
/**
* Access to the filename portion of the Content-Disposition header if

View file

@ -511,6 +511,14 @@ HttpBaseChannel::SetContentCharset(const nsACString& aContentCharset)
NS_IMETHODIMP
HttpBaseChannel::GetContentDisposition(uint32_t *aContentDisposition)
{
// DISPOSITION_FORCE_INLINE is used to explicitly set inline, used by
// the pdf reader when loading an attachment pdf without downloading it.
if (mContentDispositionHint == nsIChannel::DISPOSITION_ATTACHMENT ||
mContentDispositionHint == nsIChannel::DISPOSITION_FORCE_INLINE) {
*aContentDisposition = mContentDispositionHint;
return NS_OK;
}
nsresult rv;
nsCString header;

View file

@ -41,6 +41,10 @@
#include "nsCExternalHandlerService.h" // contains contractids for the helper app service
#include "nsIMIMEHeaderParam.h"
#include "nsIMIMEInfo.h"
#include "nsIMIMEService.h"
#include "nsILoadInfo.h"
#include "nsIContentPolicy.h"
#include "nsNetCID.h"
#include "nsMimeTypes.h"
@ -389,6 +393,36 @@ nsresult nsDocumentOpenInfo::DispatchContent(nsIRequest *request, nsISupports *
forceExternalHandling = true;
}
// For a PDF, check if it will be handled internally. If so, don't force
// external handling for top-level document loads.
if (forceExternalHandling &&
mContentType.LowerCaseEqualsASCII(APPLICATION_PDF)) {
nsCOMPtr<nsILoadInfo> loadInfo;
aChannel->GetLoadInfo(getter_AddRefs(loadInfo));
if (loadInfo &&
loadInfo->GetExternalContentPolicyType() ==
nsIContentPolicy::TYPE_DOCUMENT) {
nsCOMPtr<nsIMIMEInfo> mimeInfo;
nsCOMPtr<nsIMIMEService> mimeSvc(
do_GetService(NS_MIMESERVICE_CONTRACTID));
if (mimeSvc) {
mimeSvc->GetFromTypeAndExtension(nsLiteralCString(APPLICATION_PDF),
EmptyCString(),
getter_AddRefs(mimeInfo));
}
if (mimeInfo) {
int32_t action = nsIHandlerInfo::saveToDisk;
mimeInfo->GetPreferredAction(&action);
bool alwaysAsk = true;
mimeInfo->GetAlwaysAskBeforeHandling(&alwaysAsk);
forceExternalHandling =
alwaysAsk || action != nsIHandlerInfo::handleInternally;
}
}
}
LOG((" forceExternalHandling: %s", forceExternalHandling ? "yes" : "no"));
// The type or data the contentListener wants.

View file

@ -104,7 +104,9 @@ NS_IMETHODIMP RemoteHandlerApp::LaunchWithURI(nsIURI *aURI, nsIInterfaceRequesto
NS_IMPL_ISUPPORTS(RemoteHandlerApp, nsIHandlerApp)
static inline void CopyHanderInfoTonsIHandlerInfo(HandlerInfo info, nsIHandlerInfo* aHandlerInfo)
static inline void
CopyHandlerInfoTonsIHandlerInfo(const HandlerInfo& info,
nsIHandlerInfo* aHandlerInfo)
{
HandlerApp preferredApplicationHandler = info.preferredApplicationHandler();
nsCOMPtr<nsIHandlerApp> preferredApp(new RemoteHandlerApp(preferredApplicationHandler));
@ -112,6 +114,8 @@ static inline void CopyHanderInfoTonsIHandlerInfo(HandlerInfo info, nsIHandlerIn
nsCOMPtr<nsIMutableArray> possibleHandlers;
aHandlerInfo->GetPossibleApplicationHandlers(getter_AddRefs(possibleHandlers));
possibleHandlers->AppendElement(preferredApp, false);
aHandlerInfo->SetPreferredAction(info.preferredAction());
aHandlerInfo->SetAlwaysAskBeforeHandling(info.alwaysAskBeforeHandling());
}
ContentHandlerService::~ContentHandlerService()
{
@ -127,7 +131,7 @@ NS_IMETHODIMP ContentHandlerService::FillHandlerInfo(nsIHandlerInfo *aHandlerInf
HandlerInfo info;
nsIHandlerInfoToHandlerInfo(aHandlerInfo, &info);
mHandlerServiceChild->SendFillHandlerInfo(info, nsCString(aOverrideType), &info);
CopyHanderInfoTonsIHandlerInfo(info, aHandlerInfo);
CopyHandlerInfoTonsIHandlerInfo(info, aHandlerInfo);
return NS_OK;
}

View file

@ -19,7 +19,7 @@ struct HandlerInfo {
bool alwaysAskBeforeHandling;
HandlerApp preferredApplicationHandler;
HandlerApp[] possibleApplicationHandlers;
long preferredAction;
int32_t preferredAction;
};
sync protocol PHandlerService