[api-minor] Support the Content-Disposition filename in the Firefox PDF Viewer (bug 1694556, PR 9379 follow-up)
As can be seen [in the mozilla-central code](https://searchfox.org/mozilla-central/rev/a6db3bd67367aa9ddd9505690cab09b47e65a762/toolkit/components/pdfjs/content/PdfStreamConverter.jsm#1222-1225), we're already getting the Content-Disposition filename. However, that data isn't passed through to the viewer nor to the `PDFDataTransportStream`-implementation, which explains why it's currently being ignored. *Please note:* This will also require a small mozilla-central patch, see https://bugzilla.mozilla.org/show_bug.cgi?id=1694556, to forward the necessary data to the viewer.
This commit is contained in:
parent
061637d3f4
commit
6fd899dc44
@ -334,6 +334,7 @@ function getDocument(src) {
|
|||||||
length: params.length,
|
length: params.length,
|
||||||
initialData: params.initialData,
|
initialData: params.initialData,
|
||||||
progressiveDone: params.progressiveDone,
|
progressiveDone: params.progressiveDone,
|
||||||
|
contentDispositionFilename: params.contentDispositionFilename,
|
||||||
disableRange: params.disableRange,
|
disableRange: params.disableRange,
|
||||||
disableStream: params.disableStream,
|
disableStream: params.disableStream,
|
||||||
},
|
},
|
||||||
@ -401,6 +402,8 @@ function _fetchDocument(worker, source, pdfDataRangeTransport, docId) {
|
|||||||
source.length = pdfDataRangeTransport.length;
|
source.length = pdfDataRangeTransport.length;
|
||||||
source.initialData = pdfDataRangeTransport.initialData;
|
source.initialData = pdfDataRangeTransport.initialData;
|
||||||
source.progressiveDone = pdfDataRangeTransport.progressiveDone;
|
source.progressiveDone = pdfDataRangeTransport.progressiveDone;
|
||||||
|
source.contentDispositionFilename =
|
||||||
|
pdfDataRangeTransport.contentDispositionFilename;
|
||||||
}
|
}
|
||||||
return worker.messageHandler
|
return worker.messageHandler
|
||||||
.sendWithPromise("GetDocRequest", {
|
.sendWithPromise("GetDocRequest", {
|
||||||
@ -554,11 +557,18 @@ class PDFDataRangeTransport {
|
|||||||
* @param {number} length
|
* @param {number} length
|
||||||
* @param {Uint8Array} initialData
|
* @param {Uint8Array} initialData
|
||||||
* @param {boolean} [progressiveDone]
|
* @param {boolean} [progressiveDone]
|
||||||
|
* @param {string} [contentDispositionFilename]
|
||||||
*/
|
*/
|
||||||
constructor(length, initialData, progressiveDone = false) {
|
constructor(
|
||||||
|
length,
|
||||||
|
initialData,
|
||||||
|
progressiveDone = false,
|
||||||
|
contentDispositionFilename = null
|
||||||
|
) {
|
||||||
this.length = length;
|
this.length = length;
|
||||||
this.initialData = initialData;
|
this.initialData = initialData;
|
||||||
this.progressiveDone = progressiveDone;
|
this.progressiveDone = progressiveDone;
|
||||||
|
this.contentDispositionFilename = contentDispositionFilename;
|
||||||
|
|
||||||
this._rangeListeners = [];
|
this._rangeListeners = [];
|
||||||
this._progressListeners = [];
|
this._progressListeners = [];
|
||||||
|
@ -451,6 +451,10 @@ function addLinkAttributes(link, { url, target, rel, enabled = true } = {}) {
|
|||||||
link.rel = typeof rel === "string" ? rel : DEFAULT_LINK_REL;
|
link.rel = typeof rel === "string" ? rel : DEFAULT_LINK_REL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isPdfFile(filename) {
|
||||||
|
return typeof filename === "string" && /\.pdf$/i.test(filename);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the file name from a given URL.
|
* Gets the file name from a given URL.
|
||||||
* @param {string} url
|
* @param {string} url
|
||||||
@ -652,6 +656,7 @@ export {
|
|||||||
DOMSVGFactory,
|
DOMSVGFactory,
|
||||||
getFilenameFromUrl,
|
getFilenameFromUrl,
|
||||||
isFetchSupported,
|
isFetchSupported,
|
||||||
|
isPdfFile,
|
||||||
isValidFetchUrl,
|
isValidFetchUrl,
|
||||||
LinkTarget,
|
LinkTarget,
|
||||||
loadScript,
|
loadScript,
|
||||||
|
@ -19,6 +19,7 @@ import {
|
|||||||
UnexpectedResponseException,
|
UnexpectedResponseException,
|
||||||
} from "../shared/util.js";
|
} from "../shared/util.js";
|
||||||
import { getFilenameFromContentDispositionHeader } from "./content_disposition.js";
|
import { getFilenameFromContentDispositionHeader } from "./content_disposition.js";
|
||||||
|
import { isPdfFile } from "./display_utils.js";
|
||||||
|
|
||||||
function validateRangeRequestCapabilities({
|
function validateRangeRequestCapabilities({
|
||||||
getResponseHeader,
|
getResponseHeader,
|
||||||
@ -70,7 +71,7 @@ function extractFilenameFromHeader(getResponseHeader) {
|
|||||||
filename = decodeURIComponent(filename);
|
filename = decodeURIComponent(filename);
|
||||||
} catch (ex) {}
|
} catch (ex) {}
|
||||||
}
|
}
|
||||||
if (/\.pdf$/i.test(filename)) {
|
if (isPdfFile(filename)) {
|
||||||
return filename;
|
return filename;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -82,11 +83,7 @@ function createResponseStatusError(status, url) {
|
|||||||
return new MissingPDFException('Missing PDF "' + url + '".');
|
return new MissingPDFException('Missing PDF "' + url + '".');
|
||||||
}
|
}
|
||||||
return new UnexpectedResponseException(
|
return new UnexpectedResponseException(
|
||||||
"Unexpected server response (" +
|
`Unexpected server response (${status}) while retrieving PDF "${url}".`,
|
||||||
status +
|
|
||||||
') while retrieving PDF "' +
|
|
||||||
url +
|
|
||||||
'".',
|
|
||||||
status
|
status
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { assert, createPromiseCapability } from "../shared/util.js";
|
import { assert, createPromiseCapability } from "../shared/util.js";
|
||||||
|
import { isPdfFile } from "./display_utils.js";
|
||||||
|
|
||||||
/** @implements {IPDFStream} */
|
/** @implements {IPDFStream} */
|
||||||
class PDFDataTransportStream {
|
class PDFDataTransportStream {
|
||||||
@ -25,6 +26,8 @@ class PDFDataTransportStream {
|
|||||||
|
|
||||||
this._queuedChunks = [];
|
this._queuedChunks = [];
|
||||||
this._progressiveDone = params.progressiveDone || false;
|
this._progressiveDone = params.progressiveDone || false;
|
||||||
|
this._contentDispositionFilename =
|
||||||
|
params.contentDispositionFilename || null;
|
||||||
|
|
||||||
const initialData = params.initialData;
|
const initialData = params.initialData;
|
||||||
if (initialData?.length > 0) {
|
if (initialData?.length > 0) {
|
||||||
@ -125,7 +128,8 @@ class PDFDataTransportStream {
|
|||||||
return new PDFDataTransportStreamReader(
|
return new PDFDataTransportStreamReader(
|
||||||
this,
|
this,
|
||||||
queuedChunks,
|
queuedChunks,
|
||||||
this._progressiveDone
|
this._progressiveDone,
|
||||||
|
this._contentDispositionFilename
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,10 +157,17 @@ class PDFDataTransportStream {
|
|||||||
|
|
||||||
/** @implements {IPDFStreamReader} */
|
/** @implements {IPDFStreamReader} */
|
||||||
class PDFDataTransportStreamReader {
|
class PDFDataTransportStreamReader {
|
||||||
constructor(stream, queuedChunks, progressiveDone = false) {
|
constructor(
|
||||||
|
stream,
|
||||||
|
queuedChunks,
|
||||||
|
progressiveDone = false,
|
||||||
|
contentDispositionFilename = null
|
||||||
|
) {
|
||||||
this._stream = stream;
|
this._stream = stream;
|
||||||
this._done = progressiveDone || false;
|
this._done = progressiveDone || false;
|
||||||
this._filename = null;
|
this._filename = isPdfFile(contentDispositionFilename)
|
||||||
|
? contentDispositionFilename
|
||||||
|
: null;
|
||||||
this._queuedChunks = queuedChunks || [];
|
this._queuedChunks = queuedChunks || [];
|
||||||
this._loaded = 0;
|
this._loaded = 0;
|
||||||
for (const chunk of this._queuedChunks) {
|
for (const chunk of this._queuedChunks) {
|
||||||
|
@ -18,6 +18,7 @@ import {
|
|||||||
addLinkAttributes,
|
addLinkAttributes,
|
||||||
getFilenameFromUrl,
|
getFilenameFromUrl,
|
||||||
isFetchSupported,
|
isFetchSupported,
|
||||||
|
isPdfFile,
|
||||||
isValidFetchUrl,
|
isValidFetchUrl,
|
||||||
LinkTarget,
|
LinkTarget,
|
||||||
loadScript,
|
loadScript,
|
||||||
@ -128,6 +129,7 @@ export {
|
|||||||
// From "./display/display_utils.js":
|
// From "./display/display_utils.js":
|
||||||
addLinkAttributes,
|
addLinkAttributes,
|
||||||
getFilenameFromUrl,
|
getFilenameFromUrl,
|
||||||
|
isPdfFile,
|
||||||
LinkTarget,
|
LinkTarget,
|
||||||
loadScript,
|
loadScript,
|
||||||
PDFDateString,
|
PDFDateString,
|
||||||
|
@ -44,6 +44,7 @@ import {
|
|||||||
getFilenameFromUrl,
|
getFilenameFromUrl,
|
||||||
GlobalWorkerOptions,
|
GlobalWorkerOptions,
|
||||||
InvalidPDFException,
|
InvalidPDFException,
|
||||||
|
isPdfFile,
|
||||||
LinkTarget,
|
LinkTarget,
|
||||||
loadScript,
|
loadScript,
|
||||||
MissingPDFException,
|
MissingPDFException,
|
||||||
@ -727,7 +728,10 @@ const PDFViewerApplication = {
|
|||||||
onOpenWithTransport: (url, length, transport) => {
|
onOpenWithTransport: (url, length, transport) => {
|
||||||
this.open(url, { length, range: transport });
|
this.open(url, { length, range: transport });
|
||||||
},
|
},
|
||||||
onOpenWithData: data => {
|
onOpenWithData: (data, contentDispositionFilename) => {
|
||||||
|
if (isPdfFile(contentDispositionFilename)) {
|
||||||
|
this._contentDispositionFilename = contentDispositionFilename;
|
||||||
|
}
|
||||||
this.open(data);
|
this.open(data);
|
||||||
},
|
},
|
||||||
onOpenWithURL: (url, length, originalUrl) => {
|
onOpenWithURL: (url, length, originalUrl) => {
|
||||||
@ -1744,7 +1748,7 @@ const PDFViewerApplication = {
|
|||||||
}
|
}
|
||||||
this.documentInfo = info;
|
this.documentInfo = info;
|
||||||
this.metadata = metadata;
|
this.metadata = metadata;
|
||||||
this._contentDispositionFilename = contentDispositionFilename;
|
this._contentDispositionFilename ??= contentDispositionFilename;
|
||||||
this._contentLength ??= contentLength; // See `getDownloadInfo`-call above.
|
this._contentLength ??= contentLength; // See `getDownloadInfo`-call above.
|
||||||
|
|
||||||
// Provides some basic debug information
|
// Provides some basic debug information
|
||||||
|
@ -13,8 +13,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { createObjectURL, createValidAbsoluteUrl } from "pdfjs-lib";
|
import { createObjectURL, createValidAbsoluteUrl, isPdfFile } from "pdfjs-lib";
|
||||||
import { PdfFileRegExp } from "./ui_utils.js";
|
|
||||||
import { viewerCompatibilityParams } from "./viewer_compatibility.js";
|
import { viewerCompatibilityParams } from "./viewer_compatibility.js";
|
||||||
|
|
||||||
if (typeof PDFJSDev !== "undefined" && !PDFJSDev.test("CHROME || GENERIC")) {
|
if (typeof PDFJSDev !== "undefined" && !PDFJSDev.test("CHROME || GENERIC")) {
|
||||||
@ -68,10 +67,10 @@ class DownloadManager {
|
|||||||
* @returns {boolean} Indicating if the data was opened.
|
* @returns {boolean} Indicating if the data was opened.
|
||||||
*/
|
*/
|
||||||
openOrDownloadData(element, data, filename) {
|
openOrDownloadData(element, data, filename) {
|
||||||
const isPdfFile = PdfFileRegExp.test(filename);
|
const isPdfData = isPdfFile(filename);
|
||||||
const contentType = isPdfFile ? "application/pdf" : "";
|
const contentType = isPdfData ? "application/pdf" : "";
|
||||||
|
|
||||||
if (isPdfFile && !viewerCompatibilityParams.disableCreateObjectURL) {
|
if (isPdfData && !viewerCompatibilityParams.disableCreateObjectURL) {
|
||||||
let blobUrl = this._openBlobUrls.get(element);
|
let blobUrl = this._openBlobUrls.get(element);
|
||||||
if (!blobUrl) {
|
if (!blobUrl) {
|
||||||
blobUrl = URL.createObjectURL(new Blob([data], { type: contentType }));
|
blobUrl = URL.createObjectURL(new Blob([data], { type: contentType }));
|
||||||
|
@ -14,10 +14,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import "../extensions/firefox/tools/l10n.js";
|
import "../extensions/firefox/tools/l10n.js";
|
||||||
import { DEFAULT_SCALE_VALUE, PdfFileRegExp } from "./ui_utils.js";
|
|
||||||
import { DefaultExternalServices, PDFViewerApplication } from "./app.js";
|
import { DefaultExternalServices, PDFViewerApplication } from "./app.js";
|
||||||
import { PDFDataRangeTransport, shadow } from "pdfjs-lib";
|
import { isPdfFile, PDFDataRangeTransport, shadow } from "pdfjs-lib";
|
||||||
import { BasePreferences } from "./preferences.js";
|
import { BasePreferences } from "./preferences.js";
|
||||||
|
import { DEFAULT_SCALE_VALUE } from "./ui_utils.js";
|
||||||
|
|
||||||
if (typeof PDFJSDev === "undefined" || !PDFJSDev.test("MOZCENTRAL")) {
|
if (typeof PDFJSDev === "undefined" || !PDFJSDev.test("MOZCENTRAL")) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@ -129,10 +129,10 @@ class DownloadManager {
|
|||||||
* @returns {boolean} Indicating if the data was opened.
|
* @returns {boolean} Indicating if the data was opened.
|
||||||
*/
|
*/
|
||||||
openOrDownloadData(element, data, filename) {
|
openOrDownloadData(element, data, filename) {
|
||||||
const isPdfFile = PdfFileRegExp.test(filename);
|
const isPdfData = isPdfFile(filename);
|
||||||
const contentType = isPdfFile ? "application/pdf" : "";
|
const contentType = isPdfData ? "application/pdf" : "";
|
||||||
|
|
||||||
if (isPdfFile) {
|
if (isPdfData) {
|
||||||
let blobUrl = this._openBlobUrls.get(element);
|
let blobUrl = this._openBlobUrls.get(element);
|
||||||
if (!blobUrl) {
|
if (!blobUrl) {
|
||||||
blobUrl = URL.createObjectURL(new Blob([data], { type: contentType }));
|
blobUrl = URL.createObjectURL(new Blob([data], { type: contentType }));
|
||||||
@ -332,7 +332,8 @@ class FirefoxExternalServices extends DefaultExternalServices {
|
|||||||
pdfDataRangeTransport = new FirefoxComDataRangeTransport(
|
pdfDataRangeTransport = new FirefoxComDataRangeTransport(
|
||||||
args.length,
|
args.length,
|
||||||
args.data,
|
args.data,
|
||||||
args.done
|
args.done,
|
||||||
|
args.filename
|
||||||
);
|
);
|
||||||
|
|
||||||
callbacks.onOpenWithTransport(
|
callbacks.onOpenWithTransport(
|
||||||
@ -367,7 +368,7 @@ class FirefoxExternalServices extends DefaultExternalServices {
|
|||||||
callbacks.onError(args.errorCode);
|
callbacks.onError(args.errorCode);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
callbacks.onOpenWithData(args.data);
|
callbacks.onOpenWithData(args.data, args.filename);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -119,8 +119,8 @@ class PDFAttachmentViewer extends BaseTreeViewer {
|
|||||||
let attachmentsCount = 0;
|
let attachmentsCount = 0;
|
||||||
for (const name of names) {
|
for (const name of names) {
|
||||||
const item = attachments[name];
|
const item = attachments[name];
|
||||||
const content = item.content;
|
const content = item.content,
|
||||||
const filename = getFilenameFromUrl(item.filename);
|
filename = getFilenameFromUrl(item.filename);
|
||||||
|
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
div.className = "treeItem";
|
div.className = "treeItem";
|
||||||
|
@ -69,9 +69,6 @@ const SpreadMode = {
|
|||||||
// Used by `PDFViewerApplication`, and by the API unit-tests.
|
// Used by `PDFViewerApplication`, and by the API unit-tests.
|
||||||
const AutoPrintRegExp = /\bprint\s*\(/;
|
const AutoPrintRegExp = /\bprint\s*\(/;
|
||||||
|
|
||||||
// Used by the (various) `DownloadManager`-implementations.
|
|
||||||
const PdfFileRegExp = /\.pdf$/i;
|
|
||||||
|
|
||||||
// Replaces {{arguments}} with their values.
|
// Replaces {{arguments}} with their values.
|
||||||
function formatL10nValue(text, args) {
|
function formatL10nValue(text, args) {
|
||||||
if (!args) {
|
if (!args) {
|
||||||
@ -1062,7 +1059,6 @@ export {
|
|||||||
normalizeWheelEventDirection,
|
normalizeWheelEventDirection,
|
||||||
NullL10n,
|
NullL10n,
|
||||||
parseQueryString,
|
parseQueryString,
|
||||||
PdfFileRegExp,
|
|
||||||
PresentationModeState,
|
PresentationModeState,
|
||||||
ProgressBar,
|
ProgressBar,
|
||||||
RendererType,
|
RendererType,
|
||||||
|
Loading…
Reference in New Issue
Block a user