UNPKG

4.96 kBJavaScriptView Raw
1/**
2 * @licstart The following is the entire license notice for the
3 * JavaScript code in this page
4 *
5 * Copyright 2022 Mozilla Foundation
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 * @licend The above is the entire license notice for the
20 * JavaScript code in this page
21 */
22"use strict";
23
24Object.defineProperty(exports, "__esModule", {
25 value: true
26});
27exports.getFilenameFromContentDispositionHeader = getFilenameFromContentDispositionHeader;
28
29var _util = require("../shared/util.js");
30
31function getFilenameFromContentDispositionHeader(contentDisposition) {
32 let needsEncodingFixup = true;
33 let tmp = toParamRegExp("filename\\*", "i").exec(contentDisposition);
34
35 if (tmp) {
36 tmp = tmp[1];
37 let filename = rfc2616unquote(tmp);
38 filename = unescape(filename);
39 filename = rfc5987decode(filename);
40 filename = rfc2047decode(filename);
41 return fixupEncoding(filename);
42 }
43
44 tmp = rfc2231getparam(contentDisposition);
45
46 if (tmp) {
47 const filename = rfc2047decode(tmp);
48 return fixupEncoding(filename);
49 }
50
51 tmp = toParamRegExp("filename", "i").exec(contentDisposition);
52
53 if (tmp) {
54 tmp = tmp[1];
55 let filename = rfc2616unquote(tmp);
56 filename = rfc2047decode(filename);
57 return fixupEncoding(filename);
58 }
59
60 function toParamRegExp(attributePattern, flags) {
61 return new RegExp("(?:^|;)\\s*" + attributePattern + "\\s*=\\s*" + "(" + '[^";\\s][^;\\s]*' + "|" + '"(?:[^"\\\\]|\\\\"?)+"?' + ")", flags);
62 }
63
64 function textdecode(encoding, value) {
65 if (encoding) {
66 if (!/^[\x00-\xFF]+$/.test(value)) {
67 return value;
68 }
69
70 try {
71 const decoder = new TextDecoder(encoding, {
72 fatal: true
73 });
74 const buffer = (0, _util.stringToBytes)(value);
75 value = decoder.decode(buffer);
76 needsEncodingFixup = false;
77 } catch (e) {}
78 }
79
80 return value;
81 }
82
83 function fixupEncoding(value) {
84 if (needsEncodingFixup && /[\x80-\xff]/.test(value)) {
85 value = textdecode("utf-8", value);
86
87 if (needsEncodingFixup) {
88 value = textdecode("iso-8859-1", value);
89 }
90 }
91
92 return value;
93 }
94
95 function rfc2231getparam(contentDispositionStr) {
96 const matches = [];
97 let match;
98 const iter = toParamRegExp("filename\\*((?!0\\d)\\d+)(\\*?)", "ig");
99
100 while ((match = iter.exec(contentDispositionStr)) !== null) {
101 let [, n, quot, part] = match;
102 n = parseInt(n, 10);
103
104 if (n in matches) {
105 if (n === 0) {
106 break;
107 }
108
109 continue;
110 }
111
112 matches[n] = [quot, part];
113 }
114
115 const parts = [];
116
117 for (let n = 0; n < matches.length; ++n) {
118 if (!(n in matches)) {
119 break;
120 }
121
122 let [quot, part] = matches[n];
123 part = rfc2616unquote(part);
124
125 if (quot) {
126 part = unescape(part);
127
128 if (n === 0) {
129 part = rfc5987decode(part);
130 }
131 }
132
133 parts.push(part);
134 }
135
136 return parts.join("");
137 }
138
139 function rfc2616unquote(value) {
140 if (value.startsWith('"')) {
141 const parts = value.slice(1).split('\\"');
142
143 for (let i = 0; i < parts.length; ++i) {
144 const quotindex = parts[i].indexOf('"');
145
146 if (quotindex !== -1) {
147 parts[i] = parts[i].slice(0, quotindex);
148 parts.length = i + 1;
149 }
150
151 parts[i] = parts[i].replace(/\\(.)/g, "$1");
152 }
153
154 value = parts.join('"');
155 }
156
157 return value;
158 }
159
160 function rfc5987decode(extvalue) {
161 const encodingend = extvalue.indexOf("'");
162
163 if (encodingend === -1) {
164 return extvalue;
165 }
166
167 const encoding = extvalue.slice(0, encodingend);
168 const langvalue = extvalue.slice(encodingend + 1);
169 const value = langvalue.replace(/^[^']*'/, "");
170 return textdecode(encoding, value);
171 }
172
173 function rfc2047decode(value) {
174 if (!value.startsWith("=?") || /[\x00-\x19\x80-\xff]/.test(value)) {
175 return value;
176 }
177
178 return value.replace(/=\?([\w-]*)\?([QqBb])\?((?:[^?]|\?(?!=))*)\?=/g, function (matches, charset, encoding, text) {
179 if (encoding === "q" || encoding === "Q") {
180 text = text.replace(/_/g, " ");
181 text = text.replace(/=([0-9a-fA-F]{2})/g, function (match, hex) {
182 return String.fromCharCode(parseInt(hex, 16));
183 });
184 return textdecode(charset, text);
185 }
186
187 try {
188 text = atob(text);
189 } catch (e) {}
190
191 return textdecode(charset, text);
192 });
193 }
194
195 return "";
196}
\No newline at end of file