summaryrefslogtreecommitdiff
path: root/addons/web/static/src/js/libs/content-disposition.js
diff options
context:
space:
mode:
authorstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
committerstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
commit3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch)
treea44932296ef4a9b71d5f010906253d8c53727726 /addons/web/static/src/js/libs/content-disposition.js
parent0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff)
initial commit 2
Diffstat (limited to 'addons/web/static/src/js/libs/content-disposition.js')
-rw-r--r--addons/web/static/src/js/libs/content-disposition.js249
1 files changed, 249 insertions, 0 deletions
diff --git a/addons/web/static/src/js/libs/content-disposition.js b/addons/web/static/src/js/libs/content-disposition.js
new file mode 100644
index 00000000..d229bd4c
--- /dev/null
+++ b/addons/web/static/src/js/libs/content-disposition.js
@@ -0,0 +1,249 @@
+/*
+(The MIT License)
+
+Copyright (c) 2014-2017 Douglas Christopher Wilson
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * Stripped down to only parsing/decoding.
+ */
+odoo.define('web.contentdisposition', function () {
+'use strict';
+
+/**
+ * RegExp to match percent encoding escape.
+ * @private
+ */
+var HEX_ESCAPE_REPLACE_REGEXP = /%([0-9A-Fa-f]{2})/g;
+
+/**
+ * RegExp to match non-latin1 characters.
+ * @private
+ */
+var NON_LATIN1_REGEXP = /[^\x20-\x7e\xa0-\xff]/g;
+
+/**
+ * RegExp to match quoted-pair in RFC 2616
+ *
+ * quoted-pair = "\" CHAR
+ * CHAR = <any US-ASCII character (octets 0 - 127)>
+ * @private
+ */
+var QESC_REGEXP = /\\([\u0000-\u007f])/g;
+
+/**
+ * RegExp for various RFC 2616 grammar
+ *
+ * parameter = token "=" ( token | quoted-string )
+ * token = 1*<any CHAR except CTLs or separators>
+ * separators = "(" | ")" | "<" | ">" | "@"
+ * | "," | ";" | ":" | "\" | <">
+ * | "/" | "[" | "]" | "?" | "="
+ * | "{" | "}" | SP | HT
+ * quoted-string = ( <"> *(qdtext | quoted-pair ) <"> )
+ * qdtext = <any TEXT except <">>
+ * quoted-pair = "\" CHAR
+ * CHAR = <any US-ASCII character (octets 0 - 127)>
+ * TEXT = <any OCTET except CTLs, but including LWS>
+ * LWS = [CRLF] 1*( SP | HT )
+ * CRLF = CR LF
+ * CR = <US-ASCII CR, carriage return (13)>
+ * LF = <US-ASCII LF, linefeed (10)>
+ * SP = <US-ASCII SP, space (32)>
+ * HT = <US-ASCII HT, horizontal-tab (9)>
+ * CTL = <any US-ASCII control character (octets 0 - 31) and DEL (127)>
+ * OCTET = <any 8-bit sequence of data>
+ * @private
+ */
+var PARAM_REGEXP = /;[\x09\x20]*([!#$%&'*+.0-9A-Z^_`a-z|~-]+)[\x09\x20]*=[\x09\x20]*("(?:[\x20!\x23-\x5b\x5d-\x7e\x80-\xff]|\\[\x20-\x7e])*"|[!#$%&'*+.0-9A-Z^_`a-z|~-]+)[\x09\x20]*/g;
+
+/**
+ * RegExp for various RFC 5987 grammar
+ *
+ * ext-value = charset "'" [ language ] "'" value-chars
+ * charset = "UTF-8" / "ISO-8859-1" / mime-charset
+ * mime-charset = 1*mime-charsetc
+ * mime-charsetc = ALPHA / DIGIT
+ * / "!" / "#" / "$" / "%" / "&"
+ * / "+" / "-" / "^" / "_" / "`"
+ * / "{" / "}" / "~"
+ * language = ( 2*3ALPHA [ extlang ] )
+ * / 4ALPHA
+ * / 5*8ALPHA
+ * extlang = *3( "-" 3ALPHA )
+ * value-chars = *( pct-encoded / attr-char )
+ * pct-encoded = "%" HEXDIG HEXDIG
+ * attr-char = ALPHA / DIGIT
+ * / "!" / "#" / "$" / "&" / "+" / "-" / "."
+ * / "^" / "_" / "`" / "|" / "~"
+ * @private
+ */
+var EXT_VALUE_REGEXP = /^([A-Za-z0-9!#$%&+\-^_`{}~]+)'(?:[A-Za-z]{2,3}(?:-[A-Za-z]{3}){0,3}|[A-Za-z]{4,8}|)'((?:%[0-9A-Fa-f]{2}|[A-Za-z0-9!#$&+.^_`|~-])+)$/;
+
+/**
+ * RegExp for various RFC 6266 grammar
+ *
+ * disposition-type = "inline" | "attachment" | disp-ext-type
+ * disp-ext-type = token
+ * disposition-parm = filename-parm | disp-ext-parm
+ * filename-parm = "filename" "=" value
+ * | "filename*" "=" ext-value
+ * disp-ext-parm = token "=" value
+ * | ext-token "=" ext-value
+ * ext-token = <the characters in token, followed by "*">
+ * @private
+ */
+var DISPOSITION_TYPE_REGEXP = /^([!#$%&'*+.0-9A-Z^_`a-z|~-]+)[\x09\x20]*(?:$|;)/;
+
+/**
+ * Decode a RFC 6987 field value (gracefully).
+ *
+ * @param {string} str
+ * @return {string}
+ * @private
+ */
+function decodefield(str) {
+ var match = EXT_VALUE_REGEXP.exec(str);
+
+ if (!match) {
+ throw new TypeError('invalid extended field value')
+ }
+
+ var charset = match[1].toLowerCase();
+ var encoded = match[2];
+
+ switch (charset) {
+ case 'iso-8859-1':
+ return encoded.replace(HEX_ESCAPE_REPLACE_REGEXP, pdecode).replace(NON_LATIN1_REGEXP, '?');
+ case 'utf-8':
+ return decodeURIComponent(encoded);
+ default:
+ throw new TypeError('unsupported charset in extended field')
+ }
+}
+
+/**
+ * Parse Content-Disposition header string.
+ *
+ * @param {string} string
+ * @return {ContentDisposition}
+ * @public
+ */
+function parse(string) {
+ if (!string || typeof string !== 'string') {
+ throw new TypeError('argument string is required')
+ }
+
+ var match = DISPOSITION_TYPE_REGEXP.exec(string);
+
+ if (!match) {
+ throw new TypeError('invalid type format')
+ }
+
+ // normalize type
+ var index = match[0].length;
+ var type = match[1].toLowerCase();
+
+ var key;
+ var names = [];
+ var params = {};
+ var value;
+
+ // calculate index to start at
+ index = PARAM_REGEXP.lastIndex = match[0].substr(-1) === ';' ? index - 1 : index;
+
+ // match parameters
+ while ((match = PARAM_REGEXP.exec(string))) {
+ if (match.index !== index) {
+ throw new TypeError('invalid parameter format')
+ }
+
+ index += match[0].length;
+ key = match[1].toLowerCase();
+ value = match[2];
+
+ if (names.indexOf(key) !== -1) {
+ throw new TypeError('invalid duplicate parameter')
+ }
+
+ names.push(key);
+
+ if (key.indexOf('*') + 1 === key.length) {
+ // decode extended value
+ key = key.slice(0, -1);
+ value = decodefield(value);
+
+ // overwrite existing value
+ params[key] = value;
+ continue
+ }
+
+ if (typeof params[key] === 'string') {
+ continue
+ }
+
+ if (value[0] === '"') {
+ // remove quotes and escapes
+ value = value
+ .substr(1, value.length - 2)
+ .replace(QESC_REGEXP, '$1')
+ }
+
+ params[key] = value
+ }
+
+ if (index !== -1 && index !== string.length) {
+ throw new TypeError('invalid parameter format')
+ }
+
+ return new ContentDisposition(type, params)
+}
+
+/**
+ * Percent decode a single character.
+ *
+ * @param {string} str
+ * @param {string} hex
+ * @return {string}
+ * @private
+ */
+function pdecode(str, hex) {
+ return String.fromCharCode(parseInt(hex, 16))
+}
+
+/**
+ * Class for parsed Content-Disposition header for v8 optimization
+ *
+ * @public
+ * @param {string} type
+ * @param {object} parameters
+ * @constructor
+ */
+function ContentDisposition(type, parameters) {
+ this.type = type;
+ this.parameters = parameters
+}
+
+return {
+ parse: parse,
+};
+});