| /** |
| * @licstart The following is the entire license notice for the |
| * Javascript code in this page |
| * |
| * Copyright 2020 Mozilla Foundation |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| * @licend The above is the entire license notice for the |
| * Javascript code in this page |
| */ |
| "use strict"; |
| |
| Object.defineProperty(exports, "__esModule", { |
| value: true |
| }); |
| exports.getFilenameFromContentDispositionHeader = getFilenameFromContentDispositionHeader; |
| |
| function getFilenameFromContentDispositionHeader(contentDisposition) { |
| let needsEncodingFixup = true; |
| let tmp = toParamRegExp("filename\\*", "i").exec(contentDisposition); |
| |
| if (tmp) { |
| tmp = tmp[1]; |
| let filename = rfc2616unquote(tmp); |
| filename = unescape(filename); |
| filename = rfc5987decode(filename); |
| filename = rfc2047decode(filename); |
| return fixupEncoding(filename); |
| } |
| |
| tmp = rfc2231getparam(contentDisposition); |
| |
| if (tmp) { |
| const filename = rfc2047decode(tmp); |
| return fixupEncoding(filename); |
| } |
| |
| tmp = toParamRegExp("filename", "i").exec(contentDisposition); |
| |
| if (tmp) { |
| tmp = tmp[1]; |
| let filename = rfc2616unquote(tmp); |
| filename = rfc2047decode(filename); |
| return fixupEncoding(filename); |
| } |
| |
| function toParamRegExp(attributePattern, flags) { |
| return new RegExp("(?:^|;)\\s*" + attributePattern + "\\s*=\\s*" + "(" + '[^";\\s][^;\\s]*' + "|" + '"(?:[^"\\\\]|\\\\"?)+"?' + ")", flags); |
| } |
| |
| function textdecode(encoding, value) { |
| if (encoding) { |
| if (!/^[\x00-\xFF]+$/.test(value)) { |
| return value; |
| } |
| |
| try { |
| const decoder = new TextDecoder(encoding, { |
| fatal: true |
| }); |
| const bytes = Array.from(value, function (ch) { |
| return ch.charCodeAt(0) & 0xff; |
| }); |
| value = decoder.decode(new Uint8Array(bytes)); |
| needsEncodingFixup = false; |
| } catch (e) { |
| if (/^utf-?8$/i.test(encoding)) { |
| try { |
| value = decodeURIComponent(escape(value)); |
| needsEncodingFixup = false; |
| } catch (err) {} |
| } |
| } |
| } |
| |
| return value; |
| } |
| |
| function fixupEncoding(value) { |
| if (needsEncodingFixup && /[\x80-\xff]/.test(value)) { |
| value = textdecode("utf-8", value); |
| |
| if (needsEncodingFixup) { |
| value = textdecode("iso-8859-1", value); |
| } |
| } |
| |
| return value; |
| } |
| |
| function rfc2231getparam(contentDispositionStr) { |
| const matches = []; |
| let match; |
| const iter = toParamRegExp("filename\\*((?!0\\d)\\d+)(\\*?)", "ig"); |
| |
| while ((match = iter.exec(contentDispositionStr)) !== null) { |
| let [, n, quot, part] = match; |
| n = parseInt(n, 10); |
| |
| if (n in matches) { |
| if (n === 0) { |
| break; |
| } |
| |
| continue; |
| } |
| |
| matches[n] = [quot, part]; |
| } |
| |
| const parts = []; |
| |
| for (let n = 0; n < matches.length; ++n) { |
| if (!(n in matches)) { |
| break; |
| } |
| |
| let [quot, part] = matches[n]; |
| part = rfc2616unquote(part); |
| |
| if (quot) { |
| part = unescape(part); |
| |
| if (n === 0) { |
| part = rfc5987decode(part); |
| } |
| } |
| |
| parts.push(part); |
| } |
| |
| return parts.join(""); |
| } |
| |
| function rfc2616unquote(value) { |
| if (value.startsWith('"')) { |
| const parts = value.slice(1).split('\\"'); |
| |
| for (let i = 0; i < parts.length; ++i) { |
| const quotindex = parts[i].indexOf('"'); |
| |
| if (quotindex !== -1) { |
| parts[i] = parts[i].slice(0, quotindex); |
| parts.length = i + 1; |
| } |
| |
| parts[i] = parts[i].replace(/\\(.)/g, "$1"); |
| } |
| |
| value = parts.join('"'); |
| } |
| |
| return value; |
| } |
| |
| function rfc5987decode(extvalue) { |
| const encodingend = extvalue.indexOf("'"); |
| |
| if (encodingend === -1) { |
| return extvalue; |
| } |
| |
| const encoding = extvalue.slice(0, encodingend); |
| const langvalue = extvalue.slice(encodingend + 1); |
| const value = langvalue.replace(/^[^']*'/, ""); |
| return textdecode(encoding, value); |
| } |
| |
| function rfc2047decode(value) { |
| if (!value.startsWith("=?") || /[\x00-\x19\x80-\xff]/.test(value)) { |
| return value; |
| } |
| |
| return value.replace(/=\?([\w-]*)\?([QqBb])\?((?:[^?]|\?(?!=))*)\?=/g, function (matches, charset, encoding, text) { |
| if (encoding === "q" || encoding === "Q") { |
| text = text.replace(/_/g, " "); |
| text = text.replace(/=([0-9a-fA-F]{2})/g, function (match, hex) { |
| return String.fromCharCode(parseInt(hex, 16)); |
| }); |
| return textdecode(charset, text); |
| } |
| |
| try { |
| text = atob(text); |
| } catch (e) {} |
| |
| return textdecode(charset, text); |
| }); |
| } |
| |
| return ""; |
| } |