LCOV - code coverage report
Current view: top level - lib/helper - content-type.js (source / functions) Hit Total Coverage
Test: lcov.info Lines: 184 214 86.0 %
Date: 2025-01-24 02:02:48 Functions: 4 5 80.0 %
Branches: 20 27 74.1 %

           Branch data     Line data    Source code
       1            [ + ]:        229 : /**
       2                 :        229 :  * @module  helper-content-type
       3                 :        229 :  * @desc    Helper module - Helper functions for the main module {@link module:whatwg-xhr whatwg-xhr}.
       4                 :        229 :  * @version 1.0.0
       5                 :        229 :  * @author  Essam A. El-Sherif
       6                 :        229 :  */
       7                 :        229 : 
       8                 :        229 : /*
       9                 :        229 :  * RegExp to match *( ";" parameter ) in RFC 7231 sec 3.1.1.1
      10                 :        229 :  *
      11                 :        229 :  * parameter     = token "=" ( token / quoted-string )
      12                 :        229 :  * token         = 1*tchar
      13                 :        229 :  * tchar         = "!" / "#" / "$" / "%" / "&" / "'" / "*"
      14                 :        229 :  *               / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
      15                 :        229 :  *               / DIGIT / ALPHA
      16                 :        229 :  *               ; any VCHAR, except delimiters
      17                 :        229 :  * quoted-string = DQUOTE *( qdtext / quoted-pair ) DQUOTE
      18                 :        229 :  * qdtext        = HTAB / SP / %x21 / %x23-5B / %x5D-7E / obs-text
      19                 :        229 :  * obs-text      = %x80-FF
      20                 :        229 :  * quoted-pair   = "\" ( HTAB / SP / VCHAR / obs-text )
      21                 :        229 :  */
      22                 :        229 : const PARAM_REGEXP = /; *([!#$%&'*+.^_`|~0-9A-Za-z-]+) *= *("(?:[\u000b\u0020\u0021\u0023-\u005b\u005d-\u007e\u0080-\u00ff]|\\[\u000b\u0020-\u00ff])*"|[!#$%&'*+.^_`|~0-9A-Za-z-]+) */g; // eslint-disable-line no-control-regex
      23                 :        229 : const TEXT_REGEXP  = /^[\u000b\u0020-\u007e\u0080-\u00ff]+$/; // eslint-disable-line no-control-regex
      24                 :        229 : const TOKEN_REGEXP = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
      25                 :        229 : 
      26                 :        229 : /*
      27                 :        229 :  * RegExp to match quoted-pair in RFC 7230 sec 3.2.6
      28                 :        229 :  *
      29                 :        229 :  * quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text )
      30                 :        229 :  * obs-text    = %x80-FF
      31                 :        229 :  */
      32                 :        229 : const QESC_REGEXP = /\\([\u000b\u0020-\u00ff])/g // eslint-disable-line no-control-regex;
      33                 :        229 : 
      34                 :        229 : /*
      35                 :        229 :  * RegExp to match chars that must be quoted-pair in RFC 7230 sec 3.2.6
      36                 :        229 :  */
      37                 :        229 : const QUOTE_REGEXP = /([\\"])/g;
      38                 :        229 : 
      39                 :        229 : /*
      40                 :        229 :  * RegExp to match type in RFC 7231 sec 3.1.1.1
      41                 :        229 :  *
      42                 :        229 :  * media-type = type "/" subtype
      43                 :        229 :  * type       = token
      44                 :        229 :  * subtype    = token
      45                 :        229 :  */
      46                 :        229 : const TYPE_REGEXP = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+\/[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
      47                 :        229 : 
      48                 :        229 : /**
      49                 :        229 :  * @func   format
      50                 :        229 :  * @static
      51                 :        229 :  * @param  {object} obj
      52                 :        229 :  * @return {string}
      53                 :        229 :  * @desc   Format object to media type.
      54                 :        229 :  */
      55            [ + ]:        229 : export function format(obj){
      56            [ - ]:          6 :         if(!obj || typeof obj !== 'object'){
      57                 :          0 :                 throw new TypeError('argument obj is required');
      58                 :          0 :         }
      59                 :          6 : 
      60                 :          6 :         var parameters = obj.parameters;
      61                 :          6 :         var type = obj.type;
      62                 :          6 : 
      63            [ - ]:          6 :         if(!type || !TYPE_REGEXP.test(type)){
      64                 :          0 :                 throw new TypeError('invalid type');
      65                 :          0 :         }
      66                 :          6 : 
      67                 :          6 :         var string = type;
      68                 :          6 : 
      69                 :          6 :         // append parameters
      70                 :          6 :         if (parameters && typeof parameters === 'object'){
      71                 :          6 :                 var param;
      72                 :          6 :                 var params = Object.keys(parameters);
      73                 :          6 : 
      74            [ + ]:          6 :                 for (var i = 0; i < params.length; i++){
      75                 :          8 :                         param = params[i];
      76                 :          8 : 
      77            [ - ]:          8 :                         if(!TOKEN_REGEXP.test(param)){
      78                 :          0 :                                 throw new TypeError('invalid parameter name');
      79                 :          0 :                         }
      80                 :          8 : 
      81                 :          8 :                         string += ';' + param + '=' + qstring(parameters[param]);
      82                 :          8 :                 }
      83                 :          6 :         }
      84                 :          6 : 
      85                 :          6 :         return string;
      86                 :          6 : }
      87                 :        229 : 
      88                 :        229 : /**
      89                 :        229 :  * @func   parse
      90                 :        229 :  * @static
      91                 :        229 :  * @param  {string|object} string
      92                 :        229 :  * @return {object}
      93                 :        229 :  * @desc   Parse media type to object.
      94                 :        229 :  */
      95            [ + ]:        229 : export function parse (string) {
      96       [ + ][ + ]:       1840 :         if(!string){
      97                 :         30 :                 throw new TypeError('argument string is required');
      98            [ + ]:         30 :         }
      99                 :         30 : 
     100                 :         30 :         // support req/res-like objects as argument
     101                 :         30 :         var header = typeof string === 'object'
     102            [ - ]:       1840 :                 ? getcontenttype(string)
     103            [ + ]:       1840 :                 : string;
     104                 :       1840 : 
     105            [ - ]:       1840 :         if(typeof header !== 'string'){
     106                 :          0 :                 throw new TypeError('argument string is required to be a string');
     107            [ + ]:          0 :         }
     108                 :        730 : 
     109                 :        730 :         var index = header.indexOf(';');
     110                 :        730 :         var type = index !== -1
     111            [ + ]:       1840 :                 ? header.slice(0, index).trim()
     112            [ + ]:       1840 :                 : header.trim();
     113                 :       1840 : 
     114            [ + ]:       1840 :         if (!TYPE_REGEXP.test(type)){
     115                 :          3 :                 throw new TypeError('invalid media type');
     116            [ + ]:          3 :         }
     117                 :        727 : 
     118                 :        727 :         var obj = new ContentType(type.toLowerCase());
     119                 :        727 : 
     120                 :        727 :         // parse parameters
     121            [ + ]:       1840 :         if (index !== -1) {
     122                 :         52 :                 var key
     123                 :         52 :                 var match
     124                 :         52 :                 var value
     125                 :         52 : 
     126                 :         52 :                 PARAM_REGEXP.lastIndex = index
     127                 :         52 : 
     128            [ + ]:         52 :                 while((match = PARAM_REGEXP.exec(header))) {
     129                 :         55 :                         if(match.index !== index){
     130                 :         55 :                                 throw new TypeError('invalid parameter format');
     131                 :         55 :                         }
     132                 :         55 : 
     133                 :         55 :                         index += match[0].length;
     134                 :         55 :                         key = match[1].toLowerCase();
     135                 :         55 :                         value = match[2];
     136                 :         55 : 
     137            [ + ]:         55 :                         if (value.charCodeAt(0) === 0x22 /* " */) {
     138                 :          3 :                                 // remove quotes
     139                 :          3 :                                 value = value.slice(1, -1);
     140                 :          3 : 
     141                 :          3 :                                 // remove escapes
     142            [ + ]:          3 :                                 if(value.indexOf('\\') !== -1){
     143                 :          1 :                                         value = value.replace(QESC_REGEXP, '$1');
     144                 :          1 :                                 }
     145                 :          3 :                         }
     146                 :         55 : 
     147                 :         55 :                         obj.parameters[key] = value;
     148                 :         55 :                 }
     149                 :         52 : 
     150                 :         52 :                 if(index !== header.length){
     151                 :         52 :                         throw new TypeError('invalid parameter format');
     152                 :         52 :                 }
     153            [ + ]:         52 :         }
     154                 :        727 : 
     155                 :        727 :         return obj;
     156                 :       1840 : }
     157                 :        229 : 
     158                 :        229 : /*
     159                 :        229 :  * Get content-type from req/res objects.
     160                 :        229 :  *
     161                 :        229 :  * @param  {object}
     162                 :        229 :  * @return {object}
     163                 :        229 :  * @private
     164                 :        229 :  */
     165                 :          0 : function getcontenttype (obj) {
     166                 :          0 :         var header;
     167                 :          0 : 
     168                 :          0 :         if (typeof obj.getHeader === 'function') {
     169                 :          0 :                 // res-like
     170                 :          0 :                 header = obj.getHeader('content-type')
     171                 :          0 :         } else if (typeof obj.headers === 'object') {
     172                 :          0 :                 // req-like
     173                 :          0 :                 header = obj.headers && obj.headers['content-type']
     174                 :          0 :         }
     175                 :          0 : 
     176                 :          0 :         if (typeof header !== 'string') {
     177                 :          0 :                 throw new TypeError('content-type header is missing from object')
     178                 :          0 :         }
     179                 :          0 : 
     180                 :          0 :         return header
     181                 :          0 : }
     182                 :        229 : 
     183                 :        229 : /*
     184                 :        229 :  * Quote a string if necessary.
     185                 :        229 :  *
     186                 :        229 :  * @param {string} val
     187                 :        229 :  * @return {string}
     188                 :        229 :  * @private
     189                 :        229 :  */
     190                 :        229 : 
     191            [ + ]:          8 : function qstring (val) {
     192                 :          8 :         var str = String(val)
     193                 :          8 : 
     194                 :          8 :         // no need to quote tokens
     195                 :          8 :         if (TOKEN_REGEXP.test(str)) {
     196                 :          8 :                 return str;
     197            [ - ]:          8 :         }
     198                 :          0 : 
     199            [ - ]:          8 :         if (str.length > 0 && !TEXT_REGEXP.test(str)) {
     200                 :          0 :                 throw new TypeError('invalid parameter value');
     201                 :          0 :         }
     202                 :          0 : 
     203                 :          0 :         return '"' + str.replace(QUOTE_REGEXP, '\\$1') + '"'
     204                 :          8 : }
     205                 :        229 : 
     206                 :        229 : /*
     207                 :        229 :  * Class to represent a content type.
     208                 :        229 :  * @private
     209                 :        229 :  */
     210            [ + ]:       1757 : function ContentType (type) {
     211                 :       1757 :         this.parameters = Object.create(null);
     212                 :       1757 :         this.type = type;
     213                 :       1757 : }
     214                 :        229 : 

Generated by: LCOV version 1.14