LCOV - code coverage report
Current view: top level - lib/helper - content-type.js (source / functions) Hit Total Coverage
Test: lcov.info Lines: 186 216 86.1 %
Date: 2024-12-07 00:20:21 Functions: 4 5 80.0 %
Branches: 20 27 74.1 %

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

Generated by: LCOV version 1.14