LCOV - code coverage report
Current view: top level - lib - whatwg-xhr.js (source / functions) Hit Total Coverage
Test: lcov.info Lines: 2933 3089 94.9 %
Date: 2024-12-07 00:20:21 Functions: 69 82 84.1 %
Branches: 329 376 87.5 %

           Branch data     Line data    Source code
       1            [ + ]:        348 : /**
       2                 :        348 :  * XMLHttpRequest Living Standard — Last Updated 20 February 2023
       3                 :        348 :  * url: https://xhr.spec.whatwg.org/
       4                 :        348 :  *
       5                 :        348 :  * class XMLHttpRequestEventTarget extends EventTarget
       6                 :        348 :  * class XMLHttpRequestUpload      extends XMLHttpRequestEventTarget
       7                 :        348 :  * const XMLHttpRequestResponseType
       8                 :        348 :  * export class XMLHttpRequest extends XMLHttpRequestEventTarget
       9                 :        348 :  * export class ProgressEvent  extends Event
      10                 :        348 :  * export class FormData
      11                 :        348 :  *
      12                 :        348 :  * function handleError
      13                 :        348 :  * function requestErrorSteps
      14                 :        348 :  * function setResponseToNetworkError
      15                 :        348 :  *
      16                 :        348 :  * function getResponseMimeType
      17                 :        348 :  * function getFinalMimeType
      18                 :        348 :  * function getFinalEncoding
      19                 :        348 :  * function setDocumentResponse
      20                 :        348 :  * function getTextResponse
      21                 :        348 :  *
      22                 :        348 :  * class ClientRequestData
      23                 :        348 :  * function requestDataURL
      24                 :        348 :  *
      25                 :        348 :  * @module  whatwg-xhr
      26                 :        348 :  * @desc    Main module - A Node.js implementation of the {@link https://xhr.spec.whatwg.org/ WHATWG XMLHttpRequest Living Standard} for non-browser environments.
      27                 :        348 :  * @version 1.0.0
      28                 :        348 :  * @author  Essam A. El-Sherif
      29                 :        348 :  */
      30                 :        348 : 
      31                 :        348 : /* Import nodeJS core modules */
      32                 :        348 : import fs                  from 'node:fs';
      33                 :        348 : import http                from 'node:http';
      34                 :        348 : import https               from 'node:https';
      35                 :        348 : import process             from 'node:process';
      36                 :        348 : import threads             from 'node:worker_threads';
      37                 :        348 : import { spawn }           from 'node:child_process';
      38                 :        348 : import { dirname }         from 'node:path';
      39                 :        348 : import { fileURLToPath }   from 'node:url';
      40                 :        348 : import { Readable }        from 'node:stream';
      41                 :        348 : 
      42                 :        348 : /**
      43                 :        348 :  * Global object available in all node modules >= v17.0.0
      44                 :        348 :  *
      45                 :        348 :  * DOMException  Added in: node v17.0.0
      46                 :        348 :  *
      47                 :        348 :  * @external DOMException
      48                 :        348 :  * @desc Global object available in all node modules >= v17.0.0, defined by {@link https://webidl.spec.whatwg.org/#idl-DOMException WHATWG IDL Living Standard} and implemented by {@link https://nodejs.org/docs/latest/api/globals.html#domexception node.js}.
      49                 :        348 :  */
      50                 :        348 : 
      51                 :        348 : /**
      52                 :        348 :  * Global object available in all node modules >= v15.4.0.
      53                 :        348 :  *
      54                 :        348 :  * @interface EventTarget
      55                 :        348 :  * @desc A browser-compatible implementation of the EventTarget class, defined by {@link https://dom.spec.whatwg.org/#eventtarget WHATWG DOM Living Standard} and implemented by {@link https://nodejs.org/docs/latest/api/globals.html#eventtarget node.js}.
      56                 :        348 :  */
      57                 :        348 : 
      58                 :        348 : /**
      59                 :        348 :  * Global object available in all node modules >= v15.4.0.
      60                 :        348 :  *
      61                 :        348 :  * @interface Event
      62                 :        348 :  * @desc A browser-compatible implementation of the Event class, defined by {@link https://dom.spec.whatwg.org/#event WHATWG DOM Living Standard} and implemented by {@link https://nodejs.org/docs/latest/api/globals.html#event node.js}.
      63                 :        348 :  */
      64                 :        348 : 
      65                 :        348 : /* Import npm-packages dependencies */
      66                 :        348 : import whatwgEncoding      from 'whatwg-encoding';
      67                 :        348 : import htmlEncodingSniffer from 'html-encoding-sniffer';
      68                 :        348 : 
      69                 :        348 : /* Import from local helper modules */
      70                 :        348 : import {
      71                 :        348 :         parse  as contentTypeParse,
      72                 :        348 :         format as contentTypeFormat
      73                 :        348 : } from './helper/content-type.js';
      74                 :        348 : 
      75                 :        348 : import {
      76                 :        348 :         dataURLProcessor,
      77                 :        348 :         parseMIMEType,
      78                 :        348 :         serializeAMimeType
      79                 :        348 : } from './helper/whatwg-misc.js';
      80                 :        348 : 
      81                 :        348 : import {
      82                 :        348 :         forbiddenRequestHeader,
      83                 :        348 :         forbiddenHttpRequestMethod,
      84                 :        348 :         safelyExtractBodyWithType
      85                 :        348 : } from './helper/whatwg-fetch.js';
      86                 :        348 : 
      87                 :        348 : import {
      88                 :        348 :         xmlEncodingSniffer
      89                 :        348 : } from './helper/xml-encoding-sniffer.js';
      90                 :        348 : 
      91                 :        348 : /* Emulate commonJS __filename & __dirname global constants */
      92                 :        348 : const __filename = fileURLToPath(import.meta.url);
      93                 :        348 : const __dirname  = dirname(__filename);
      94                 :        348 : 
      95                 :        348 : /**
      96                 :        348 :  * @const {boolean} disableHeaderCheck
      97                 :        348 :  * @static
      98                 :        348 :  * @desc  Allow request-headers forbidden by {@link https://xhr.spec.whatwg.org/ XHR Specs}.
      99                 :        348 :  */
     100                 :        348 : export const disableHeaderCheck = false;
     101                 :        348 : 
     102                 :        348 : /**
     103                 :        348 :  * @func   defaultHeaders
     104                 :        348 :  * @return {object} Default headers to include in each XMLHttpRequest.
     105                 :        348 :  */
     106            [ + ]:        348 : const defaultHeaders = () => ({
     107                 :       2923 :         'User-Agent' : 'whatwg-xhr',
     108                 :       2923 :         'Accept': '*/*',
     109                 :       2923 :         'Accept-Language': 'en-US,en;q=0.5'
     110                 :        348 : });
     111                 :        348 : /****/
     112                 :        348 : 
     113                 :        348 : /**
     114                 :        348 :  * @func   defaultHeadersCase
     115                 :        348 :  * @return {object} Lower case default headers.
     116                 :        348 :  */
     117                 :        348 : const defaultHeadersCase = () => ({
     118                 :          0 :         'user-agent' : 'User-Agent',
     119                 :          0 :         'accept': 'Accept',
     120                 :          0 :         'accept-language': 'Accept-Language'
     121                 :        348 : });
     122                 :        348 : /****/
     123                 :        348 : 
     124                 :        348 : /** @const {WeakMap} xmlHttpRequestEventTarget - Map any XMLHttpRequestEventTarget object created to an associated data object. */
     125                 :        348 : const xmlHttpRequestEventTarget = new WeakMap();
     126                 :        348 : 
     127                 :        348 : /** @const {WeakMap} xmlHttpRequest - Map any XMLHttpRequest object created to an associated data object. */
     128                 :        348 : const xmlHttpRequest = new WeakMap();
     129                 :        348 : 
     130                 :        348 : /** @const {WeakMap} progressEvent - Map any ProgressEvent object created to an associated data object. */
     131                 :        348 : const progressEvent = new WeakMap();
     132                 :        348 : 
     133                 :        348 : /** @const {WeakMap} formData - Map any FormData object created to an associated data object. */
     134                 :        348 : const formData  = new WeakMap();
     135                 :        348 : 
     136                 :        348 : let allowXMLHttpRequestUploadConstructor = false;
     137                 :        348 : 
     138                 :        348 : /**
     139                 :        348 :  * XMLHttpRequest Living Standard — Last Updated 20 February 2023
     140                 :        348 :  * url: https://xhr.spec.whatwg.org/#interface-xmlhttprequest
     141                 :        348 :  *
     142                 :        348 :  * interface XMLHttpRequestEventTarget : EventTarget{
     143                 :        348 :  *   // event handlers
     144                 :        348 :  *   attribute EventHandler onloadstart;
     145                 :        348 :  *   attribute EventHandler onprogress;
     146                 :        348 :  *   attribute EventHandler onabort;
     147                 :        348 :  *   attribute EventHandler onerror;
     148                 :        348 :  *   attribute EventHandler onload;
     149                 :        348 :  *   attribute EventHandler ontimeout;
     150                 :        348 :  *   attribute EventHandler onloadend;
     151                 :        348 :  * };
     152                 :        348 :  *
     153                 :        348 :  * @class     XMLHttpRequestEventTarget
     154                 :        348 :  * @extends   module:whatwg-xhr~EventTarget
     155                 :        348 :  * @desc      Interface that describes the event handlers shared on XMLHttpRequest and XMLHttpRequestUpload interfaces.
     156                 :        348 :  */
     157                 :        348 : class XMLHttpRequestEventTarget extends EventTarget{
     158            [ + ]:        348 :         constructor(){
     159                 :       1484 :                 super();
     160                 :       1484 : 
     161                 :       1484 :                 const eventHandlers = {};
     162                 :       1484 : 
     163                 :       1484 :                 eventHandlers['onloadstart'] = null;    // xhr.spec. attribute EventHandler
     164                 :       1484 :                 eventHandlers['onprogress' ] = null;    // xhr.spec. attribute EventHandler
     165                 :       1484 :                 eventHandlers['onabort'    ] = null;    // xhr.spec. attribute EventHandler
     166                 :       1484 :                 eventHandlers['onerror'    ] = null;    // xhr.spec. attribute EventHandler
     167                 :       1484 :                 eventHandlers['onload'     ] = null;    // xhr.spec. attribute EventHandler
     168                 :       1484 :                 eventHandlers['ontimeout'  ] = null;    // xhr.spec. attribute EventHandler
     169                 :       1484 :                 eventHandlers['onloadend'  ] = null;    // xhr.spec. attribute EventHandler
     170                 :       1484 : 
     171                 :       1484 :                 xmlHttpRequestEventTarget.set(this, eventHandlers);
     172                 :       1484 :         }
     173                 :        348 : 
     174                 :        348 :         /**
     175                 :        348 :          * @member   {function} onloadstart
     176                 :        348 :          * @memberof module:whatwg-xhr~XMLHttpRequestEventTarget
     177                 :        348 :          * @instance
     178                 :        348 :          * @desc     Get/Set the event handler fired whenever the 'loadstart' event is emitted.
     179                 :        348 :          */
     180            [ + ]:        348 :         get onloadstart(){ return xmlHttpRequestEventTarget.get(this)['onloadstart']; }
     181                 :        348 : 
     182            [ + ]:        348 :         set onloadstart(callback){
     183                 :        248 :                 this.removeEventListener('loadstart', xmlHttpRequestEventTarget.get(this)['onloadstart']);
     184                 :        248 :                 xmlHttpRequestEventTarget.get(this)['onloadstart'] = null;
     185                 :        248 : 
     186            [ + ]:        248 :                 if(typeof callback === 'function'){
     187                 :         32 :                         this.addEventListener('loadstart', callback);
     188                 :         32 :                         xmlHttpRequestEventTarget.get(this)['onloadstart'] = callback;
     189                 :         32 :                 }
     190                 :        248 :         }
     191                 :        348 : 
     192                 :        348 :         /**
     193                 :        348 :          * @member   {function} onprogress
     194                 :        348 :          * @memberof module:whatwg-xhr~XMLHttpRequestEventTarget
     195                 :        348 :          * @instance
     196                 :        348 :          * @desc     Get/Set the event handler fired whenever the 'progress' event is emitted.
     197                 :        348 :          */
     198            [ + ]:        348 :         get onprogress(){ return xmlHttpRequestEventTarget.get(this)['onprogress']; }
     199                 :        348 : 
     200            [ + ]:        348 :         set onprogress(callback){
     201                 :        135 :                 this.removeEventListener('progress', xmlHttpRequestEventTarget.get(this)['onprogress']);
     202                 :        135 :                 xmlHttpRequestEventTarget.get(this)['onprogress'] = null;
     203                 :        135 : 
     204            [ + ]:        135 :                 if(typeof callback === 'function'){
     205                 :         19 :                         this.addEventListener('progress', callback);
     206                 :         19 :                         xmlHttpRequestEventTarget.get(this)['onprogress'] = callback;
     207                 :         19 :                 }
     208                 :        135 :         }
     209                 :        348 : 
     210                 :        348 :         /**
     211                 :        348 :          * @member   {function} onabort
     212                 :        348 :          * @memberof module:whatwg-xhr~XMLHttpRequestEventTarget
     213                 :        348 :          * @instance
     214                 :        348 :          * @desc     Get/Set the event handler fired whenever the 'abort' event is emitted.
     215                 :        348 :          */
     216            [ + ]:        348 :         get onabort(){ return xmlHttpRequestEventTarget.get(this)['onabort']; }
     217                 :        348 : 
     218            [ + ]:        348 :         set onabort(callback){
     219                 :        105 :                 this.removeEventListener('abort', xmlHttpRequestEventTarget.get(this)['onabort']);
     220                 :        105 :                 xmlHttpRequestEventTarget.get(this)['onabort'] = null;
     221                 :        105 : 
     222            [ + ]:        105 :                 if(typeof callback === 'function'){
     223                 :          3 :                         this.addEventListener('abort', callback);
     224                 :          3 :                         xmlHttpRequestEventTarget.get(this)['onabort'] = callback;
     225                 :          3 :                 }
     226                 :        105 :         }
     227                 :        348 : 
     228                 :        348 :         /**
     229                 :        348 :          * @member   {function} onerror
     230                 :        348 :          * @memberof module:whatwg-xhr~XMLHttpRequestEventTarget
     231                 :        348 :          * @instance
     232                 :        348 :          * @desc     Get/Set the event handler fired whenever the 'error' event is emitted.
     233                 :        348 :          */
     234            [ + ]:        348 :         get onerror(){ return xmlHttpRequestEventTarget.get(this)['onerror']; }
     235                 :        348 : 
     236            [ + ]:        348 :         set onerror(callback){
     237                 :        354 :                 this.removeEventListener('error', xmlHttpRequestEventTarget.get(this)['onerror']);
     238                 :        354 :                 xmlHttpRequestEventTarget.get(this)['onerror'] = null;
     239                 :        354 : 
     240            [ + ]:        354 :                 if(typeof callback === 'function'){
     241                 :         32 :                         this.addEventListener('error', callback);
     242                 :         32 :                         xmlHttpRequestEventTarget.get(this)['onerror'] = callback;
     243                 :         32 :                 }
     244                 :        354 :         }
     245                 :        348 : 
     246                 :        348 :         /**
     247                 :        348 :          * @member   {function} onload
     248                 :        348 :          * @memberof module:whatwg-xhr~XMLHttpRequestEventTarget
     249                 :        348 :          * @instance
     250                 :        348 :          * @desc     Get/Set the event handler fired whenever the 'load' event is emitted.
     251                 :        348 :          */
     252            [ + ]:        348 :         get onload(){ return xmlHttpRequestEventTarget.get(this)['onload']; }
     253                 :        348 : 
     254            [ + ]:        348 :         set onload(callback){
     255                 :        406 :                 this.removeEventListener('load', xmlHttpRequestEventTarget.get(this)['onload']);
     256                 :        406 :                 xmlHttpRequestEventTarget.get(this)['onload'] = null;
     257                 :        406 : 
     258            [ + ]:        406 :                 if(typeof callback === 'function'){
     259                 :         71 :                         this.addEventListener('load', callback);
     260                 :         71 :                         xmlHttpRequestEventTarget.get(this)['onload'] = callback;
     261                 :         71 :                 }
     262                 :        406 :         }
     263                 :        348 : 
     264                 :        348 :         /**
     265                 :        348 :          * @member   {function} ontimeout
     266                 :        348 :          * @memberof module:whatwg-xhr~XMLHttpRequestEventTarget
     267                 :        348 :          * @instance
     268                 :        348 :          * @desc     Get/Set the event handler fired whenever the 'timeout' event is emitted.
     269                 :        348 :          */
     270            [ + ]:        348 :         get ontimeout(){ return xmlHttpRequestEventTarget.get(this)['ontimeout']; }
     271                 :        348 : 
     272            [ + ]:        348 :         set ontimeout(callback){
     273                 :        106 :                 this.removeEventListener('timeout', xmlHttpRequestEventTarget.get(this)['ontimeout']);
     274                 :        106 :                 xmlHttpRequestEventTarget.get(this)['ontimeout'] = null;
     275                 :        106 : 
     276            [ + ]:        106 :                 if(typeof callback === 'function'){
     277                 :          3 :                         this.addEventListener('timeout', callback);
     278                 :          3 :                         xmlHttpRequestEventTarget.get(this)['ontimeout'] = callback;
     279                 :          3 :                 }
     280                 :        106 :         }
     281                 :        348 : 
     282                 :        348 :         /**
     283                 :        348 :          * @member   {function} onloadend
     284                 :        348 :          * @memberof module:whatwg-xhr~XMLHttpRequestEventTarget
     285                 :        348 :          * @instance
     286                 :        348 :          * @desc     Get/Set the event handler fired whenever the 'loadend' event is emitted.
     287                 :        348 :          */
     288            [ + ]:        348 :         get onloadend(){ return xmlHttpRequestEventTarget.get(this)['onloadend']; }
     289                 :        348 : 
     290            [ + ]:        348 :         set onloadend(callback){
     291                 :        380 :                 this.removeEventListener('loadend', xmlHttpRequestEventTarget.get(this)['onloadend']);
     292                 :        380 :                 xmlHttpRequestEventTarget.get(this)['onloadend'] = null;
     293                 :        380 : 
     294            [ + ]:        380 :                 if(typeof callback === 'function'){
     295                 :         43 :                         this.addEventListener('loadend', callback);
     296                 :         43 :                         xmlHttpRequestEventTarget.get(this)['onloadend'] = callback;
     297                 :         43 :                 }
     298                 :        380 :         }
     299                 :        348 : }
     300                 :        348 : 
     301                 :        348 : /**
     302                 :        348 :  * XMLHttpRequest Living Standard — Last Updated 20 February 2023
     303                 :        348 :  * url: https://xhr.spec.whatwg.org/#interface-xmlhttprequest
     304                 :        348 :  *
     305                 :        348 :  * interface XMLHttpRequestUpload : XMLHttpRequestEventTarget {
     306                 :        348 :  * };
     307                 :        348 :  *
     308                 :        348 :  * @class     XMLHttpRequestUpload
     309                 :        348 :  * @extends   module:whatwg-xhr~XMLHttpRequestEventTarget
     310                 :        348 :  * @desc      Interface that represents the upload process for a specific XMLHttpRequest.
     311                 :        348 :  */
     312                 :        348 : class XMLHttpRequestUpload extends XMLHttpRequestEventTarget{
     313            [ + ]:        348 :         constructor(){
     314                 :        742 :                 super();
     315                 :        742 :                 if(!allowXMLHttpRequestUploadConstructor)
     316            [ - ]:        742 :                         throw new TypeError(`Illegal constructor.`);
     317                 :        742 :         }
     318                 :        348 : }
     319                 :        348 : 
     320                 :        348 : /**
     321                 :        348 :  * XMLHttpRequest Living Standard — Last Updated 20 February 2023
     322                 :        348 :  * url: https://xhr.spec.whatwg.org/#interface-xmlhttprequest
     323                 :        348 :  *
     324                 :        348 :  * enum XMLHttpRequestResponseType{
     325                 :        348 :  *   "",
     326                 :        348 :  *   "arraybuffer",
     327                 :        348 :  *   "blob",
     328                 :        348 :  *   "document",
     329                 :        348 :  *   "json",
     330                 :        348 :  *   "text"
     331                 :        348 :  * };
     332                 :        348 :  *
     333                 :        348 :  * @const {object} XMLHttpRequestResponseType
     334                 :        348 :  * @desc  Enumerated set of response types.
     335                 :        348 :  */
     336                 :        348 : const XMLHttpRequestResponseType = {
     337                 :        348 :         '': null,
     338                 :        348 :         'arraybuffer': null,
     339                 :        348 :         'blob': null,
     340                 :        348 :         'document': null,
     341                 :        348 :         'json': null,
     342                 :        348 :         'text': null,
     343                 :        348 : };
     344                 :        348 : 
     345                 :        348 : Object.preventExtensions(XMLHttpRequestResponseType);
     346                 :        348 : Object.freeze(XMLHttpRequestResponseType);
     347                 :        348 : 
     348                 :        348 : /**
     349                 :        348 :  * XMLHttpRequest Living Standard — Last Updated 20 February 2023
     350                 :        348 :  * url: https://xhr.spec.whatwg.org/#interface-xmlhttprequest
     351                 :        348 :  *
     352                 :        348 :  * interface XMLHttpRequest : XMLHttpRequestEventTarget{
     353                 :        348 :  *   constructor();
     354                 :        348 :  *
     355                 :        348 :  *   // event handler
     356                 :        348 :  *   attribute EventHandler onreadystatechange;
     357                 :        348 :  *
     358                 :        348 :  *   // states
     359                 :        348 :  *   const unsigned short UNSENT = 0;
     360                 :        348 :  *   const unsigned short OPENED = 1;
     361                 :        348 :  *   const unsigned short HEADERS_RECEIVED = 2;
     362                 :        348 :  *   const unsigned short LOADING = 3;
     363                 :        348 :  *   const unsigned short DONE = 4;
     364                 :        348 :  *
     365                 :        348 :  *   readonly attribute unsigned short readyState;
     366                 :        348 :  *
     367                 :        348 :  *   // request
     368                 :        348 :  *   undefined open(ByteString method, USVString url);
     369                 :        348 :  *   undefined open(ByteString method, USVString url, boolean async,
     370                 :        348 :  *                  optional USVString? username = null, optional USVString? password = null);
     371                 :        348 :  *   undefined setRequestHeader(ByteString name, ByteString value);
     372                 :        348 :  *
     373                 :        348 :  *   attribute unsigned long timeout;
     374                 :        348 :  *   attribute boolean       withCredentials;
     375                 :        348 :  *
     376                 :        348 :  *   [SameObject] readonly attribute XMLHttpRequestUpload upload;
     377                 :        348 :  *
     378                 :        348 :  *   undefined send(optional (Document or XMLHttpRequestBodyInit)? body = null);
     379                 :        348 :  *   undefined abort();
     380                 :        348 :  *
     381                 :        348 :  *   // response
     382                 :        348 :  *   readonly attribute USVString      responseURL;
     383                 :        348 :  *   readonly attribute unsigned short status;
     384                 :        348 :  *   readonly attribute ByteString     statusText;
     385                 :        348 :  *
     386                 :        348 :  *   ByteString  getResponseHeader(ByteString name);
     387                 :        348 :  *   ByteString  getAllResponseHeaders();
     388                 :        348 :  *   undefined   overrideMimeType(DOMString mime);
     389                 :        348 :  *
     390                 :        348 :  *   attribute XMLHttpRequestResponseType responseType;
     391                 :        348 :  *
     392                 :        348 :  *   readonly attribute any       response;
     393                 :        348 :  *   readonly attribute USVString responseText;
     394                 :        348 :  *
     395                 :        348 :  *   [Exposed=Window] readonly attribute Document? responseXML;
     396                 :        348 :  * };
     397                 :        348 :  *
     398                 :        348 :  * @class     XMLHttpRequest
     399                 :        348 :  * @extends   module:whatwg-xhr~XMLHttpRequestEventTarget
     400                 :        348 :  * @static
     401                 :        348 :  * @desc      Interface that represents the objects used to interact with a server.
     402                 :        348 :  */
     403                 :        348 : export class XMLHttpRequest extends XMLHttpRequestEventTarget{
     404            [ + ]:        348 :         constructor(){
     405                 :        742 :                 super();
     406                 :        742 : 
     407                 :        742 :                 const requestData = {};
     408                 :        742 : 
     409                 :        742 :                 // event handler
     410                 :        742 :                 requestData['onreadystatechange'] = null;              // xhr.spec. attribute EventHandler
     411                 :        742 : 
     412                 :        742 :                 // states - An XMLHttpRequest object has an associated:
     413                 :        742 :                 requestData['readyState'] = this.UNSENT;               // xhr.spec. readonly attribute unsigned short state: initially unsent.
     414                 :        742 : 
     415                 :        742 :                 // requesAn XMLHttpRequest object has an associated:
     416                 :        742 :                 requestData['timeout'] = 0;                            // xhr.spec. attribute unsigned long timeout: An unsigned integer, initially 0.
     417                 :        742 :                 requestData['withCredentials'] = false;                // xhr.spec. attribute boolean cross-origin credentials: A boolean, initially false.
     418                 :        742 : 
     419                 :        742 :                 allowXMLHttpRequestUploadConstructor = true;           //
     420                 :        742 :                 requestData['upload'] = new XMLHttpRequestUpload();    // xhr.spec. readonly attribute XMLHttpRequestUpload upload object: an XMLHttpRequestUpload object.
     421                 :        742 :                 allowXMLHttpRequestUploadConstructor = false;          //
     422                 :        742 : 
     423                 :        742 :                 // response - An XMLHttpRequest object has an associated:
     424                 :        742 :                 requestData['status'    ] = 0;                 // xhr.spec. readonly attribute unsigned short status;
     425                 :        742 :                 requestData['statusText'] = '';                // xhr.spec. readonly attribute ByteString statusText;
     426                 :        742 : 
     427                 :        742 :                 requestData['response'    ] = '';              // xhr.spec. readonly attribute any response: a response, initially a network error.
     428                 :        742 :                 requestData['responseText'] = '';              // xhr.spec. readonly attribute ByteString responseText.
     429                 :        742 :                 requestData['responseType'] = '';              // xhr.spec. response type: one of "", "arraybuffer", "blob", "document", "json", and "text"; initially "".
     430                 :        742 :                 requestData['responseURL' ] = '';              // xhr.spec. readonly attribute USVString responseURL;
     431                 :        742 :                 requestData['responseXML' ] = null;            // xhr.spec. [Exposed=Window] readonly attribute Document? responseXML;
     432                 :        742 : 
     433                 :        742 :                 // associated data - An XMLHttpRequest object has an associated:
     434                 :        742 :                 requestData['sendFlag'] = false;               // xhr.spec. send() flag: a flag, initially unset.
     435                 :        742 :                 requestData['method'  ] = '';                  // xhr.spec. request method: a method.
     436                 :        742 :                 requestData['url'     ] = null;                // xhr.spec. request URL: A URL.
     437                 :        742 :                 requestData['async'   ] = true;                // xhr.spec. synchronous flag: a flag, initially unset.
     438                 :        742 : 
     439                 :        742 :                 requestData['user'    ] = null;
     440                 :        742 :                 requestData['password'] = null;
     441                 :        742 : 
     442                 :        742 :                 requestData['requestHeaders'    ] = {};        // xhr.spec. author request headers: a header list, initially empty.
     443                 :        742 :                 requestData['requestHeadersCase'] = {};
     444                 :        742 : 
     445                 :        742 :                 requestData['requestBody'       ] = null;      // xhr.spec. request body: initially null.
     446                 :        742 :                 requestData['uploadCompleteFlag'] = false;     // xhr.spec. upload complete flag: a flag, initially unset.
     447                 :        742 :                 requestData['uploadListenerFlag'] = false;     // xhr.spec. upload listener flag: a flag, initially unset.
     448                 :        742 :                 requestData['timeoutFlag'       ] = false;     // xhr.spec. timeout flag: a flag, initially unset.
     449                 :        742 :                 requestData['receivedBytes'     ] = Buffer.alloc(0);   // xhr.spec. received bytes: a byte sequence, initially the empty byte sequence.
     450                 :        742 :                 requestData['responseObject'    ] = null;      // xhr.spec. response object: an object, failure, or null, initially null.
     451                 :        742 :                 requestData['fetchController'   ] = null;      // xhr.spec. fetch controller: a fetch controller, initially a new fetch controller.
     452                 :        742 :                 requestData['overrideMimeType'  ] = null;      // xhr.spec. A MIME type or null, initially null. Can get a value when overrideMimeType() is invoked.
     453                 :        742 : 
     454                 :        742 :                 requestData['_redirectCount'       ] = 0;     // fetch.spec.2.2.5. A request has an associated redirect count. Unless stated otherwise, it is zero.
     455                 :        742 :                 requestData['_responseAbort'       ] = false; // fetch.spec.2.2.6. A response can have an associated aborted flag, which is initially unset.
     456                 :        742 :                 requestData['_responseNetworkError'] = false;
     457                 :        742 :                 requestData['_responseBody'        ] = null;  // fetch.spec.2.2.6. A response has an associated body (null or a body). Unless stated otherwise it is null.
     458                 :        742 : 
     459                 :        742 :                 xmlHttpRequest.set(this, requestData);
     460                 :        742 :         }
     461                 :        348 : 
     462                 :        348 :         /**
     463                 :        348 :          * @member   {function} onreadystatechange
     464                 :        348 :          * @memberof module:whatwg-xhr.XMLHttpRequest
     465                 :        348 :          * @instance
     466                 :        348 :          * @desc     Get/Set the event handler fired whenever there's change in readyState.
     467                 :        348 :          */
     468                 :        348 :         get onreadystatechange(){ return xmlHttpRequest.get(this)['onreadystatechange']; }
     469                 :        348 : 
     470            [ + ]:        348 :         set onreadystatechange(callback){
     471                 :        221 :                 this.removeEventListener('readystatechange', xmlHttpRequest.get(this)['onreadystatechange']);
     472                 :        221 :                 xmlHttpRequest.get(this)['onreadystatechange'] = null;
     473                 :        221 : 
     474            [ + ]:        221 :                 if(typeof callback === 'function'){
     475                 :        137 :                         this.addEventListener('readystatechange', callback);
     476                 :        137 :                         xmlHttpRequest.get(this)['onreadystatechange'] = callback;
     477                 :        137 :                 }
     478                 :        221 :         }
     479                 :        348 : 
     480                 :        348 :         /**
     481                 :        348 :          * @member   {number} readyState
     482                 :        348 :          * @memberof module:whatwg-xhr.XMLHttpRequest
     483                 :        348 :          * @readonly
     484                 :        348 :          * @instance
     485                 :        348 :          * @desc     Get the state an XMLHttpRequest client is in.
     486                 :        348 :          */
     487            [ + ]:        348 :         get readyState(){ return xmlHttpRequest.get(this)['readyState']; }
     488                 :        348 : 
     489                 :        348 :         /**
     490                 :        348 :          * @member   {object} upload
     491                 :        348 :          * @memberof module:whatwg-xhr.XMLHttpRequest
     492                 :        348 :          * @readonly
     493                 :        348 :          * @instance
     494                 :        348 :          * @desc     Get an XMLHttpRequestUpload object that can be observed to monitor an upload's progress.
     495                 :        348 :          */
     496            [ + ]:        348 :         get upload(){ return xmlHttpRequest.get(this)['upload']; }
     497                 :        348 : 
     498                 :        348 :         /**
     499                 :        348 :          * @member   {number} status
     500                 :        348 :          * @memberof module:whatwg-xhr.XMLHttpRequest
     501                 :        348 :          * @readonly
     502                 :        348 :          * @instance
     503                 :        348 :          * @desc     Get the numerical HTTP status code of the server response.
     504                 :        348 :          */
     505            [ + ]:        348 :         get status(){ return xmlHttpRequest.get(this)['status']; }
     506                 :        348 : 
     507                 :        348 :         /**
     508                 :        348 :          * @member   {string} statusText
     509                 :        348 :          * @memberof module:whatwg-xhr.XMLHttpRequest
     510                 :        348 :          * @readonly
     511                 :        348 :          * @instance
     512                 :        348 :          * @desc     Get the HTTP status message of the server response.
     513                 :        348 :          */
     514            [ + ]:        348 :         get statusText(){ return xmlHttpRequest.get(this)['statusText']; }
     515                 :        348 : 
     516                 :        348 :         /**
     517                 :        348 :          * XMLHttpRequest Living Standard — Last Updated 20 February 2023
     518                 :        348 :          * url: https://xhr.spec.whatwg.org/#the-response-attribute
     519                 :        348 :          *
     520                 :        348 :          * client.response
     521                 :        348 :          *
     522                 :        348 :          *   Returns the response body.
     523                 :        348 :          *
     524                 :        348 :          * The response getter steps are:
     525                 :        348 :          * 1. If this’s response type is the empty string or "text", then:
     526                 :        348 :          *     1. If this’s state is not loading or done, then return the empty string.
     527                 :        348 :          *     2. Return the result of getting a text response for this.
     528                 :        348 :          * 2. If this’s state is not done, then return null.
     529                 :        348 :          * 3. If this’s response object is failure, then return null.
     530                 :        348 :          * 4. If this’s response object is non-null, then return it.
     531                 :        348 :          * 5. If this’s response type is "arraybuffer", then set this’s response object to a new ArrayBuffer object representing this’s received bytes.
     532                 :        348 :          *    If this throws an exception, then set this’s response object to failure and return null.
     533                 :        348 :          *    Note: Allocating an ArrayBuffer object is not guaranteed to succeed. [ECMASCRIPT]
     534                 :        348 :          * 6. Otherwise, if this’s response type is "blob", set this’s response object to a new Blob object representing this’s received bytes with type
     535                 :        348 :          *    set to the result of get a final MIME type for this.
     536                 :        348 :          * 7. Otherwise, if this’s response type is "document", set a document response for this.
     537                 :        348 :          * 8. Otherwise:
     538                 :        348 :          *    1. Assert: this’s response type is "json".
     539                 :        348 :          *    2. If this’s response’s body is null, then return null.
     540                 :        348 :          *    3. Let jsonObject be the result of running parse JSON from bytes on this’s received bytes. If that threw an exception, then return null.
     541                 :        348 :          *    4. Set this’s response object to jsonObject.
     542                 :        348 :          * 9. Return this’s response object.
     543                 :        348 :          *
     544                 :        348 :          * @member   {ArrayBuffer|Blob|Document|object|string} response
     545                 :        348 :          * @memberof module:whatwg-xhr.XMLHttpRequest
     546                 :        348 :          * @readonly
     547                 :        348 :          * @instance
     548                 :        348 :          * @desc     Get the response's body content received from a server following a request being sent.
     549                 :        348 :          */
     550            [ + ]:        348 :         get response(){
     551                 :        294 : 
     552                 :        294 :                 const requestData = xmlHttpRequest.get(this);
     553                 :        294 : 
     554                 :        294 :                 // xhr.spec.1. If this’s response type is the empty string or "text", then:
     555       [ + ][ + ]:        294 :                 if(requestData['responseType'] === '' || requestData['responseType'] === 'text'){
     556                 :         57 : 
     557                 :         57 :                         // xhr.spec.1.1. If this’s state is not loading or done, then return the empty string.
     558            [ + ]:         57 :                         if(requestData['readyState'] !== this.LOADING && requestData['readyState'] !== this.DONE){
     559                 :         19 :                                 return '';
     560            [ + ]:         19 :                         }
     561                 :         38 : 
     562                 :         38 :                         // xhr.spec.1.2. Return the result of getting a text response for this.
     563                 :         38 :                         return getTextResponse.call(this);
     564            [ + ]:         38 :                 }
     565                 :         28 : 
     566                 :         28 :                 // xhr.spec.2. If this’s state is not done, then return null.
     567                 :         28 :                 if(requestData['readyState'] !== this.DONE)
     568       [ + ][ - ]:        294 :                         return null;
     569                 :         28 : 
     570                 :         28 :                 // xhr.spec.3. If this’s response object is failure, then return null.
     571                 :         28 :                 if(requestData['responseObject'] === 'failure')
     572       [ + ][ - ]:        294 :                         return null;
     573                 :         28 : 
     574                 :         28 :                 // xhr.spec.4. If this’s response object is non-null, then return it.
     575                 :         28 :                 if(requestData['responseObject'] !== null)
     576       [ + ][ + ]:        294 :                         return requestData['responseObject'];
     577                 :         13 : 
     578                 :         13 :                 // xhr.spec.5. If this’s response type is "arraybuffer"
     579            [ + ]:        294 :                 if(requestData['responseType'] === 'arraybuffer'){
     580                 :          1 :                         // xhr.spec.5. set this’s response object to a new ArrayBuffer object representing this’s received bytes.
     581                 :          1 :                         try{
     582                 :          1 :                                 requestData['responseObject'] = new Uint8Array(requestData['receivedBytes']).buffer;
     583                 :          1 :                         }
     584            [ - ]:          1 :                         catch(e){
     585                 :          0 :                                 // xhr.spec.5. If this throws an exception, then set this’s response object to failure and return null.
     586                 :          0 :                                 requestData['responseObject'] = 'failure';
     587                 :          0 :                                 return null;
     588                 :          0 :                         }
     589            [ + ]:          1 :                 }
     590                 :         12 :                 else
     591                 :         12 :                 // xhr.spec.6. Otherwise, if this’s response type is "blob",
     592            [ + ]:         12 :                 if(requestData['responseType'] === 'blob'){
     593                 :          2 : 
     594                 :          2 :                         // xhr.spec.6. set this’s response object to a new Blob object representing this’s received bytes with type
     595                 :          2 :                         // set to the result of get a final MIME type for this.
     596                 :          2 : 
     597                 :          2 :                         if(!(requestData['responseObject'] instanceof Blob)){
     598                 :          2 : 
     599                 :          2 :                                 requestData['responseObject'] = new Blob([requestData['receivedBytes']], {
     600                 :          2 :                                                 endings: 'native',
     601                 :          2 :                                                 type: getFinalMimeType.call(this)
     602                 :          2 :                                         });
     603                 :          2 :                         }
     604            [ + ]:          2 :                 }
     605                 :         10 :                 else
     606                 :         10 :                 // xhr.spec.7. Otherwise, if this’s response type is "document", set a document response for this.
     607            [ - ]:         10 :                 if(requestData['responseType'] === 'document'){
     608                 :          0 :                         // @todo...
     609                 :          0 :                 }
     610                 :         10 :                 // xhr.spec.8. Otherwise:
     611                 :         10 :                 else{
     612                 :         10 :                         // xhr.spec.8.1. Assert: this’s response type is "json".
     613                 :         10 :                         if(requestData['responseType'] === 'json'){
     614                 :         10 : 
     615                 :         10 :                                 // xhr.spec.8.2. If this’s response’s body is null, then return null.
     616                 :         10 :                                 // author. if(requestData['_responseBody'] === null)
     617                 :         10 :                                 if(requestData['receivedBytes'].length === 0)
     618       [ + ][ + ]:         10 :                                         return null;
     619                 :          6 : 
     620                 :          6 :                                 // xhr.spec.8.3. Let jsonObject be the result of running parse JSON from bytes on this’s received bytes.
     621                 :          6 :                                 // If that threw an exception, then return null.
     622                 :          6 :                                 try{
     623                 :          6 :                                         let jsonObject = JSON.parse(requestData['receivedBytes']);
     624                 :          6 : 
     625                 :          6 :                                         // xhr.spec.8.4. Set this’s response object to jsonObject.
     626                 :          6 :                                         requestData['responseObject'] = jsonObject;
     627            [ + ]:         10 :                                 }catch(e){
     628                 :          4 :                                         return null;
     629                 :          4 :                                 }
     630                 :         10 :                         }
     631            [ + ]:         10 :                 }
     632                 :          5 :                 // xhr.spec.9. Return this’s response object.
     633                 :          5 :                 return requestData['responseObject'];
     634                 :        294 :         }
     635                 :        348 : 
     636                 :        348 :         /**
     637                 :        348 :          * XMLHttpRequest Living Standard — Last Updated 20 February 2023
     638                 :        348 :          * url: https://xhr.spec.whatwg.org/#the-responsetext-attribute
     639                 :        348 :          *
     640                 :        348 :          * client.responseText
     641                 :        348 :          *
     642                 :        348 :          *    Returns response as text.
     643                 :        348 :          *    Throws an "InvalidStateError" DOMException if responseType is not the empty string or "text".
     644                 :        348 :          *
     645                 :        348 :          * The responseText getter steps are:
     646                 :        348 :          * 1. If this’s response type is not the empty string or "text", then throw an "InvalidStateError" DOMException.
     647                 :        348 :          * 2. If this’s state is not loading or done, then return the empty string.
     648                 :        348 :          * 3. Return the result of <getting a text response> for this.
     649                 :        348 :          *
     650                 :        348 :          * @member   {string} responseText
     651                 :        348 :          * @memberof module:whatwg-xhr.XMLHttpRequest
     652                 :        348 :          * @readonly
     653                 :        348 :          * @instance
     654                 :        348 :          * @desc     Get the text received from a server following a request being sent.
     655                 :        348 :          */
     656            [ + ]:        348 :         get responseText(){
     657                 :        465 :                 const requestData = xmlHttpRequest.get(this);
     658                 :        465 : 
     659                 :        465 :                 // xhr.spec.1. If this’s response type is not the empty string or "text", then throw an "InvalidStateError" DOMException.
     660            [ + ]:        465 :                 if(requestData['responseType'] !== '' && requestData['responseType'] !== 'text')
     661            [ - ]:        465 :                         throw new DOMException(`XMLHttpRequest.responseText getter: responseText is only available if responseType is '' or 'text'.`, 'InvalidAccessError');
     662                 :        465 : 
     663                 :        465 :                 // xhr.spec.2. If this’s state is not loading or done, then return the empty string.
     664       [ + ][ + ]:        465 :                 if(requestData['readyState'] !== this.LOADING && requestData['readyState'] !== this.DONE){
     665                 :          3 :                         return '';
     666            [ + ]:          3 :                 }
     667                 :        253 : 
     668                 :        253 :                 // xhr.spec.3. Return the result of <getting a text response> for this.
     669                 :        253 :                 return getTextResponse.call(this);
     670                 :        465 :         }
     671                 :        348 : 
     672                 :        348 :         /**
     673                 :        348 :          * XMLHttpRequest Living Standard — Last Updated 20 February 2023
     674                 :        348 :          * url: https://xhr.spec.whatwg.org/#the-responsetype-attribute
     675                 :        348 :          *
     676                 :        348 :          * client.responseType[ = value ]
     677                 :        348 :          *
     678                 :        348 :          *   Returns the response type.
     679                 :        348 :          *   Can be set to change the response type. Values are: the empty string (default), "arraybuffer", "blob", "document", "json", and "text".
     680                 :        348 :          *   When set: setting to "document" is ignored if the current global object is not a Window object.
     681                 :        348 :          *   When set: throws an "InvalidStateError" DOMException if state is loading or done.
     682                 :        348 :          *   When set: throws an "InvalidAccessError" DOMException if the synchronous flag is set and the current global object is a Window object.
     683                 :        348 :          *
     684                 :        348 :          * The responseType getter steps are to return this’s response type.
     685                 :        348 :          * The responseType setter steps are:
     686                 :        348 :          * 1. If the current global object is not a Window object and the given value is "document", then return.
     687                 :        348 :          * 2. If this’s state is loading or done, then throw an "InvalidStateError" DOMException.
     688                 :        348 :          * 3. If the current global object is a Window object and this’s synchronous flag is set, then throw an "InvalidAccessError" DOMException.
     689                 :        348 :          * 4. Set this’s response type to the given value.
     690                 :        348 :          *
     691                 :        348 :          * @member   {string} responseType
     692                 :        348 :          * @memberof module:whatwg-xhr.XMLHttpRequest
     693                 :        348 :          * @instance
     694                 :        348 :          * @desc     Get/Set an enumerated string value specifying the type of data contained in the response.
     695                 :        348 :          */
     696            [ + ]:        348 :         get responseType(){
     697                 :        450 :                 return xmlHttpRequest.get(this)['responseType'];
     698                 :        450 :         }
     699                 :        348 : 
     700            [ + ]:        348 :         set responseType(type){
     701            [ + ]:         39 :                 if(String(type) in XMLHttpRequestResponseType){
     702                 :         31 :                         const requestData = xmlHttpRequest.get(this);
     703                 :         31 : 
     704                 :         31 :                         // xhr.spec.3. If the current global object is a Window object and this’s synchronous flag is set,
     705                 :         31 :                         // then throw an "InvalidAccessError" DOMException.
     706                 :         31 : 
     707                 :         31 :                         // @author. xhr.spec.3. will also be applicable to main thread
     708                 :         31 :                         if(threads.isMainThread){
     709                 :         31 :                                 if(!requestData['async'])
     710            [ - ]:         31 :                                         throw new DOMException(
     711                 :          0 :                                                                 `XMLHttpRequest.responseType setter: synchronous XMLHttpRequests do not support timeout and responseType`,
     712                 :          0 :                                                                 'InvalidAccessError'
     713                 :          0 :                                         );
     714            [ - ]:         31 :                         }
     715                 :          0 :                         else{
     716                 :          0 :                                 // xhr.spec.1. If the current global object is not a Window object and the given value is "document", then return.
     717                 :          0 :                                 if(String(type).toLowerCase() === 'document')
     718                 :          0 :                                         return;
     719                 :          0 :                         }
     720                 :         31 : 
     721                 :         31 :                         // xhr.spec.2. If this’s state is loading or done, then throw an "InvalidStateError" DOMException.
     722                 :         31 :                         if(requestData['readyState'] === this.LOADING || requestData['readyState'] === this.DONE)
     723            [ - ]:         31 :                                 throw new DOMException(`XMLHttpRequest.responseType setter: Cannot set 'responseType' property on XMLHttpRequest after 'send()' (when its state is LOADING or DONE).`, 'InvalidStateError');
     724                 :         31 : 
     725                 :         31 :                         requestData['responseType'] = String(type).toLowerCase();
     726                 :         31 :                 }
     727                 :         39 :         }
     728                 :        348 : 
     729                 :        348 :         /**
     730                 :        348 :          * XMLHttpRequest Living Standard — Last Updated 20 February 2023
     731                 :        348 :          * url: https://xhr.spec.whatwg.org/#the-responsexml-attribute
     732                 :        348 :          *
     733                 :        348 :          * The responseXML getter
     734                 :        348 :          *
     735                 :        348 :          * client . responseXML
     736                 :        348 :          *
     737                 :        348 :          *  Returns the response as document.
     738                 :        348 :          *  Throws an "InvalidStateError" DOMException if responseType is not the empty string or "document".
     739                 :        348 :          *
     740                 :        348 :          * The responseXML getter steps are:
     741                 :        348 :          * 1. If this’s response type is not the empty string or "document", then throw an "InvalidStateError" DOMException.
     742                 :        348 :          * 2. If this’s state is not done, then return null.
     743                 :        348 :          * 3. Assert: this’s response object is not failure.
     744                 :        348 :          * 4. If this’s response object is non-null, then return it.
     745                 :        348 :          * 5. Set a document response for this.
     746                 :        348 :          * 6. Return this’s response object.
     747                 :        348 :          *
     748                 :        348 :          * @member   {Document|null} responseXML
     749                 :        348 :          * @memberof module:whatwg-xhr.XMLHttpRequest
     750                 :        348 :          * @readonly
     751                 :        348 :          * @instance
     752                 :        348 :          * @desc     Get a Document containing the HTML or XML retrieved by the request, or null.
     753                 :        348 :          */
     754            [ + ]:        348 :         get responseXML(){
     755                 :        216 : 
     756                 :        216 :                 const requestData = xmlHttpRequest.get(this);
     757                 :        216 : 
     758                 :        216 :                 // xhr.spec.1. If this’s response type is not the empty string or "document", then throw an "InvalidStateError" DOMException.
     759       [ - ][ - ]:        216 :                 if(this.responseType !== '' && this.responseType !== 'document'){
     760                 :          0 :                         throw new DOMException(
     761                 :          0 :                                 `XMLHttpRequest.responseXML getter: responseXML is only available if responseType is '' or 'document'.`, 'InvalidStateError');  // firefox 102
     762                 :          0 :                 }
     763                 :        216 : 
     764                 :        216 :                 // xhr.spec.2. If this’s state is not done, then return null.
     765                 :        216 :                 if(xmlHttpRequest.get(this)['readyState'] !== this.DONE)
     766       [ + ][ + ]:        216 :                         return null;
     767                 :          4 : 
     768                 :          4 :                 // xhr.spec.3. Assert: this’s response object is not failure.
     769                 :          4 :                 if(requestData['responseObject'] === 'failure')
     770       [ + ][ - ]:        216 :                         return null;
     771                 :          4 : 
     772                 :          4 :                 // xhr.spec.4. If this’s response object is non-null, then return it.
     773                 :          4 :                 if(requestData['responseObject'] !== null)
     774       [ + ][ - ]:        216 :                         return requestData['responseObject'];
     775                 :          4 : 
     776                 :          4 :                 // xhr.spec.5. Set a document response for this.
     777                 :          4 :                 setDocumentResponse.call(this);
     778                 :          4 : 
     779                 :          4 :                 // xhr.spec.6. Return this’s response object.
     780                 :          4 :                 return xmlHttpRequest.get(this)['responseObject'];
     781                 :        216 :         }
     782                 :        348 : 
     783                 :        348 :         /**
     784                 :        348 :          * XMLHttpRequest Living Standard — Last Updated 20 February 2023
     785                 :        348 :          * url: https://xhr.spec.whatwg.org/#the-responseurl-attribute
     786                 :        348 :          *
     787                 :        348 :          * The responseURL getter
     788                 :        348 :          *
     789                 :        348 :          * The responseURL getter steps are to return the empty string if this’s response’s URL is null;
     790                 :        348 :          * otherwise its serialization with the exclude fragment flag set.
     791                 :        348 :          *
     792                 :        348 :          * @member   {string} responseURL
     793                 :        348 :          * @memberof module:whatwg-xhr.XMLHttpRequest
     794                 :        348 :          * @readonly
     795                 :        348 :          * @instance
     796                 :        348 :          * @desc     Get the serialized URL of the response or the empty string if the URL is null.
     797                 :        348 :          */
     798            [ + ]:        348 :         get responseURL(){
     799                 :        209 :                 const requestData = xmlHttpRequest.get(this);
     800                 :        209 : 
     801            [ - ]:        209 :                 if(requestData['response'] && requestData['response'].url){
     802                 :          0 :                         return requestData['response'].url.replace(/#.*$/, '');
     803                 :          0 :                 }
     804                 :        209 : 
     805                 :        209 :                 return '';
     806                 :        209 :         }
     807                 :        348 : 
     808                 :        348 :         /**
     809                 :        348 :          * XMLHttpRequest Living Standard — Last Updated 20 February 2023
     810                 :        348 :          * url: https://xhr.spec.whatwg.org/#the-timeout-attribute
     811                 :        348 :          * client.timeout
     812                 :        348 :          *
     813                 :        348 :          *   Can be set to a time in milliseconds. When set to a non-zero value will cause fetching to terminate after the given time has passed.
     814                 :        348 :          *   When the time has passed, the request has not yet completed, and this’s synchronous flag is unset, a timeout event will then be dispatched,
     815                 :        348 :          *   or a "TimeoutError" DOMException will be thrown otherwise (for the send() method).
     816                 :        348 :          *   When set: throws an "InvalidAccessError" DOMException if the synchronous flag is set and the current global object is a Window object.
     817                 :        348 :          *
     818                 :        348 :          * The timeout getter steps are to return this’s timeout.
     819                 :        348 :          * The timeout setter steps are:
     820                 :        348 :          * 1. If the current global object is a Window object and this’s synchronous flag is set, then throw an "InvalidAccessError" DOMException.
     821                 :        348 :          * 2. Set this’s timeout to the given value.
     822                 :        348 :          * Note: This implies that the timeout attribute can be set while fetching is in progress. If that occurs it will still be measured relative
     823                 :        348 :          *       to the start of fetching.
     824                 :        348 :          *
     825                 :        348 :          * @member   {number} timeout
     826                 :        348 :          * @memberof module:whatwg-xhr.XMLHttpRequest
     827                 :        348 :          * @instance
     828                 :        348 :          * @desc     Get/Set an unsigned long representing the number of milliseconds a request can take before automatically being terminated.
     829                 :        348 :          */
     830                 :        348 :         get timeout(){ return xmlHttpRequest.get(this)['timeout']; }
     831                 :        348 : 
     832            [ + ]:        348 :         set timeout(int){
     833                 :          3 : 
     834                 :          3 :                 // xhr.spec.1. If the current global object is a Window object and this’s synchronous flag is set, then throw an "InvalidAccessError" DOMException.
     835            [ - ]:          3 :                 if(globalThis.Window && !xmlHttpRequest.get(this)['async'])
     836            [ - ]:          3 :                         throw new DOMException(`XMLHttpRequest.timeout setter: synchronous XMLHttpRequests do not support timeout and responseType`, 'InvalidAccessError');
     837                 :          3 : 
     838                 :          3 :                 // @author. xhr.spec.1. will also be applicable to main thread
     839                 :          3 :                 if(threads.isMainThread && !xmlHttpRequest.get(this)['async'])
     840            [ - ]:          3 :                         throw new DOMException(`XMLHttpRequest.timeout setter: synchronous XMLHttpRequests do not support timeout and responseType`, 'InvalidAccessError');
     841                 :          3 : 
     842                 :          3 :                 // xhr.spec.2. Set this’s timeout to the given value.
     843            [ - ]:          3 :                 xmlHttpRequest.get(this)['timeout'] = isNaN(int) ? 0 : int;
     844                 :          3 :         }
     845                 :        348 : 
     846                 :        348 :         /**
     847                 :        348 :          * XMLHttpRequest Living Standard — Last Updated 20 February 2023
     848                 :        348 :          * url: https://xhr.spec.whatwg.org/#the-withcredentials-attribute
     849                 :        348 :          * client.withCredentials
     850                 :        348 :          *
     851                 :        348 :          *   True when credentials are to be included in a cross-origin request.
     852                 :        348 :          *   False when they are to be excluded in a cross-origin request and when cookies are to be ignored in its response. Initially false.
     853                 :        348 :          *   When set: throws an "InvalidStateError" DOMException if state is not unsent or opened, or if the send() flag is set.
     854                 :        348 :          *
     855                 :        348 :          * The withCredentials getter steps are to return this’s cross-origin credentials.
     856                 :        348 :          * The withCredentials setter steps are:
     857                 :        348 :          * 1. If this’s state is not unsent or opened, then throw an "InvalidStateError" DOMException.
     858                 :        348 :          * 2. If this’s send() flag is set, then throw an "InvalidStateError" DOMException.
     859                 :        348 :          * 3. Set this’s cross-origin credentials to the given value.
     860                 :        348 :          *
     861                 :        348 :          * @member   {boolean} withCredentials
     862                 :        348 :          * @memberof module:whatwg-xhr.XMLHttpRequest
     863                 :        348 :          * @instance
     864                 :        348 :          * @desc     Get/Set a boolean value that indicates whether or not cross-site Access-Control requests should be made using credentials.
     865                 :        348 :          */
     866                 :        348 :         get withCredentials(){ return xmlHttpRequest.get(this)['withCredentials']; }
     867                 :        348 : 
     868            [ + ]:        348 :         set withCredentials(cred = false){
     869                 :          1 :                 const requestData = xmlHttpRequest.get(this);
     870                 :          1 : 
     871                 :          1 :                 // xhr.spec.1. If this’s state is not unsent or opened, then throw an "InvalidStateError" DOMException.
     872                 :          1 :                 // xhr.spec.2. If this’s send() flag is set, then throw an "InvalidStateError" DOMException.
     873                 :          1 :                 if(requestData['readyState'] > this.OPENED || requestData['sendFlag'])
     874            [ - ]:          1 :                         throw new DOMException(`XMLHttpRequest.withCredentials setter: XMLHttpRequest must not be sending.`, 'InvalidStateError');
     875                 :          0 : 
     876                 :          0 :                 // xhr.spec.3. Set this’s cross-origin credentials to the given value.
     877                 :          0 :                 xmlHttpRequest.get(this)['withCredentials'] = Boolean(cred);
     878                 :          1 :         }
     879                 :        348 : } // @endof class XMLHttpRequest extends XMLHttpRequestEventTarget
     880                 :        348 : 
     881                 :        348 : 
     882                 :        348 : /**
     883                 :        348 :  * @const    {number} UNSENT
     884                 :        348 :  * @memberof module:whatwg-xhr.XMLHttpRequest
     885                 :        348 :  * @instance
     886                 :        348 :  * @default  0
     887                 :        348 :  * @desc     State of XMLHttpRequest object, client has been created, open() not called yet.
     888                 :        348 :  */
     889                 :        348 : Object.defineProperty(XMLHttpRequest.prototype, 'UNSENT', {value: 0, writable: false, enumerable: true, configurable: false});
     890                 :        348 : 
     891                 :        348 : /**
     892                 :        348 :  * @const    {number} OPENED
     893                 :        348 :  * @memberof module:whatwg-xhr.XMLHttpRequest
     894                 :        348 :  * @instance
     895                 :        348 :  * @default  1
     896                 :        348 :  * @desc     State of XMLHttpRequest object, open() has been called.
     897                 :        348 :  */
     898                 :        348 : Object.defineProperty(XMLHttpRequest.prototype, 'OPENED', {value: 1, writable: false, enumerable: true, configurable: false});
     899                 :        348 : 
     900                 :        348 : /**
     901                 :        348 :  * @const    {number} HEADERS_RECEIVED
     902                 :        348 :  * @memberof module:whatwg-xhr.XMLHttpRequest
     903                 :        348 :  * @instance
     904                 :        348 :  * @default  2
     905                 :        348 :  * @desc     State of XMLHttpRequest object, send() has been called, headers and status are available.
     906                 :        348 :  */
     907                 :        348 : Object.defineProperty(XMLHttpRequest.prototype, 'HEADERS_RECEIVED', {value: 2, writable: false, enumerable: true, configurable: false});
     908                 :        348 : 
     909                 :        348 : /**
     910                 :        348 :  * @const    {number} LOADING
     911                 :        348 :  * @memberof module:whatwg-xhr.XMLHttpRequest
     912                 :        348 :  * @instance
     913                 :        348 :  * @default  3
     914                 :        348 :  * @desc     State of XMLHttpRequest object, downloading, responseText holds partial data.
     915                 :        348 :  */
     916                 :        348 : Object.defineProperty(XMLHttpRequest.prototype, 'LOADING', {value: 3, writable: false, enumerable: true, configurable: false});
     917                 :        348 : 
     918                 :        348 : /**
     919                 :        348 :  * @const    {number} DONE
     920                 :        348 :  * @memberof module:whatwg-xhr.XMLHttpRequest
     921                 :        348 :  * @instance
     922                 :        348 :  * @default  4
     923                 :        348 :  * @desc     State of XMLHttpRequest object, the operation is complete.
     924                 :        348 :  */
     925                 :        348 : Object.defineProperty(XMLHttpRequest.prototype, 'DONE', {value: 4, writable: false, enumerable: true, configurable: false});
     926                 :        348 : 
     927                 :        348 : /**
     928                 :        348 :  * XMLHttpRequest Living Standard — Last Updated 20 February 2023
     929                 :        348 :  * url: https://xhr.spec.whatwg.org/#the-open()-method
     930                 :        348 :  *
     931                 :        348 :  * client.open(method, url [, async = true [, username = null [, password = null]]])
     932                 :        348 :  *
     933                 :        348 :  *   Sets the request method, request URL, and synchronous flag.
     934                 :        348 :  *   Throws a  "SyntaxError"        DOMException if either method is not a valid method or url cannot be parsed.
     935                 :        348 :  *   Throws a  "SecurityError"      DOMException if method is a case-insensitive match for `CONNECT`, `TRACE`, or `TRACK`.
     936                 :        348 :  *   Throws an "InvalidAccessError" DOMException if async is false, the current global object is a Window object, and the timeout attribute is not zero
     937                 :        348 :  *                                  or the responseType attribute is not the empty string.
     938                 :        348 :  *
     939                 :        348 :  * Synchronous XMLHttpRequest outside of workers is in the process of being removed from the web platform as it has detrimental effects to the end user’s
     940                 :        348 :  * experience. (This is a long process that takes many years.) Developers must not pass false for the async argument when the current global object is a
     941                 :        348 :  * Window object. User agents are strongly encouraged to warn about such usage in developer tools and may experiment with throwing an "InvalidAccessError"
     942                 :        348 :  * DOMException when it occurs.
     943                 :        348 :  *
     944                 :        348 :  * The open(method, url) and open(method, url, async, username, password) method steps are:
     945                 :        348 :  *
     946                 :        348 :  *   1. If this’s relevant global object is a Window object and its associated Document is not fully active, then throw an "InvalidStateError" DOMException.
     947                 :        348 :  *   2. If method is not a method, then throw a "SyntaxError" DOMException.
     948                 :        348 :  *   3. If method is a forbidden method, then throw a "SecurityError" DOMException.
     949                 :        348 :  *   4. Normalize method.
     950                 :        348 :  *   5. Let parsedURL be the result of parsing url with this’s relevant settings object’s API base URL and this’s relevant settings object’s API URL
     951                 :        348 :  *      character encoding.
     952                 :        348 :  *   6. If parsedURL is failure, then throw a "SyntaxError" DOMException.
     953                 :        348 :  *   7. If the async argument is omitted, set async to true, and set username and password to null.
     954                 :        348 :  *      Note: Unfortunately legacy content prevents treating the async argument being undefined identical from it being omitted.
     955                 :        348 :  *   8. If parsedURL’s host is non-null, then:
     956                 :        348 :  *      1. If the username argument is not null, set the username given parsedURL and username.
     957                 :        348 :  *      2. If the password argument is not null, set the password given parsedURL and password.
     958                 :        348 :  *   9. If async is false, the current global object is a Window object, and either this’s timeout is not 0 or this’s response type is not the empty
     959                 :        348 :  *      string, then throw an "InvalidAccessError" DOMException.
     960                 :        348 :  *  10. Terminate this’s fetch controller.
     961                 :        348 :  *      Note: A fetch can be ongoing at this point.
     962                 :        348 :  *  11. Set variables associated with the object as follows:
     963                 :        348 :  *        Unset this’s send() flag.
     964                 :        348 :  *        Unset this’s upload listener flag.
     965                 :        348 :  *        Set   this’s request method to method.
     966                 :        348 :  *        Set   this’s request URL to parsedURL.
     967                 :        348 :  *        Set   this’s synchronous flag if async is false; otherwise unset this’s synchronous flag.
     968                 :        348 :  *        Empty this’s author request headers.
     969                 :        348 :  *        Set   this’s response to a network error.
     970                 :        348 :  *        Set   this’s received bytes to the empty byte sequence.
     971                 :        348 :  *        Set   this’s response object to null.
     972                 :        348 :  *      Note: Override MIME type is not overridden here as the overrideMimeType() method can be invoked before the open() method.
     973                 :        348 :  *  12. If this’s state is not opened, then:
     974                 :        348 :  *      1. Set this’s state to opened.
     975                 :        348 :  *      2. Fire an event named readystatechange at this.
     976                 :        348 :  *
     977                 :        348 :  * @method   open
     978                 :        348 :  * @instance
     979                 :        348 :  * @memberof module:whatwg-xhr.XMLHttpRequest
     980                 :        348 :  * @param    {string}  method   - The HTTP request method to use, such as "GET", "POST", "PUT", "DELETE", etc. Ignored for non-HTTP(S) URLs.
     981                 :        348 :  * @param    {string}  url      - A string or any other object with a stringifier that provides the URL of the resource to request.
     982                 :        348 :  * @param    {boolean} is_async - (Optional) Boolean parameter, defaulting to true, indicating whether or not to perform the operation asynchronously.
     983                 :        348 :  * @param    {string}  username - (Optional) user name to use for authentication purposes; by default, this is the null value.
     984                 :        348 :  * @param    {string}  password - (Optional) password to use for authentication purposes; by default, this is the null value.
     985                 :        348 :  * @desc     XMLHttpRequest method that initializes a newly-created request, or re-initializes an existing one.
     986                 :        348 :  * @requires module:whatwg-fetch.forbiddenHttpRequestMethod
     987                 :        348 :  */
     988            [ + ]:        348 : XMLHttpRequest.prototype.open = function open(method, url, is_async = true, username = null, password = null){
     989                 :        761 : 
     990                 :        761 :         // xhr.spec.1. If this’s relevant global object is a Window object and its associated Document is not fully active, then throw an "InvalidStateError" DOMException.
     991            [ - ]:        761 :         if(globalThis.Window && !document.isConnected)
     992            [ - ]:        761 :                 throw new DOMException(`XMLHttpRequest.open: ......`, 'InvalidStateError');
     993                 :        761 : 
     994                 :        761 :         // xhr.spec.2. If method is not a method, then throw a "SyntaxError" DOMException
     995                 :        761 :         if(typeof method === 'function')
     996            [ - ]:        761 :                 throw new DOMException(`XMLHttpRequest.open: an invalid or illegal method string was specified`, 'SyntaxError');
     997                 :        761 : 
     998                 :        761 :         // xhr.spec.2. If method is not a method, then throw a "SyntaxError" DOMException
     999                 :        761 :         method = String(method);
    1000                 :        761 :         if(/[^\w]/.test(method))
    1001       [ + ][ + ]:        761 :                 throw new DOMException(`XMLHttpRequest.open: an invalid or illegal method string was specified`, 'SyntaxError');
    1002                 :        529 : 
    1003                 :        529 :         // xhr.spec.3. If method is a forbidden method, then throw a "SecurityError" DOMException
    1004                 :        529 :         if(forbiddenHttpRequestMethod.has(String(method).toLowerCase()))
    1005       [ + ][ + ]:        761 :                 throw new DOMException(`XMLHttpRequest.open: the operation is insecure.`, 'SecurityError');
    1006                 :        520 : 
    1007                 :        520 :         // xhr.spec.4. Normalize method.
    1008                 :        520 :         // fetch.spec. To normalize a method, if it is a byte-case-insensitive match for `DELETE`, `GET`, `HEAD`, `OPTIONS`, `POST`, or `PUT`, byte-uppercase it.
    1009       [ + ][ + ]:        761 :         method = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT'].find(m => m === String(method).toUpperCase()) || String(method);
    1010                 :        761 : 
    1011                 :        761 :         // xhr.spec.5. Let parsedURL be the result of parsing url with this’s relevant settings object’s API base URL and
    1012                 :        761 :         //             this’s relevant settings object’s API URL character encoding.
    1013                 :        761 :         let parsedURL;
    1014                 :        761 :         try{
    1015                 :        761 :                 parsedURL = new URL(url);
    1016                 :        761 :         }
    1017            [ + ]:        761 :         catch(e){
    1018                 :          1 :                 // xhr.spec.6. If parsedURL is failure, then throw a "SyntaxError" DOMException
    1019                 :          1 :                 throw new DOMException(`XMLHttpRequest.open: an invalid or illegal url string was specified`, 'SyntaxError');
    1020            [ + ]:          1 :         }
    1021                 :        519 : 
    1022                 :        519 :         // xhr.spec.7. If the async argument is omitted, set async to true, and set username and password to null.
    1023                 :        519 :         // @author: already handled by default arguments: open(method, url, is_async = true, username = null, password = null)
    1024                 :        519 : 
    1025                 :        519 :         // xhr.spec.8. If parsedURL’s host is non-null, then:
    1026            [ + ]:        761 :         if(parsedURL.host){
    1027                 :        503 :                 // xhr.spec.8.1. If the username argument is not null, set the username given parsedURL and username.
    1028            [ + ]:        503 :                 if(username){
    1029                 :          1 :                 /*
    1030                 :          1 :                  * URL Living Standard — Last Updated 24 May 2023
    1031                 :          1 :                  * url: https://url.spec.whatwg.org/#set-the-username
    1032                 :          1 :                  *
    1033                 :          1 :                  * To set the username given a url and username, set url’s username to the result of running UTF-8 percent-encode on username
    1034                 :          1 :                  * using the userinfo percent-encode set.
    1035                 :          1 :                  */
    1036                 :          1 :                         parsedURL.username = username;
    1037                 :          1 :                 }
    1038                 :        503 :                 // xhr.spec.8.2. If the password argument is not null, set the password given parsedURL and password.
    1039            [ + ]:        503 :                 if(password){
    1040                 :          1 :                 /*
    1041                 :          1 :                  * URL Living Standard — Last Updated 24 May 2023
    1042                 :          1 :                  * url: https://url.spec.whatwg.org/#set-the-password
    1043                 :          1 :                  *
    1044                 :          1 :                  * To set the password given a url and password, set url’s password to the result of running UTF-8 percent-encode on password
    1045                 :          1 :                  * using the userinfo percent-encode set.
    1046                 :          1 :                  */
    1047                 :          1 :                         parsedURL.password = password;
    1048                 :          1 :                 }
    1049            [ + ]:        503 :         }
    1050                 :        519 : 
    1051                 :        519 :         const requestData = xmlHttpRequest.get(this);
    1052                 :        519 : 
    1053                 :        519 :         // xhr.spec.9. If async is false, the current global object is a Window object, and either this’s timeout is not 0 or this’s response type is not the empty
    1054                 :        519 :         //             string, then throw an "InvalidAccessError" DOMException.
    1055       [ - ][ - ]:        761 :         if(globalThis.Window && is_async === false && (requestData['timeout'] || requestData['responseType']))
    1056       [ + ][ - ]:        761 :                 throw new DOMException(`XMLHttpRequest.open: synchronous XMLHttpRequests do not support timeout and responseType`, 'InvalidAccessError');
    1057                 :        519 : 
    1058                 :        519 :         // @author. xhr.spec.9. will also be applicable to main thread
    1059            [ + ]:        761 :         if(threads.isMainThread && is_async === false && (requestData['timeout'] || requestData['responseType']))
    1060       [ + ][ + ]:        761 :                 throw new DOMException(`XMLHttpRequest.open: synchronous XMLHttpRequests do not support timeout and responseType`, 'InvalidAccessError');
    1061                 :        514 : 
    1062                 :        514 :         // xhr.spec.10. Terminate this’s fetch controller. Note: A fetch can be ongoing at this point.
    1063            [ + ]:        761 :         if(requestData['fetchController']){
    1064                 :          2 :                 requestData['fetchController'].destroy();
    1065                 :          2 :                 requestData['fetchController'] = null;
    1066            [ + ]:          2 :         }
    1067                 :        514 : 
    1068                 :        514 :         // xhr.spec.11. Set variables associated with the object as follows:
    1069                 :        514 :         // xhr.spec.11. Unset this’s send() flag.
    1070                 :        514 :         requestData['sendFlag'] = false;
    1071                 :        514 : 
    1072                 :        514 :         // xhr.spec.11. Unset this’s upload listener flag.
    1073                 :        514 :         requestData['uploadListenerFlag'] = false;
    1074                 :        514 : 
    1075                 :        514 :         // xhr.spec.11. Set this’s request method to method.
    1076                 :        514 :         requestData['method'] = method;
    1077                 :        514 : 
    1078                 :        514 :         // xhr.spec.11. Set this’s request URL to parsedURL.
    1079                 :        514 :         requestData['url'] = parsedURL.href;
    1080                 :        514 : 
    1081                 :        514 :         // xhr.spec.11. Set this’s synchronous flag if async is false; otherwise unset this’s synchronous flag.
    1082                 :        514 :         requestData['async'] = !(is_async === false);
    1083                 :        514 : 
    1084                 :        514 :         // xhr.spec.11. Empty this’s author request headers.
    1085                 :        514 : 
    1086                 :        514 :         requestData['requestHeaders'    ] = {};
    1087                 :        514 :         requestData['requestHeadersCase'] = {};
    1088                 :        514 : 
    1089                 :        514 :         // xhr.spec.11. Set this’s response to a network error.
    1090                 :        514 :         setResponseToNetworkError.call(this);
    1091                 :        514 : 
    1092                 :        514 :         // xhr.spec.11. Set this’s received bytes to the empty byte sequence.
    1093                 :        514 :         requestData['receivedBytes'] = Buffer.alloc(0);
    1094                 :        514 : 
    1095                 :        514 :         // xhr.spec.11. Set this’s response object to null.
    1096                 :        514 :         requestData['responseObject'] = null;
    1097                 :        514 : 
    1098                 :        514 :         // xhr.spec.12. If this’s state is not opened, then:
    1099            [ + ]:        761 :         if(requestData['readyState'] !== this.OPENED){
    1100                 :        506 : 
    1101                 :        506 :                 // xhr.spec.12.1. Set this’s state to opened.
    1102                 :        506 :                 requestData['readyState'] = this.OPENED;
    1103                 :        506 : 
    1104                 :        506 :                 // xhr.spec.12.2. Fire an event named readystatechange at this.
    1105                 :        506 :                 this.dispatchEvent(new Event('readystatechange'));
    1106                 :        506 :         }
    1107                 :        348 : }; // @endof method XMLHttpRequest.prototype.open
    1108                 :        348 : 
    1109                 :        348 : /**
    1110                 :        348 :  * XMLHttpRequest Living Standard — Last Updated 20 February 2023
    1111                 :        348 :  * url: https://xhr.spec.whatwg.org/#the-abort()-method
    1112                 :        348 :  *
    1113                 :        348 :  * client.abort()
    1114                 :        348 :  *   Cancels any network activity.
    1115                 :        348 :  *
    1116                 :        348 :  * The abort() method steps are:
    1117                 :        348 :  * 1. Abort this’s fetch controller.
    1118                 :        348 :  * 2. If this’s state is opened with this’s send() flag set, headers received, or loading, then run the request error steps for this and abort.
    1119                 :        348 :  * 3. If this’s state is done, then set this’s state to unsent and this’s response to a network error.
    1120                 :        348 :  * Note: No readystatechange event is dispatched.
    1121                 :        348 :  *
    1122                 :        348 :  * @method   abort
    1123                 :        348 :  * @instance
    1124                 :        348 :  * @memberof module:whatwg-xhr.XMLHttpRequest
    1125                 :        348 :  * @desc     XMLHttpRequest method that aborts the request if it has already been sent.
    1126                 :        348 :  */
    1127            [ + ]:        348 : XMLHttpRequest.prototype.abort = function abort(){
    1128                 :          6 : 
    1129                 :          6 :         const requestData = xmlHttpRequest.get(this);
    1130                 :          6 : 
    1131                 :          6 :         // xhr.spec.1. Abort this’s fetch controller
    1132            [ + ]:          6 :         if(requestData['fetchController']){
    1133                 :          3 :                 requestData['fetchController'].destroy();
    1134                 :          3 :                 requestData['fetchController'] = null;
    1135                 :          3 :         }
    1136                 :          6 : 
    1137                 :          6 :         // xhr.spec.2. If this’s state is opened with this’s send() flag set, headers received,
    1138                 :          6 :         //             or loading, then run the request error steps for this and abort.
    1139                 :          6 :         if(
    1140       [ + ][ + ]:          6 :                 requestData['readyState'] === this.OPENED && requestData['sendFlag'] ||
    1141            [ + ]:          6 :                 requestData['readyState'] === this.HEADERS_RECEIVED ||
    1142                 :          1 :                 requestData['readyState'] === this.LOADING
    1143            [ + ]:          6 :         ){
    1144                 :          5 :                 requestErrorSteps.call(this, 'abort');
    1145                 :          5 :         }
    1146                 :          6 : 
    1147                 :          6 :         // xhr.spec.3. If this’s state is done, then set this’s state to unsent and this’s response to a network error.
    1148            [ + ]:          6 :         if(requestData['readyState'] === this.DONE){
    1149                 :          5 : 
    1150                 :          5 :                 requestData['readyState'] = this.UNSENT;
    1151                 :          5 :                 setResponseToNetworkError.call(this);
    1152                 :          5 :         }
    1153                 :        348 : }; // @endof method XMLHttpRequest.prototype.abort
    1154                 :        348 : 
    1155                 :        348 : /**
    1156                 :        348 :  * XMLHttpRequest Living Standard — Last Updated 20 February 2023
    1157                 :        348 :  * url: https://xhr.spec.whatwg.org/#the-setrequestheader()-method
    1158                 :        348 :  *
    1159                 :        348 :  * client.setRequestHeader(name, value)
    1160                 :        348 :  *   Appends a value to an existing request header or adds a new request header.
    1161                 :        348 :  *   Throws an "InvalidStateError" DOMException if either state is not opened or the send() flag is set.
    1162                 :        348 :  *   Throws a "SyntaxError" DOMException if name is not a header name or if value is not a header value.
    1163                 :        348 :  *
    1164                 :        348 :  * The setRequestHeader(name, value) method must run these steps:
    1165                 :        348 :  *   1. If this’s state is not opened, then throw an "InvalidStateError" DOMException.
    1166                 :        348 :  *   2. If this’s send() flag is set, then throw an "InvalidStateError" DOMException.
    1167                 :        348 :  *   3. Normalize value.
    1168                 :        348 :  *   4. If name is not a header name or value is not a header value, then throw a "SyntaxError" DOMException.
    1169                 :        348 :  *   5. An empty byte sequence represents an empty header value.
    1170                 :        348 :  *   6. If (name, value) is a forbidden request-header, then return.
    1171                 :        348 :  *   7. Combine (name, value) in this’s author request headers.
    1172                 :        348 :  *
    1173                 :        348 :  * @method   setRequestHeader
    1174                 :        348 :  * @instance
    1175                 :        348 :  * @memberof module:whatwg-xhr.XMLHttpRequest
    1176                 :        348 :  * @param    {string}  name  - The name of the header whose value is to be set.
    1177                 :        348 :  * @param    {string}  value - The value to set as the body of the header.
    1178                 :        348 :  * @desc     XMLHttpRequest method that sets the value of an HTTP request header.
    1179                 :        348 :  * @requires module:whatwg-fetch.forbiddenRequestHeader
    1180                 :        348 :  */
    1181            [ + ]:        348 : XMLHttpRequest.prototype.setRequestHeader = function setRequestHeader(name, value){
    1182                 :       2392 : 
    1183                 :       2392 :         // @author: validate the number of arguments
    1184                 :       2392 :         if(arguments.length < 2)
    1185       [ + ][ + ]:       2392 :                 throw new TypeError(`XMLHttpRequest.setRequestHeader: At least 2 arguments required, but only ${arguments.length} passed`);     // firefox 102
    1186                 :       1578 : 
    1187                 :       1578 :         const requestData = xmlHttpRequest.get(this);
    1188                 :       1578 : 
    1189                 :       1578 :         // xhr.spec.1. If this’s state is not opened, then throw an "InvalidStateError" DOMException.
    1190                 :       1578 :         if(requestData['readyState'] !== this.OPENED)
    1191       [ + ][ + ]:       2392 :                 throw new DOMException(`XMLHttpRequest.send: XMLHttpRequest state must be OPENED.`, 'InvalidStateError');       // firefox 102
    1192                 :       1573 : 
    1193                 :       1573 :         // xhr.spec.2. If this’s send() flag is set, then throw an "InvalidStateError" DOMException.
    1194                 :       1573 :         if(requestData['sendFlag'])
    1195       [ + ][ + ]:       2392 :                 throw new DOMException(`XMLHttpRequest.send: XMLHttpRequest must not be sending.`, 'InvalidStateError');        // firefox 102
    1196                 :       1572 : 
    1197                 :       1572 :         // xhr.spec.3. Normalize value.
    1198                 :       1572 :         // fetch.spec. To normalize a byte sequence potentialValue, remove any leading and trailing HTTP whitespace bytes from potentialValue.
    1199                 :       1572 :         value = String(value).trim();
    1200                 :       1572 : 
    1201                 :       1572 :         // xhr.spec.4. If name is not a header name or value is not a header value, then throw a "SyntaxError" DOMException.
    1202                 :       1572 :         try{
    1203                 :       1572 :                 http.validateHeaderName(name);
    1204                 :       1572 :         }
    1205            [ + ]:       2392 :         catch(err){
    1206                 :         71 : 
    1207                 :         71 :                 name = String(name);
    1208            [ + ]:         71 :                 for(let i = 0; i < name.length; i++){
    1209            [ + ]:        110 :                         if(name[i].codePointAt(0) > 0xFF){
    1210                 :          2 :                                 let msg = '';
    1211                 :          2 : 
    1212                 :          2 :                                 msg += `XMLHttpRequest.setRequestHeader: `;
    1213                 :          2 :                                 msg += `Cannot convert argument 1 to ByteString because the character at index ${i} `;
    1214                 :          2 :                                 msg += `has value ${name[i].codePointAt(0)} which is greater than 255.`
    1215                 :          2 : 
    1216                 :          2 :                                 throw new TypeError(msg); // firefox 102
    1217                 :          2 :                         }
    1218            [ + ]:        110 :                 }
    1219                 :         69 : 
    1220                 :         69 :                 throw new DOMException(`XMLHttpRequest.setRequestHeader: Invalid header name.`, 'SyntaxError'); // firefox 102
    1221            [ + ]:         69 :         }
    1222                 :       1501 : 
    1223                 :       1501 :         try{
    1224                 :       1501 :                 http.validateHeaderValue(name, value);
    1225                 :       1501 :         }
    1226            [ + ]:       2392 :         catch(err){
    1227                 :          4 : 
    1228            [ + ]:          4 :                 for(let i = 0; i < value.length; i++){
    1229            [ + ]:         10 :                         if(value[i].codePointAt(0) > 0xFF){
    1230                 :          1 :                                 let msg = '';
    1231                 :          1 : 
    1232                 :          1 :                                 msg += `XMLHttpRequest.setRequestHeader: `;
    1233                 :          1 :                                 msg += `Cannot convert argument 2 to ByteString because the character at index ${i} `;
    1234                 :          1 :                                 msg += `has value ${value[i].codePointAt(0)} which is greater than 255.`
    1235                 :          1 : 
    1236                 :          1 :                                 throw new TypeError(msg); // firefox 102
    1237                 :          1 :                         }
    1238            [ + ]:         10 :                 }
    1239                 :          3 : 
    1240                 :          3 :                 throw new DOMException(`XMLHttpRequest.setRequestHeader: Invalid header value.`, 'SyntaxError'); // firefox 102
    1241            [ + ]:          3 :         }
    1242                 :       1497 : 
    1243                 :       1497 :         // xhr.spec.6. If (name, value) is a forbidden request-header, then return.
    1244            [ + ]:       2392 :         if(forbiddenRequestHeader(name, value)){
    1245                 :         22 :                 return;
    1246            [ + ]:         22 :         }
    1247                 :       1475 : 
    1248                 :       1475 :         const headers     = requestData['requestHeaders'];
    1249                 :       1475 :         const headersCase = requestData['requestHeadersCase'];
    1250                 :       1475 : 
    1251                 :       1475 :         // xhr.spec.7. Combine (name, value) in this’s author request headers.
    1252            [ + ]:       2392 :         if(headersCase[name.toLowerCase()]){
    1253                 :         13 :                 let nameCase = headersCase[name.toLowerCase()];
    1254                 :         13 :                 headers[nameCase] = headers[nameCase] ? headers[nameCase] + ', ' + value : value;
    1255            [ + ]:         13 :         }
    1256                 :       1462 :         else{
    1257                 :       1462 :                 headersCase[name.toLowerCase()] = name;
    1258                 :       1462 :                 headers[name] = value;
    1259                 :       1462 :         }
    1260                 :        348 : }; // @endof method XMLHttpRequest.prototype.setRequestHeader
    1261                 :        348 : 
    1262                 :        348 : /**
    1263                 :        348 :  * XMLHttpRequest Living Standard — Last Updated 20 February 2023
    1264                 :        348 :  * url: https://xhr.spec.whatwg.org/#the-send()-method
    1265                 :        348 :  *
    1266                 :        348 :  * client.send([body = null])
    1267                 :        348 :  *   Initiates the request. The body argument provides the request body, if any, and is ignored if the request method is GET or HEAD.
    1268                 :        348 :  *   Throws an "InvalidStateError" DOMException if either state is not opened or the send() flag is set.
    1269                 :        348 :  *
    1270                 :        348 :  * The send(body) method steps are:
    1271                 :        348 :  *   1. If this’s state is not opened, then throw an "InvalidStateError" DOMException.
    1272                 :        348 :  *   2. If this’s send() flag is set, then throw an "InvalidStateError" DOMException.
    1273                 :        348 :  *   3. If this’s request method is `GET` or `HEAD`, then set body to null.
    1274                 :        348 :  *   4. If body is not null, then:
    1275                 :        348 :  *      1. Let extractedContentType be null.
    1276                 :        348 :  *      2. If body is a Document, then set this’s request body to body, serialized, converted, and UTF-8 encoded.
    1277                 :        348 :  *      3. Otherwise:
    1278                 :        348 :  *         1. Let bodyWithType be the result of safely extracting body.
    1279                 :        348 :  *         2. Set this’s request body to bodyWithType’s body.
    1280                 :        348 :  *         3. Set extractedContentType to bodyWithType’s type.
    1281                 :        348 :  *      4. Let originalAuthorContentType be the result of getting `Content-Type` from this’s author request headers.
    1282                 :        348 :  *      5. If originalAuthorContentType is non-null, then:
    1283                 :        348 :  *         1. If body is a Document or a USVString, then:
    1284                 :        348 :  *            1. Let contentTypeRecord be the result of parsing originalAuthorContentType.
    1285                 :        348 :  *            2. If contentTypeRecord is not failure, contentTypeRecord’s parameters["charset"] exists, and parameters["charset"] is not an ASCII case-insensitive
    1286                 :        348 :  *               match for "UTF-8", then:
    1287                 :        348 :  *               1. Set contentTypeRecord’s parameters["charset"] to "UTF-8".
    1288                 :        348 :  *               2. Let newContentTypeSerialized be the result of serializing contentTypeRecord.
    1289                 :        348 :  *               3. Set (`Content-Type`, newContentTypeSerialized) in this’s author request headers.
    1290                 :        348 :  *      6. Otherwise:
    1291                 :        348 :  *         1. If body is an HTML document, then set (`Content-Type`, `text/html;charset=UTF-8`) in this’s author request headers.
    1292                 :        348 :  *         2. Otherwise, if body is an XML document, set (`Content-Type`, `application/xml;charset=UTF-8`) in this’s author request headers.
    1293                 :        348 :  *         3. Otherwise, if extractedContentType is not null, set (`Content-Type`, extractedContentType) in this’s author request headers.
    1294                 :        348 :  *   5. If one or more event listeners are registered on this’s upload object, then set this’s upload listener flag.
    1295                 :        348 :  *   6. Let req be a new request, initialized as follows:
    1296                 :        348 :  *        method                    This’s request method.
    1297                 :        348 :  *        URL                       This’s request URL.
    1298                 :        348 :  *        header list               This’s author request headers.
    1299                 :        348 :  *        unsafe-request flag       Set.
    1300                 :        348 :  *        body                      This’s request body.
    1301                 :        348 :  *        client                    This’s relevant settings object.
    1302                 :        348 :  *        mode                      "cors".
    1303                 :        348 :  *        use-CORS-preflight flag   Set if this’s upload listener flag is set.
    1304                 :        348 :  *        credentials mode          If this’s cross-origin credentials is true, then "include"; otherwise "same-origin".
    1305                 :        348 :  *        use-URL-credentials flag  Set if this’s request URL includes credentials.
    1306                 :        348 :  *        initiator type            "xmlhttprequest".
    1307                 :        348 :  *   7. Unset this’s upload complete flag.
    1308                 :        348 :  *   8. Unset this’s timed out flag.
    1309                 :        348 :  *   9. If req’s body is null, then set this’s upload complete flag.
    1310                 :        348 :  *  10. Set this’s send() flag.
    1311                 :        348 :  *  11. If this’s synchronous flag is unset, then:
    1312                 :        348 :  *      1. Fire a progress event named loadstart at this with 0 and 0.
    1313                 :        348 :  *      2. Let requestBodyTransmitted be 0.
    1314                 :        348 :  *      3. Let requestBodyLength be req’s body’s length, if req’s body is non-null; otherwise 0.
    1315                 :        348 :  *      4. Assert: requestBodyLength is an integer.
    1316                 :        348 :  *      5. If this’s upload complete flag is unset and this’s upload listener flag is set, then fire a progress event named loadstart at this’s upload object
    1317                 :        348 :  *         with requestBodyTransmitted and requestBodyLength.
    1318                 :        348 :  *      6. If this’s state is not opened or this’s send() flag is unset, then return.
    1319                 :        348 :  *      7. Let processRequestBodyChunkLength, given a bytesLength, be these steps:
    1320                 :        348 :  *         1. Increase requestBodyTransmitted by bytesLength.
    1321                 :        348 :  *         2. If not roughly 50ms have passed since these steps were last invoked, then return.
    1322                 :        348 :  *         3. If this’s upload listener flag is set, then fire a progress event named progress at this’s upload object with requestBodyTransmitted and
    1323                 :        348 :  *            requestBodyLength.
    1324                 :        348 :  *         Note: These steps are only invoked when new bytes are transmitted.
    1325                 :        348 :  *      8. Let processRequestEndOfBody be these steps:
    1326                 :        348 :  *         1. Set this’s upload complete flag.
    1327                 :        348 :  *         2. If this’s upload listener flag is unset, then return.
    1328                 :        348 :  *         3. Fire a progress event named progress at this’s upload object with requestBodyTransmitted and requestBodyLength.
    1329                 :        348 :  *         4. Fire a progress event named load at this’s upload object with requestBodyTransmitted and requestBodyLength.
    1330                 :        348 :  *         5. Fire a progress event named loadend at this’s upload object with requestBodyTransmitted and requestBodyLength.
    1331                 :        348 :  *      9. Let processResponse, given a response, be these steps:
    1332                 :        348 :  *         1. Set this’s response to response.
    1333                 :        348 :  *         2. Handle errors for this.
    1334                 :        348 :  *         3. If this’s response is a network error, then return.
    1335                 :        348 :  *         4. Set this’s state to headers received.
    1336                 :        348 :  *         5. Fire an event named readystatechange at this.
    1337                 :        348 :  *         6. If this’s state is not headers received, then return.
    1338                 :        348 :  *         7. If this’s response’s body is null, then run handle response end-of-body for this and return.
    1339                 :        348 :  *         8. Let length be the result of extracting a length from this’s response’s header list.
    1340                 :        348 :  *         9. If length is not an integer, then set it to 0.
    1341                 :        348 :  *        10. Let processBodyChunk given bytes be these steps:
    1342                 :        348 :  *            1. Append bytes to this’s received bytes.
    1343                 :        348 :  *            2. If not roughly 50ms have passed since these steps were last invoked, then return.
    1344                 :        348 :  *            3. If this’s state is headers received, then set this’s state to loading.
    1345                 :        348 :  *            4. Fire an event named readystatechange at this.
    1346                 :        348 :  *               Note: Web compatibility is the reason readystatechange fires more often than this’s state changes.
    1347                 :        348 :  *            5. Fire a progress event named progress at this with this’s received bytes’s length and length.
    1348                 :        348 :  *        11. Let processEndOfBody be this step: run handle response end-of-body for this.
    1349                 :        348 :  *        12. Let processBodyError be these steps:
    1350                 :        348 :  *            1. Set this’s response to a network error.
    1351                 :        348 :  *            2.  Run handle errors for this.
    1352                 :        348 :  *        13. Incrementally read this’s response’s body, given processBodyChunk, processEndOfBody, processBodyError, and this’s relevant global object.
    1353                 :        348 :  *     10. Set this’s fetch controller to the result of fetching req with processRequestBodyChunkLength set to processRequestBodyChunkLength,
    1354                 :        348 :  *         processRequestEndOfBody set to processRequestEndOfBody, and processResponse set to processResponse.
    1355                 :        348 :  *     11. Let now be the present time.
    1356                 :        348 :  *     12. Run these steps in parallel:
    1357                 :        348 :  *         1. Wait until either req’s done flag is set or this’s timeout is not 0 and this’s timeout milliseconds have passed since now.
    1358                 :        348 :  *         2. If req’s done flag is unset, then set this’s timed out flag and terminate this’s fetch controller.
    1359                 :        348 :  *  12. Otherwise, if this’s synchronous flag is set:
    1360                 :        348 :  *      1. Let processedResponse be false.
    1361                 :        348 :  *      2. Let processResponseConsumeBody, given a response and nullOrFailureOrBytes, be these steps:
    1362                 :        348 :  *         1. If nullOrFailureOrBytes is not failure, then set this’s response to response.
    1363                 :        348 :  *         2. If nullOrFailureOrBytes is a byte sequence, then append nullOrFailureOrBytes to this’s received bytes.
    1364                 :        348 :  *         3. Set processedResponse to true.
    1365                 :        348 :  *      3. Set this’s fetch controller to the result of fetching req with processResponseConsumeBody set to processResponseConsumeBody and
    1366                 :        348 :  *         useParallelQueue set to true.
    1367                 :        348 :  *      4. Let now be the present time.
    1368                 :        348 :  *      5. Pause until either processedResponse is true or this’s timeout is not 0 and this’s timeout milliseconds have passed since now.
    1369                 :        348 :  *      6. If processedResponse is false, then set this’s timed out flag and terminate this’s fetch controller.
    1370                 :        348 :  *      7. Report timing for this’s fetch controller given the current global object.
    1371                 :        348 :  *      8. Run handle response end-of-body for this.
    1372                 :        348 :  *
    1373                 :        348 :  * To handle response end-of-body for an XMLHttpRequest object xhr, run these steps:
    1374                 :        348 :  *      1. Handle errors for xhr.
    1375                 :        348 :  *      2. If xhr’s response is a network error, then return.
    1376                 :        348 :  *      3. Let transmitted be xhr’s received bytes’s length.
    1377                 :        348 :  *      4. Let length be the result of extracting a length from this’s response’s header list.
    1378                 :        348 :  *      5. If length is not an integer, then set it to 0.
    1379                 :        348 :  *      6. If xhr’s synchronous flag is unset, then fire a progress event named progress at xhr with transmitted and length.
    1380                 :        348 :  *      7. Set xhr’s state to done.
    1381                 :        348 :  *      8. Unset xhr’s send() flag.
    1382                 :        348 :  *      9. Fire an event named readystatechange at xhr.
    1383                 :        348 :  *     10. Fire a progress event named load at xhr with transmitted and length.
    1384                 :        348 :  *     11. Fire a progress event named loadend at xhr with transmitted and length.
    1385                 :        348 :  *
    1386                 :        348 :  * @method   send
    1387                 :        348 :  * @instance
    1388                 :        348 :  * @memberof module:whatwg-xhr.XMLHttpRequest
    1389                 :        348 :  * @param    {Document| Blob|ArrayBuffer|TypedArray|DataView|FormData|URLSearchParams|string|null} body - The request body.
    1390                 :        348 :  * @desc     XMLHttpRequest method that sends the request to the server.
    1391                 :        348 :  * @requires module:whatwg-fetch.safelyExtractBodyWithType
    1392                 :        348 :  * @requires module:helper-content-type.parse
    1393                 :        348 :  * @requires module:helper-content-type.format
    1394                 :        348 :  */
    1395            [ + ]:        348 : XMLHttpRequest.prototype.send = function send(body = null){
    1396                 :        755 : 
    1397                 :        755 :         const xhr = this;
    1398                 :        755 :         const requestData = xmlHttpRequest.get(xhr);
    1399                 :        755 : 
    1400                 :        755 :         // xhr.spec.1. If this’s state is not opened, then throw an "InvalidStateError" DOMException.
    1401                 :        755 :         if(requestData['readyState'] !== xhr.OPENED)
    1402       [ + ][ + ]:        755 :                 throw new DOMException(`XMLHttpRequest.send: XMLHttpRequest state must be OPENED.`, 'InvalidStateError');       // firefox 102
    1403                 :        484 : 
    1404                 :        484 :         // xhr.spec.2. If this’s send() flag is set, then throw an "InvalidStateError" DOMException.
    1405                 :        484 :         if(requestData['sendFlag'])
    1406       [ + ][ + ]:        755 :                 throw new DOMException(`XMLHttpRequest.send: XMLHttpRequest must not be sending.`, 'InvalidStateError');        // firefox 102
    1407                 :        483 : 
    1408                 :        483 :         // xhr.spec.3. If this’s request method is `GET` or `HEAD`, then set body to null.
    1409       [ + ][ + ]:        755 :         if(requestData['method'].toUpperCase() === 'GET' || requestData['method'].toUpperCase() === 'HEAD'){
    1410                 :        263 :                 body = null;
    1411            [ + ]:        263 :         }
    1412                 :        483 : 
    1413                 :        483 :         // xhr.spec.4. If body is not null, then:
    1414       [ + ][ + ]:        755 :         if(body !== null && body !== ''){
    1415                 :         77 : 
    1416                 :         77 :                 // xhr.spec.4.1. Let extractedContentType be null.
    1417                 :         77 :                 let extractedContentType = null;
    1418                 :         77 : 
    1419                 :         77 :                 // xhr.spec.4.2. If body is a Document, then set this’s request body to body, serialized, converted, and UTF-8 encoded.
    1420                 :         77 :                 if(globalThis.Document && body instanceof globalThis.Document){
    1421                 :         77 :                         // @todo: xhr.spec.4.2. set this’s request body to body, serialized, converted, and UTF-8 encoded.
    1422                 :         77 :                 }
    1423                 :         77 :                 // xhr.spec.4.3. Otherwise:
    1424                 :         77 :                 else{
    1425                 :         77 :                         // xhr.spec.4.3.1. Let bodyWithType be the result of safely extracting body.
    1426                 :         77 :                         let bodyWithType = safelyExtractBodyWithType(body);
    1427                 :         77 : 
    1428                 :         77 :                         // xhr.spec.4.3.2. Set this’s request body to bodyWithType’s body.
    1429                 :         77 :                         requestData['requestBody'] = bodyWithType.body;
    1430                 :         77 : 
    1431                 :         77 :                         // xhr.spec.4.3.3. Set extractedContentType to bodyWithType’s type.
    1432                 :         77 :                         extractedContentType = bodyWithType.type;
    1433                 :         77 :                 }
    1434                 :         77 : 
    1435                 :         77 :                 // xhr.spec.4.4. Let originalAuthorContentType be the result of getting `Content-Type` from this’s author request headers.
    1436                 :         77 :                 let originalAuthorContentType = null;
    1437                 :         77 : 
    1438                 :         77 :                 if(requestData['requestHeadersCase']['content-type'])
    1439            [ + ]:         77 :                         originalAuthorContentType = requestData['requestHeaders'][requestData['requestHeadersCase']['content-type']];
    1440                 :         77 : 
    1441                 :         77 :                 // xhr.spec.4.5. If originalAuthorContentType is non-null, then:
    1442            [ + ]:         77 :                 if(originalAuthorContentType !== null){
    1443                 :         29 : 
    1444                 :         29 :                         // xhr.spec.4.5.1. If body is a Document or a USVString, then:
    1445                 :         29 :                         if(
    1446                 :         29 :                                 (globalThis.Document && body instanceof globalThis.Document) ||
    1447       [ + ][ + ]:         29 :                                 typeof body === 'string' || typeof requestData['requestBody'].source === 'string'){
    1448                 :         21 :                                 try{
    1449                 :         21 :                                         // xhr.spec.4.5.1.1. Let contentTypeRecord be the result of parsing originalAuthorContentType.
    1450                 :         21 :                                         const contentTypeRecord = contentTypeParse(originalAuthorContentType);
    1451                 :         21 : 
    1452                 :         21 :                                         // xhr.spec.4.5.1.2. If contentTypeRecord is not failure,
    1453                 :         21 :                                         //                   contentTypeRecord’s parameters["charset"] exists,
    1454                 :         21 :                                         //                   and parameters["charset"] is not an ASCII case-insensitive match for "UTF-8", then:
    1455                 :         21 :                                         let charset = contentTypeRecord.parameters['charset'];
    1456       [ + ][ + ]:         21 :                                         if(charset && charset.toUpperCase() !== 'UTF-8'){
    1457                 :          6 : 
    1458                 :          6 :                                                 // xhr.spec.4.5.1.2.1. Set contentTypeRecord’s parameters["charset"] to "UTF-8".
    1459                 :          6 :                                                 contentTypeRecord.parameters['charset'] = 'UTF-8';
    1460                 :          6 : 
    1461                 :          6 :                                                 // xhr.spec.4.5.1.2.2. Let newContentTypeSerialized be the result of serializing contentTypeRecord.
    1462                 :          6 :                                                 let newContentTypeSerialized = contentTypeFormat(contentTypeRecord);
    1463                 :          6 : 
    1464                 :          6 :                                                 // xhr.spec.4.5.1.2.3. Set (`Content-Type`, newContentTypeSerialized) in this’s author request headers.
    1465                 :          6 :                                                 // @author: first delete the existing Content-Type header
    1466                 :          6 :                                                 delete requestData['requestHeaders'][requestData['requestHeadersCase']['content-type']];
    1467                 :          6 :                                                 delete requestData['requestHeadersCase']['content-type'];
    1468                 :          6 : 
    1469                 :          6 :                                                 this.setRequestHeader('Content-Type', newContentTypeSerialized);
    1470                 :          6 :                                         }
    1471            [ + ]:         21 :                                 }catch(e){}
    1472                 :         21 :                         }
    1473            [ + ]:         29 :                 }
    1474                 :         48 :                 // xhr.spec.4.6. Otherwise:
    1475                 :         48 :                 else{
    1476                 :         48 :                         // xhr.spec.4.6.1. If body is an HTML document, then set (`Content-Type`, `text/html;charset=UTF-8`) in this’s author request headers.
    1477                 :         48 :                         if(globalThis.Document && body instanceof globalThis.Document && body.type === 'html')
    1478                 :         48 :                                 this.setRequestHeader('Content-Type', 'text/html;charset=UTF-8');
    1479                 :         48 :                         else
    1480                 :         48 :                         // xhr.spec.4.6.2. Otherwise, if body is an XML document, set (`Content-Type`, `application/xml;charset=UTF-8`) in this’s author request headers.
    1481                 :         48 :                         if(globalThis.Document && body instanceof globalThis.Document && body.type === 'xml')
    1482                 :         48 :                                 this.setRequestHeader('Content-Type', 'application/xml;charset=UTF-8');
    1483                 :         48 :                         else
    1484                 :         48 :                         // xhr.spec.4.6.3. Otherwise, if extractedContentType is not null, set (`Content-Type`, extractedContentType) in this’s author request headers.
    1485            [ + ]:         48 :                         if(extractedContentType){
    1486                 :         35 :                                 this.setRequestHeader('Content-Type', extractedContentType);
    1487                 :         35 :                         }
    1488                 :         48 :                 }
    1489            [ + ]:        755 :         } // @endof if(body !== null && body !== undefined)
    1490                 :        483 : 
    1491                 :        483 :         // xhr.spec.5. If one or more event listeners are registered on this’s upload object, then set this’s upload listener flag.
    1492                 :        483 :         if(
    1493            [ + ]:        755 :                 requestData['upload']['onloadstart'] !== null ||
    1494            [ + ]:        755 :                 requestData['upload']['onprogress' ] !== null ||
    1495            [ + ]:        755 :                 requestData['upload']['onabort'    ] !== null ||
    1496            [ + ]:        755 :                 requestData['upload']['onerror'    ] !== null ||
    1497            [ + ]:        755 :                 requestData['upload']['onload'     ] !== null ||
    1498            [ + ]:        755 :                 requestData['upload']['ontimeout'  ] !== null ||
    1499                 :        462 :                 requestData['upload']['onloadend'  ] !== null
    1500            [ + ]:        755 :         ){
    1501                 :         25 :                 requestData['uploadListenerFlag'] = true;
    1502            [ + ]:         25 :         }
    1503                 :        458 :         else
    1504       [ + ][ + ]:        458 :         if(Object.getOwnPropertySymbols(requestData['upload']).filter(e => requestData['upload'][e].size).length){
    1505                 :          3 :                 requestData['uploadListenerFlag'] = true;
    1506            [ + ]:          3 :         }
    1507                 :        483 : 
    1508                 :        483 :         // xhr.spec.6. Let req be a new request, initialized as follows:
    1509       [ + ][ - ]:        755 :         let req_auth = requestData['user'] ? `${requestData['user']}:${requestData['password'] === undefined ? '' : requestData['password']}` : undefined;
    1510                 :        755 : 
    1511                 :        755 :         // xhr.spec.6. method: This’s request method.
    1512                 :        755 :         let req_method = requestData['method'];
    1513                 :        755 : 
    1514                 :        755 :         // xhr.spec.6. URL: This’s request URL.
    1515                 :        755 :         let req_url = new URL(requestData['url']);
    1516                 :        755 : 
    1517                 :        755 :         let req_host     = req_url.hostname;
    1518            [ + ]:        755 :         let req_port     = req_url.port || (req_url.protocol === 'https:' ? 443 : 80);
    1519       [ + ][ + ]:        755 :         let req_url_path = req_url.pathname + (req_url.search ? req_url.search : '');
    1520                 :        755 :         let req_protocol = req_url.protocol;
    1521                 :        755 : 
    1522                 :        755 :         // xhr.spec.6. header list: This’s author request headers.
    1523                 :        755 :         const req_headers     = requestData['requestHeaders'];
    1524                 :        755 :         const req_headersCase = requestData['requestHeadersCase'];
    1525                 :        755 : 
    1526            [ + ]:        755 :         for(let name in defaultHeaders()){
    1527            [ + ]:       2259 :                 if(!req_headersCase[name.toLowerCase()]){
    1528                 :       1300 :                         xhr.setRequestHeader(name, defaultHeaders()[name]);
    1529                 :       1300 :                 }
    1530            [ + ]:       2259 :         }
    1531                 :        483 : 
    1532                 :        483 :         // xhr.spec.6. unsafe-request flag: Set.
    1533                 :        483 :         // xhr.spec.6. body: This’s request body.
    1534                 :        483 :         // xhr.spec.6. client: This’s relevant settings object.
    1535                 :        483 :         // xhr.spec.6. mode: "cors".
    1536                 :        483 :         // xhr.spec.6. use-CORS-preflight flag: Set if this’s upload listener flag is set.
    1537                 :        483 :         // xhr.spec.6. credentials mode: If this’s cross-origin credentials is true, then "include"; otherwise "same-origin".
    1538                 :        483 :         // xhr.spec.6. use-URL-credentials flag:  Set if this’s request URL includes credentials.
    1539                 :        483 :         // xhr.spec.6. initiator type: "xmlhttprequest".
    1540                 :        483 : 
    1541                 :        483 :         // author. use http.request(url[, options][, callback])
    1542                 :        483 :         const clientRequestOptions = {
    1543                 :        483 :                 agent:           false,
    1544                 :        483 :                 auth:            req_auth,
    1545                 :        483 :                 headers:         req_headers,
    1546                 :        483 :                 host:            req_host,
    1547                 :        483 :                 port:            req_port,
    1548                 :        483 :                 method:          req_method,
    1549                 :        483 :                 path:            req_url_path,
    1550                 :        483 :                 protocol:        req_url.protocol,
    1551                 :        483 :                 setHost:         true,
    1552                 :        483 :                 timeout:         requestData['timeout'],
    1553                 :        483 :                 withCredentials: requestData['withCredentials'],
    1554                 :        483 : 
    1555                 :        483 :                 // insecureHTTPParser: true,
    1556                 :        483 :                 url:             requestData['url'],
    1557                 :        483 :         };
    1558                 :        483 : 
    1559                 :        483 :         // author. choose the proper protocol
    1560                 :        483 :         let doClientRequest;
    1561                 :        483 : 
    1562                 :        483 :         if(req_protocol === 'https:')
    1563       [ + ][ - ]:        755 :                 doClientRequest = https.request;
    1564                 :        483 :         else
    1565                 :        483 :         if(req_protocol === 'http:')
    1566  [ + ][ + ][ + ]:        483 :                 doClientRequest = http.request;
    1567                 :          3 :         else
    1568                 :          3 :         if(req_protocol === 'data:')
    1569       [ + ][ + ]:          3 :                 doClientRequest = requestDataURL;
    1570                 :          3 :         else
    1571            [ + ]:          3 :                 doClientRequest = http.request;
    1572                 :        483 : 
    1573                 :        483 :         // xhr.spec.7. Unset this’s upload complete flag.
    1574                 :        483 :         requestData['uploadCompleteFlag'] = false;
    1575                 :        483 : 
    1576                 :        483 :         // xhr.spec.8. Unset this’s timed out flag.
    1577                 :        483 :         requestData['timeoutFlag'] = false;
    1578                 :        483 : 
    1579                 :        483 :         // xhr.spec.9. If req’s body is null, then set this’s upload complete flag.
    1580                 :        483 :         if(requestData['requestBody'] === null)
    1581       [ + ][ + ]:        755 :                 requestData['uploadCompleteFlag'] = true;
    1582                 :        483 : 
    1583                 :        483 :         // xhr.spec.10. Set this’s send() flag.
    1584                 :        483 :         requestData['sendFlag'] = true;
    1585                 :        483 : 
    1586                 :        483 :         // xhr.spec.11. If this’s synchronous flag is unset, then:
    1587            [ + ]:        755 :         if(requestData['async']){
    1588                 :        258 : 
    1589                 :        258 :                 // xhr.spec.11.1. Fire a progress event named loadstart at this with 0 and 0.
    1590                 :        258 :                 xhr.dispatchEvent(new ProgressEvent('loadstart', {loaded: 0, total: 0}));
    1591                 :        258 : 
    1592                 :        258 :                 // xhr.spec.11.2. Let requestBodyTransmitted be 0.
    1593                 :        258 :                 let requestBodyTransmitted = 0;
    1594                 :        258 : 
    1595                 :        258 :                 // xhr.spec.11.3. Let requestBodyLength be req’s body’s length, if req’s body is non-null; otherwise 0.
    1596       [ + ][ + ]:        258 :                 let requestBodyLength = requestData['requestBody'] ? requestData['requestBody'].length : 0;
    1597                 :        258 : 
    1598                 :        258 :                 // xhr.spec.11.4. Assert: requestBodyLength is an integer.
    1599                 :        258 :                 if(isNaN(requestBodyLength))
    1600            [ - ]:        258 :                         requestBodyLength = 0;
    1601                 :        258 : 
    1602                 :        258 :                 // xhr.spec.11.5. If this’s upload complete flag is unset and this’s upload listener flag is set,
    1603                 :        258 :                 // then fire a progress event named loadstart at this’s upload object with requestBodyTransmitted and requestBodyLength.
    1604            [ + ]:        258 :                 if(!requestData['uploadCompleteFlag'] && requestData['uploadListenerFlag'])
    1605            [ + ]:        258 :                         requestData['upload'].dispatchEvent(new ProgressEvent('loadstart', {loaded: requestBodyTransmitted, total: requestBodyLength}));
    1606                 :        258 : 
    1607                 :        258 :                 // xhr.spec.11.6. If this’s state is not opened or this’s send() flag is unset, then return.
    1608            [ + ]:        258 :                 if(requestData['readyState'] !== xhr.OPENED || !requestData['sendFlag'])
    1609       [ + ][ + ]:        258 :                         return;
    1610                 :        255 : 
    1611                 :        255 :                 // xhr.spec.11.7. Let processRequestBodyChunkLength, given a bytesLength, be these steps:
    1612                 :        255 :                 //                Note: These steps are only invoked when new bytes are transmitted.
    1613            [ + ]:        255 :                 const processRequestBodyChunkLength = () => {
    1614                 :         76 :                         let bytesLength = requestData['requestBody'].length; // @?????
    1615                 :         76 : 
    1616                 :         76 :                         // xhr.spec.11.7.1. Increase requestBodyTransmitted by bytesLength.
    1617                 :         76 :                         requestBodyTransmitted += bytesLength;
    1618                 :         76 : 
    1619                 :         76 :                         // xhr.spec.11.7.2. If not roughly 50ms have passed since these steps were last invoked, then return.
    1620                 :         76 :                         // @todo...
    1621                 :         76 : 
    1622                 :         76 :                         // xhr.spec.11.7.3. If this’s upload listener flag is set, then fire a progress event named progress at this’s upload object
    1623                 :         76 :                         //                  with requestBodyTransmitted and requestBodyLength.
    1624            [ + ]:         76 :                         if(requestData['uploadListenerFlag']){
    1625                 :         19 :                                 requestData['upload'].dispatchEvent(new ProgressEvent('progress', {loaded: requestBodyTransmitted, total: requestBodyLength}));
    1626                 :         19 :                         }
    1627                 :         76 :                 }
    1628                 :        255 : 
    1629                 :        255 :                 // xhr.spec.11.8. Let processRequestEndOfBody be these steps:
    1630            [ + ]:        255 :                 const processRequestEndOfBody = () => {
    1631                 :         71 : 
    1632                 :         71 :                         // xhr.spec.11.8.1. Set this’s upload complete flag.
    1633                 :         71 :                         requestData['uploadCompleteFlag'] = true;
    1634                 :         71 : 
    1635                 :         71 :                         // xhr.spec.11.8.2. If this’s upload listener flag is unset, then return.
    1636       [ + ][ + ]:         71 :                         if(!requestData['uploadListenerFlag']) return;
    1637                 :         15 : 
    1638                 :         15 :                         // xhr.spec.11.8.3. Fire a progress event named progress at this’s upload object with requestBodyTransmitted and requestBodyLength.
    1639                 :         15 :                         // requestData['upload'].dispatchEvent(new ProgressEvent('progress', {loaded: requestBodyTransmitted, total: requestBodyLength}));
    1640                 :         15 : 
    1641                 :         15 :                         // xhr.spec.11.8.4. Fire a progress event named load at this’s upload object with requestBodyTransmitted and requestBodyLength.
    1642                 :         15 :                         requestData['upload'].dispatchEvent(new ProgressEvent('load', {loaded: requestBodyTransmitted, total: requestBodyLength}));
    1643                 :         15 : 
    1644                 :         15 :                         // xhr.spec.11.8.5. Fire a progress event named loadend at this’s upload object with requestBodyTransmitted and requestBodyLength.
    1645                 :         15 :                         requestData['upload'].dispatchEvent(new ProgressEvent('loadend', {loaded: requestBodyTransmitted, total: requestBodyLength}));
    1646                 :         71 :                 }
    1647                 :        255 : 
    1648                 :        255 :                 // xhr.spec.11.9. Let processResponse, given a response, be these steps:
    1649            [ + ]:        255 :                 const processResponse = (response) => {
    1650                 :        497 : 
    1651                 :        497 :                         // xhr.spec.11.9.1. Set this’s response to response.
    1652                 :        497 :                         requestData['response'] = response;
    1653                 :        497 : 
    1654                 :        497 :                         // xhr.spec.11.9.2. Handle errors for this. // @?????
    1655                 :        497 :                         handleError.call(xhr);
    1656                 :        497 : 
    1657                 :        497 :                         // xhr.spec.11.9.3. If this’s response is a network error, then return. // @?????
    1658            [ + ]:        497 :                         if(!response.statusCode){
    1659                 :          1 :                                 setResponseToNetworkError.call(this);
    1660                 :          1 :                                 return;
    1661            [ + ]:          1 :                         }
    1662                 :        238 :                         else
    1663            [ + ]:        238 :                         if( response.headers['location'] &&
    1664                 :         67 :                                 (
    1665            [ + ]:         67 :                                         response.statusCode === 301 ||
    1666            [ + ]:         67 :                                         response.statusCode === 302 ||
    1667            [ + ]:         67 :                                         response.statusCode === 303 ||
    1668            [ + ]:         67 :                                         response.statusCode === 307 ||
    1669                 :          9 :                                         response.statusCode === 308
    1670                 :         67 :                                 )
    1671            [ + ]:        238 :                         ){
    1672            [ + ]:         59 :                                 if(requestData['_redirectCount'] >= 20){
    1673                 :          4 : 
    1674                 :          4 :                                         setResponseToNetworkError.call(xhr);
    1675                 :          4 :                                         handleError.call(xhr);
    1676                 :          4 : 
    1677                 :          4 :                                         return;
    1678            [ + ]:          4 :                                 }
    1679                 :         97 :                                 requestData['_redirectCount']++;
    1680                 :         97 : 
    1681                 :         97 :                                 let loc = response.headers['location'];
    1682                 :         97 : 
    1683                 :         97 :                                 let parsedURL;
    1684                 :         97 :                                 try{
    1685                 :         97 :                                         parsedURL = new URL(loc, new URL(requestData['url']).origin);
    1686                 :         97 :                                 }
    1687                 :         59 :                                 catch(e){
    1688                 :         59 :                                         // xhr.spec.open.6. If parsedURL is failure, then throw a "SyntaxError" DOMException
    1689                 :         59 :                                         throw new DOMException(`XMLHttpRequest.open: an invalid or illegal url string was specified`, 'SyntaxError');
    1690            [ + ]:         59 :                                 }
    1691                 :         97 : 
    1692                 :         97 :                                 requestData['url'] = parsedURL.href;
    1693                 :         97 :                                 requestData['receivedBytes'] = Buffer.alloc(0);
    1694                 :         97 :                                 requestData['responseObject'] = null;
    1695                 :         97 :                                 requestData['sendFlag'] = false;
    1696                 :         97 :                                 requestData['async'] = true;
    1697                 :         97 : 
    1698                 :         97 :                                 if(
    1699                 :         97 :                                         response.statusCode >= 301                    &&
    1700            [ + ]:         59 :                                         response.statusCode <= 303                    &&
    1701            [ + ]:         59 :                                         requestData['method'].toUpperCase() !== 'GET' &&
    1702                 :          4 :                                         requestData['method'].toUpperCase() !== 'HEAD'
    1703            [ + ]:         59 :                                 ){
    1704                 :          4 :                                         requestData['method'] = 'GET';
    1705                 :          4 :                                         requestData['requestBody'] = body = null;
    1706                 :          4 : 
    1707                 :          4 :                                         for(let headerCase in requestData['requestHeadersCase'])
    1708            [ + ]:          4 :                                                 if(
    1709            [ + ]:         15 :                                                         headerCase === 'content-type'     ||
    1710            [ + ]:         15 :                                                         headerCase === 'content-length'   ||
    1711            [ + ]:         15 :                                                         headerCase === 'content-encoding' ||
    1712            [ + ]:         15 :                                                         headerCase === 'content-location' ||
    1713                 :         12 :                                                         headerCase === 'content-language'
    1714            [ + ]:         15 :                                                 ){
    1715                 :          3 :                                                         let header = requestData['requestHeadersCase'][headerCase];
    1716                 :          3 : 
    1717                 :          3 :                                                         delete requestData['requestHeaders'][header];
    1718                 :          3 :                                                         delete requestData['requestHeadersCase'][headerCase];
    1719                 :          3 :                                                 }
    1720            [ + ]:          4 :                                 }
    1721                 :         97 : 
    1722                 :         97 :                                 xhr.onloadstart = null;
    1723                 :         97 : 
    1724                 :         97 :                                 xhr.upload.onloadstart = null;
    1725                 :         97 :                                 xhr.upload.onprogress  = null;
    1726                 :         97 :                                 xhr.upload.onabort     = null;
    1727                 :         97 :                                 xhr.upload.onerror     = null;
    1728                 :         97 :                                 xhr.upload.onload      = null;
    1729                 :         97 :                                 xhr.upload.ontimeout   = null;
    1730                 :         97 :                                 xhr.upload.onloadend   = null;
    1731                 :         97 : 
    1732                 :         97 :                                 xhr.send(body);
    1733                 :         97 : 
    1734                 :         97 :                                 return;
    1735            [ + ]:         97 :                         }
    1736                 :        179 : 
    1737                 :        179 :                         requestData['status']     =  response.statusCode;
    1738                 :        179 :                         requestData['statusText'] =  response.statusMessage;
    1739                 :        179 : 
    1740                 :        179 :                         // xhr.spec.11.9.4. Set this’s state to headers received.
    1741                 :        179 :                         requestData['readyState'] = xhr.HEADERS_RECEIVED;
    1742                 :        179 : 
    1743                 :        179 :                         // xhr.spec.11.9.5. Fire an event named readystatechange at this.
    1744                 :        179 :                         xhr.dispatchEvent(new Event('readystatechange'));
    1745                 :        179 : 
    1746                 :        179 :                         // xhr.spec.11.9.6. If this’s state is not headers received, then return.
    1747       [ + ][ - ]:        497 :                         if(requestData['readyState'] !== xhr.HEADERS_RECEIVED) return;
    1748                 :        179 : 
    1749                 :        179 :                         // xhr.spec.11.9.7. If this’s response’s body is null, then run handle response end-of-body for this and return.
    1750                 :        179 : 
    1751                 :        179 : 
    1752                 :        179 :                         // xhr.spec.11.9.8. Let length be the result of extracting a length from this’s response’s header list.
    1753                 :        179 :                         // xhr.spec.11.9.9. If length is not an integer, then set it to 0.
    1754                 :        179 :                         let length = 0;
    1755                 :        179 : 
    1756            [ + ]:        497 :                         if(response.headers['content-length'] && !isNaN(+response.headers['content-length']))
    1757       [ + ][ + ]:        497 :                                 length = +response.headers['content-length'];
    1758                 :        179 : 
    1759                 :        179 :                         // xhr.spec.11.9.10. Let processBodyChunk given bytes be these steps:
    1760            [ + ]:        179 :                         response.on('data', (chunk) => {
    1761                 :        269 : 
    1762                 :        269 :                                 // xhr.spec.11.9.10.1. Append bytes to this’s received bytes.
    1763                 :        269 :                                 requestData['receivedBytes'] = Buffer.concat([requestData['receivedBytes'], chunk]);
    1764                 :        269 : 
    1765                 :        269 :                                 // xhr.spec.11.9.10.2. If not roughly 50ms have passed since these steps were last invoked, then return.
    1766                 :        269 :                                 // @todo...
    1767                 :        269 : 
    1768                 :        269 :                                 // xhr.spec.11.9.10.3. If this’s state is headers received, then set this’s state to loading.
    1769                 :        269 :                                 if(requestData['readyState'] === xhr.HEADERS_RECEIVED)
    1770            [ + ]:        269 :                                         requestData['readyState'] = xhr.LOADING;
    1771                 :        269 : 
    1772                 :        269 :                                 // xhr.spec.11.9.10.4. Fire an event named readystatechange at this.
    1773                 :        269 :                                 xhr.dispatchEvent(new Event('readystatechange'));
    1774                 :        269 : 
    1775                 :        269 :                                 // xhr.spec.11.9.10.5. Fire a progress event named progress at this with this’s received bytes’s length and length.
    1776                 :        269 :                                 xhr.dispatchEvent(new ProgressEvent('progress', {loaded: requestData['receivedBytes'].length, total: length}));
    1777                 :        179 :                         });
    1778                 :        179 : 
    1779                 :        179 :                         // xhr.spec.11.9.11. Let processEndOfBody be this step: run handle response end-of-body for this.
    1780            [ + ]:        179 :                         response.on('end', () => {
    1781                 :        386 : 
    1782                 :        386 :                                 // xhr.spec.11.9.11.1. Handle errors for this. // @?????
    1783                 :        386 :                                 handleError.call(xhr);
    1784                 :        386 : 
    1785                 :        386 :                                 // xhr.spec.11.9.11.2. If xhr’s response is a network error, then return. // @?????
    1786            [ - ]:        386 :                                 if(!response.statusCode) return;
    1787                 :        386 : 
    1788                 :        386 :                                 // xhr.spec.11.9.11.3. Let transmitted be xhr’s received bytes’s length.
    1789                 :        386 :                                 let transmitted = requestData['receivedBytes'].length;
    1790                 :        386 : 
    1791                 :        386 :                                 // xhr.spec.11.9.11.4. Let length be the result of extracting a length from this’s response’s header list.
    1792                 :        386 :                                 // xhr.spec.11.9.11.5. If length is not an integer, then set it to 0.
    1793                 :        386 :                                 let length = 0;
    1794                 :        386 : 
    1795            [ + ]:        386 :                                 if(response.headers['content-length'] && !isNaN(+response.headers['content-length']))
    1796            [ + ]:        386 :                                         length = +response.headers['content-length'];
    1797                 :        386 : 
    1798                 :        386 :                                 // xhr.spec.11.9.11.6. If xhr’s synchronous flag is unset, then fire a progress event named progress at xhr with transmitted and length.
    1799                 :        386 :                                 // @?????
    1800                 :        386 :                                 if(requestData['async'] && transmitted === 0)
    1801            [ + ]:        386 :                                         xhr.dispatchEvent(new ProgressEvent('progress', {loaded: transmitted, total: length}));
    1802                 :        386 : 
    1803                 :        386 :                                 // xhr.spec.11.9.11.7. Set xhr’s state to done.
    1804                 :        386 :                                 requestData['readyState'] = xhr.DONE;
    1805                 :        386 : 
    1806                 :        386 :                                 // xhr.spec.11.9.11.8. Unset xhr’s send() flag.
    1807                 :        386 :                                 requestData['sendFlag'] = false;
    1808                 :        386 : 
    1809                 :        386 :                                 // xhr.spec.11.9.11.9. Fire an event named readystatechange at xhr.
    1810                 :        386 :                                 xhr.dispatchEvent(new Event('readystatechange'));
    1811                 :        386 : 
    1812                 :        386 :                                 // xhr.spec.11.9.11.10. Fire a progress event named "load" at xhr with transmitted and length.
    1813                 :        386 :                                 xhr.dispatchEvent(new ProgressEvent('load', {loaded: transmitted, total: length}));
    1814                 :        386 : 
    1815                 :        386 :                                 // xhr.spec.11.9.11.11. Fire a progress event named loadend at xhr with transmitted and length.
    1816                 :        386 :                                 xhr.dispatchEvent(new ProgressEvent('loadend', {loaded: transmitted, total: length}));
    1817                 :        179 :                         });
    1818                 :        179 : 
    1819                 :        179 :                         // xhr.spec.11.9.12. Let processBodyError be these steps:
    1820            [ + ]:        179 :                         response.on('error', (error) => {
    1821                 :          3 : 
    1822                 :          3 :                                 // xhr.spec.11.9.12.1. Set this’s response to a network error.
    1823                 :          3 :                                 setResponseToNetworkError.call(xhr);
    1824                 :          3 : 
    1825                 :          3 :                                 // xhr.spec.11.9.12.2  Run handle errors for this.
    1826                 :          3 :                                 handleError.call(xhr, error);
    1827                 :        179 :                         });
    1828                 :        255 :                 }; // @endof const processResponse = (response) => {  ... }
    1829                 :        255 : 
    1830                 :        255 :                 // xhr.spec.11.10. Set this’s fetch controller to the result of fetching req ... ???????????????????????????????????????????????????
    1831                 :        255 :                 let clientRequest = null;
    1832                 :        255 : 
    1833                 :        255 :                 try{
    1834                 :        255 :                         clientRequest = requestData['fetchController'] = doClientRequest(clientRequestOptions);
    1835       [ + ][ + ]:        258 :                 }catch(err){
    1836                 :          3 : 
    1837                 :          3 :                         // xhr.spec.11.9.12.1. Set this’s response to a network error.
    1838                 :          3 :                         setResponseToNetworkError.call(xhr);
    1839                 :          3 : 
    1840                 :          3 :                         // xhr.spec.11.9.12.2  Run handle errors for this.
    1841                 :          3 :                         handleError.call(xhr, err);
    1842                 :          3 : 
    1843                 :          3 :                         return;
    1844            [ + ]:          3 :                 }
    1845                 :          3 : 
    1846            [ + ]:          3 :                 clientRequest.on('close', () => {
    1847                 :          3 :                 });
    1848                 :          3 : 
    1849            [ + ]:          3 :                 clientRequest.on('error', (err) => {
    1850                 :         27 :                         setResponseToNetworkError.call(xhr);
    1851                 :         27 :                         handleError.call(xhr, err);
    1852                 :          3 :                 });
    1853                 :          3 : 
    1854                 :          3 :                 // xhr.spec.11.7. Note: These steps are only invoked when new bytes are transmitted.
    1855            [ + ]:        258 :                 if(requestData['requestBody']){
    1856                 :         30 :                         clientRequest.setHeader('Content-Length', requestData['requestBody'].length);
    1857                 :         30 : 
    1858            [ + ]:         30 :                         (async () => {
    1859                 :         76 :                                 let buffer;
    1860                 :         76 : 
    1861            [ + ]:         76 :                                 if(requestData['requestBody'].source instanceof Blob){
    1862                 :          7 :                                         buffer = Buffer.from (await requestData['requestBody'].source.arrayBuffer());
    1863            [ + ]:          7 :                                 }
    1864                 :         23 :                                 else{
    1865                 :         23 :                                         buffer = await Promise.resolve(requestData['requestBody'].source);
    1866                 :         23 :                                 }
    1867                 :         76 : 
    1868                 :         76 :                                 clientRequest.write(buffer, processRequestBodyChunkLength); // ?????????????????????????????
    1869                 :         76 : 
    1870                 :         76 :                                 // xhr.spec.11.8. Let processRequestEndOfBody be these steps:
    1871                 :         76 :                                 clientRequest.end(processRequestEndOfBody);
    1872                 :         30 :                         })();
    1873       [ + ][ + ]:         30 :                 }
    1874                 :          3 :                 else{
    1875                 :          3 :                         clientRequest.end();
    1876            [ + ]:          3 :                 }
    1877                 :          3 : 
    1878                 :          3 :                 // xhr.spec.11.9. Let processResponse, given a response, be these steps:
    1879                 :          3 :                 clientRequest.on('response', processResponse);
    1880                 :          3 : 
    1881                 :          3 :                 // xhr.spec.11.11. Let now be the present time.
    1882                 :          3 :                 let now = Date.now();
    1883                 :          3 : 
    1884                 :          3 :                 // xhr.spec.11.12. Run these steps in parallel:
    1885                 :          3 :                 // xhr.spec.11.12.1. Wait until either req’s done flag is set or this’s timeout is not 0 and this’s timeout milliseconds have passed since now.
    1886                 :          3 :                 // xhr.spec.11.12.2. If req’s done flag is unset, then set this’s timed out flag and terminate this’s fetch controller.
    1887                 :          3 : 
    1888            [ + ]:        258 :                 if(requestData['timeout']){
    1889            [ + ]:          3 :                         setTimeout(() => {
    1890                 :          3 :                                 if(requestData['readyState'] !== xhr.DONE){
    1891                 :          3 :                                         requestData['timeoutFlag'] = true;
    1892                 :          3 :                                         handleError.call(xhr);
    1893                 :          3 :                                 }
    1894                 :          3 :                         }, requestData['timeout']);
    1895                 :          3 :                 }
    1896            [ + ]:        258 :         }
    1897                 :        225 :         // xhr.spec.12. Otherwise, if this’s synchronous flag is set:
    1898                 :        225 :         else
    1899                 :        225 :         {
    1900                 :        225 :                 // xhr.spec.12.1. Let <processedResponse> be false.
    1901                 :        225 :                 // xhr.spec.12.2. Let <processResponseConsumeBody>, given a <response> and <nullOrFailureOrBytes>, be these steps:
    1902                 :        225 :                 // xhr.spec.12.2.1. If <nullOrFailureOrBytes> is not failure, then set this’s response to response.
    1903                 :        225 :                 // xhr.spec.12.2.2. If <nullOrFailureOrBytes> is a byte sequence, then append nullOrFailureOrBytes to this’s received bytes.
    1904                 :        225 :                 // xhr.spec.12.2.3. Set <processedResponse> to true.
    1905                 :        225 : 
    1906                 :        225 :                 // xhr.spec.12.3. Set this’s fetch controller to the result of fetching req with <processResponseConsumeBody> set to processResponseConsumeBody
    1907                 :        225 :                 //                and useParallelQueue set to true.
    1908                 :        225 :                 // xhr.spec.12.4. Let now be the present time.
    1909                 :        225 :                 // xhr.spec.12.5. Pause until either processedResponse is true or this’s timeout is not 0 and this’s timeout milliseconds have passed since now.
    1910                 :        225 :                 // xhr.spec.12.6. If processedResponse is false, then set this’s timed out flag and terminate this’s fetch controller.
    1911                 :        225 :                 // xhr.spec.12.7. Report timing for this’s fetch controller given the current global object.
    1912                 :        225 :                 // xhr.spec.12.8. Run handle response end-of-body for this.
    1913                 :        225 : 
    1914                 :        225 :                 const contentFile = '.whatwg-xhr-content-' + process.pid;
    1915                 :        225 :                 const syncFile    = '.whatwg-xhr-sync-'    + process.pid;
    1916                 :        225 : 
    1917                 :        225 :                 fs.writeFileSync(syncFile, '', 'utf8');
    1918                 :        225 : 
    1919                 :        225 :                 let defaultHeadersObj = defaultHeaders();
    1920                 :        225 : 
    1921            [ + ]:        225 :                 for(let name in defaultHeadersObj){
    1922            [ + ]:        675 :                         if(req_headers[name] && req_headers[name] === defaultHeadersObj[name]){
    1923                 :        672 :                                 delete req_headers[name];
    1924                 :        672 :                                 delete req_headersCase[name.toLowerCase()];
    1925                 :        672 :                         }
    1926                 :        675 :                 }
    1927                 :        225 : 
    1928                 :        225 :                 let headersJSON = JSON.stringify(req_headers);
    1929                 :        225 : 
    1930            [ + ]:        225 :                 let bodyFlag = body !== null && body !== '';
    1931                 :        225 : 
    1932                 :        225 : const execString = `
    1933                 :        225 :         (async () => {
    1934                 :        225 :                 let fs                 = await import('node:fs');
    1935                 :        225 :                 let { XMLHttpRequest } = await import('${__filename}');
    1936                 :        225 : 
    1937                 :        225 :                 let xhr = new XMLHttpRequest;
    1938                 :        225 : 
    1939                 :        225 :                 let requestData = {};
    1940                 :        225 : 
    1941                 :        225 :                 xhr.onload = () => {
    1942                 :        225 :                         requestData['error'] = null;
    1943                 :        225 : 
    1944                 :        225 :                         requestData['status']     = xhr.status;
    1945                 :        225 :                         requestData['statusText'] = xhr.statusText;
    1946                 :        225 : 
    1947                 :        225 :                         requestData['response'       ] = xhr.response;
    1948                 :        225 :                         requestData['responseText'   ] = xhr.responseText;
    1949                 :        225 :                         requestData['responseType'   ] = xhr.responseType;
    1950                 :        225 :                         requestData['responseURL'    ] = xhr.responseURL;
    1951                 :        225 :                         requestData['responseXML'    ] = xhr.responseXML;
    1952                 :        225 :                         requestData['responseHeaders'] = xhr.getAllResponseHeaders();
    1953                 :        225 :                 };
    1954                 :        225 : 
    1955                 :        225 :                 xhr.onerror = (e) => {
    1956                 :        225 :                         requestData['error'] = e;
    1957                 :        225 :                 }
    1958                 :        225 : 
    1959                 :        225 :                 xhr.onloadend = () => {
    1960                 :        225 :                         fs.writeFileSync('${contentFile}', JSON.stringify(requestData, null, 2), 'utf8');
    1961                 :        225 :                         fs.unlinkSync('${syncFile}');
    1962                 :        225 :                 }
    1963                 :        225 : 
    1964                 :        225 :                 xhr.open('${req_method}', '${req_url}');
    1965                 :        225 : 
    1966                 :        225 :                 let headers = JSON.parse(process.argv[1]);
    1967                 :        225 :                 for(let k in headers){
    1968                 :        225 :                         xhr.setRequestHeader(k, headers[k]);
    1969                 :        225 :                 }
    1970                 :        225 : 
    1971                 :        225 :                 if(!${bodyFlag})
    1972                 :        225 :                         xhr.send();
    1973                 :        225 : 
    1974                 :        225 :                 let body = Buffer.alloc(0);
    1975                 :        225 : 
    1976                 :        225 :                 process.stdin.on('data', (chunk) => {
    1977                 :        225 :                         body = Buffer.concat([body, chunk]);
    1978                 :        225 :                         xhr.send(body);
    1979                 :        225 :                 });
    1980                 :        225 :         })();
    1981                 :        225 : `;
    1982                 :        225 : 
    1983                 :        225 :                 let syncProc = spawn(process.argv[0], ['-e', execString, headersJSON]);
    1984                 :        225 : 
    1985       [ + ][ + ]:        225 :                 if(bodyFlag && requestData['requestBody'].source instanceof Blob){
    1986                 :         10 : 
    1987                 :         10 :                         const contentBlob = '.whatwg-xhr-contentBlob-' + process.pid;
    1988                 :         10 :                         const syncBlob    = '.whatwg-xhr-syncBlob-'    + process.pid;
    1989                 :         10 : 
    1990                 :         10 :                         fs.writeFileSync(syncBlob, '', 'utf8');
    1991                 :         10 : 
    1992                 :         10 :                         let threadCode = `\
    1993                 :         10 :         const fs      = require('node:fs');
    1994                 :         10 :         const threads = require('node:worker_threads');
    1995                 :         10 : 
    1996                 :         10 :         threads.parentPort.once('message', (data) => {
    1997                 :         10 :                 data.arrayBuffer()
    1998                 :         10 :                         .then(arrayBuffer => Buffer.from(arrayBuffer))
    1999                 :         10 :                         .then(buf => {
    2000                 :         10 :                                 fs.writeFileSync('${contentBlob}', buf);
    2001                 :         10 :                                 fs.unlinkSync('${syncBlob}');
    2002                 :         10 :                         });
    2003                 :         10 :         });
    2004                 :         10 : `;
    2005                 :         10 : 
    2006                 :         10 :                         let worker = new threads.Worker(threadCode, {eval: true});
    2007                 :         10 : 
    2008                 :         10 :                         worker.postMessage(requestData['requestBody'].source);
    2009                 :         10 : 
    2010            [ + ]:         10 :                         while(fs.existsSync(syncBlob));
    2011                 :         10 :                         requestData['requestBody'].source = fs.readFileSync(contentBlob);
    2012                 :         10 :                         fs.unlinkSync(contentBlob);
    2013                 :         10 : 
    2014                 :         10 :                         syncProc.stdin.write(requestData['requestBody'].source);
    2015            [ + ]:         10 :                 }
    2016                 :        215 :                 else
    2017            [ + ]:        215 :                 if(bodyFlag){
    2018                 :         36 :                         syncProc.stdin.write(requestData['requestBody'].source);
    2019                 :         36 :                 }
    2020                 :        225 : 
    2021                 :        225 :         syncProc.stderr.on('data', (chunk) => {
    2022                 :          0 :                 let msg = chunk.toString();
    2023                 :          0 : 
    2024                 :          0 :                 setResponseToNetworkError.call(xhr);
    2025                 :          0 :                 handleError.call(xhr, new Error(msg));
    2026                 :          0 : 
    2027                 :          0 :                 process.exit(1);
    2028                 :        225 :         });
    2029                 :        225 : 
    2030            [ + ]:        225 :                 while(fs.existsSync(syncFile));
    2031                 :        225 :                 syncProc.stdin.end();
    2032                 :        225 :                 processResult();
    2033                 :        225 : 
    2034            [ + ]:        225 :                 function processResult(){
    2035                 :        225 : 
    2036            [ - ]:        225 :                         let _requestData = JSON.parse(fs.readFileSync(contentFile, 'utf8')) || {};
    2037                 :        225 :                         fs.unlinkSync(contentFile);
    2038                 :        225 : 
    2039            [ + ]:        225 :                         if(_requestData['status']){
    2040                 :        209 : 
    2041                 :        209 :                                 let response = {};
    2042                 :        209 : 
    2043                 :        209 :                                 requestData['status']     = response.statusCode    = _requestData['status'];
    2044                 :        209 :                                 requestData['statusText'] = response.statusMessage = _requestData['statusText'];
    2045                 :        209 : 
    2046                 :        209 :                                 requestData['responseType'] = _requestData['responseType'];
    2047                 :        209 :                                 requestData['responseURL' ] = _requestData['responseURL' ];
    2048                 :        209 :                                 requestData['responseXML' ] = _requestData['responseXML' ];
    2049                 :        209 : 
    2050                 :        209 :                                 response.url = _requestData['responseURL'];
    2051                 :        209 : 
    2052                 :        209 :                                 _requestData['responseHeaders'] = _requestData['responseHeaders'].split('\r\n');
    2053                 :        209 :                                 _requestData['responseHeaders'].pop();
    2054                 :        209 : 
    2055                 :        209 :                                 response.headers = {};
    2056            [ + ]:        209 :                                 for(let header of _requestData['responseHeaders']){
    2057                 :       1050 :                                         let [name, value] = header.split('\x3A\x20');
    2058                 :       1050 :                                         response.headers[name] = value;
    2059                 :       1050 :                                 }
    2060                 :        209 : 
    2061                 :        209 :                                 response.rawHeaders = [];
    2062            [ + ]:        209 :                                 for(let k in response.headers){
    2063                 :       1050 :                                         response.rawHeaders.push(k);
    2064                 :       1050 :                                         response.rawHeaders.push(response.headers[k]);
    2065                 :       1050 :                                 }
    2066                 :        209 : 
    2067            [ + ]:        209 :                                 if(_requestData['response']){
    2068                 :        106 :                                         let chunk = Buffer.from(_requestData['response']);
    2069                 :        106 :                                         requestData['receivedBytes'] = Buffer.concat([requestData['receivedBytes'], chunk]);
    2070                 :        106 :                                 }
    2071                 :        209 : 
    2072                 :        209 :                                 requestData['response'] = response;
    2073                 :        209 : 
    2074                 :        209 :                                 // xhr.spec.11.9.11.7. Set xhr’s state to done.
    2075                 :        209 :                                 requestData['readyState'] = xhr.DONE;
    2076                 :        209 : 
    2077                 :        209 :                                 // xhr.spec.11.9.11.8. Unset xhr’s send() flag.
    2078                 :        209 :                                 requestData['sendFlag'] = false;
    2079                 :        209 : 
    2080                 :        209 :                                 // xhr.spec.11.9.11.9. Fire an event named readystatechange at xhr.
    2081                 :        209 :                                 xhr.dispatchEvent(new Event('readystatechange'));
    2082                 :        209 : 
    2083                 :        209 :                                 // xhr.spec.11.9.11.10. Fire a progress event named "load" at xhr with transmitted and length.
    2084                 :        209 :                                 xhr.dispatchEvent(new ProgressEvent('load', {loaded: requestData['receivedBytes'].length, total: requestData['receivedBytes'].length}));
    2085                 :        209 : 
    2086                 :        209 :                                 // xhr.spec.11.9.11.11. Fire a progress event named loadend at xhr with transmitted and length.
    2087                 :        209 :                                 xhr.dispatchEvent(new ProgressEvent('loadend', {loaded: requestData['receivedBytes'].length, total: requestData['receivedBytes'].length}));
    2088            [ + ]:        209 :                         }
    2089                 :         16 :                         else{
    2090                 :         16 :                                 // xhr.spec.11.9.12.1. Set this’s response to a network error.
    2091                 :         16 :                                 setResponseToNetworkError.call(xhr);
    2092                 :         16 : 
    2093                 :         16 :                                 // xhr.spec.11.9.12.2  Run handle errors for this.
    2094                 :         16 :                                 handleError.call(xhr);
    2095                 :         16 :                         }
    2096                 :        225 :                 }
    2097                 :        225 :         }
    2098                 :        348 : }; // @endof method XMLHttpRequest.prototype.send
    2099                 :        348 : 
    2100                 :        348 : /**
    2101                 :        348 :  * XMLHttpRequest Living Standard — Last Updated 20 February 2023
    2102                 :        348 :  * url: https://xhr.spec.whatwg.org/#the-getresponseheader()-method
    2103                 :        348 :  *
    2104                 :        348 :  * client.getResponseHeader(name)
    2105                 :        348 :  *   The getResponseHeader(name) method steps are to return the result of getting name from this’s response’s header list.
    2106                 :        348 :  *
    2107                 :        348 :  * @method   getResponseHeader
    2108                 :        348 :  * @instance
    2109                 :        348 :  * @memberof module:whatwg-xhr.XMLHttpRequest
    2110                 :        348 :  * @param    {string} name - The name of the header whose text value is required.
    2111                 :        348 :  * @return   {string|null} The header text value or null.
    2112                 :        348 :  * @desc     XMLHttpRequest method that returns the string containing the text of a particular header's value.
    2113                 :        348 :  */
    2114            [ + ]:        348 : XMLHttpRequest.prototype.getResponseHeader = function getResponseHeader(name){
    2115                 :        263 : 
    2116                 :        263 :         // @author: validate the number of arguments
    2117                 :        263 :         if(arguments.length < 1)
    2118            [ - ]:        263 :                 throw new TypeError(`XMLHttpRequest.getResponseHeader: At least 1 argument required, but only ${arguments.length} passed`);     // firefox 102
    2119                 :        263 : 
    2120                 :        263 :         const requestData = xmlHttpRequest.get(this);
    2121                 :        263 : 
    2122       [ + ][ + ]:        263 :         if(!requestData['response']) return null;
    2123                 :        248 : 
    2124                 :        248 :         if(typeof name === 'symbol')
    2125       [ - ][ + ]:        263 :                 throw new TypeError(`can't convert symbol to string`);
    2126                 :        248 : 
    2127                 :        248 :         let headerName = String(name).toLowerCase();
    2128                 :        248 :         let responseHeaders = {};
    2129                 :        248 : 
    2130                 :        248 :         for(let headerName in requestData['response'].headers)
    2131       [ + ][ + ]:        263 :                 responseHeaders[headerName.toLowerCase()] = requestData['response'].headers[headerName];
    2132                 :        248 : 
    2133            [ + ]:        263 :         if(headerName in responseHeaders && !headerName.startsWith('set-cookie'))
    2134       [ + ][ + ]:        263 :                 return responseHeaders[headerName];
    2135                 :         31 : 
    2136                 :         31 :         return null;
    2137                 :         31 : 
    2138                 :        348 : }; // @endof method XMLHttpRequest.prototype.getResponseHeader
    2139                 :        348 : 
    2140                 :        348 : /**
    2141                 :        348 :  * XMLHttpRequest Living Standard — Last Updated 20 February 2023
    2142                 :        348 :  * url: https://xhr.spec.whatwg.org/#the-getallresponseheaders()-method
    2143                 :        348 :  *
    2144                 :        348 :  * client.getAllResponseHeaders()
    2145                 :        348 :  *   The getAllResponseHeaders() method steps are:
    2146                 :        348 :  *   1. Let <output> be an empty byte sequence.
    2147                 :        348 :  *   2. Let <initialHeaders> be the result of running <sort and combine> with this’s response’s header list.
    2148                 :        348 :  *   3. Let <headers> be the result of sorting initialHeaders in ascending order, with a being less than b if a’s name is legacy-uppercased-byte less than b’s name.
    2149                 :        348 :  *      Note: Unfortunately, this is needed for compatibility with deployed content.
    2150                 :        348 :  *   4. For each <header> in <headers>, append <header>’s name, followed by a 0x3A 0x20 byte pair, followed by <header>’s value,
    2151                 :        348 :  *      followed by a 0x0D 0x0A byte pair, to <output>.
    2152                 :        348 :  *   5. Return <output>.
    2153                 :        348 :  *
    2154                 :        348 :  * @method   getAllResponseHeaders
    2155                 :        348 :  * @instance
    2156                 :        348 :  * @memberof module:whatwg-xhr.XMLHttpRequest
    2157                 :        348 :  * @return   {string|null} A string representing all of the response's headers, or null if no response has been received.
    2158                 :        348 :  * @desc     XMLHttpRequest method that returns all the response headers, separated by CRLF, as a string, or null if no response.
    2159                 :        348 :  */
    2160            [ + ]:        348 : XMLHttpRequest.prototype.getAllResponseHeaders = function getAllResponseHeaders(){
    2161                 :        236 : 
    2162                 :        236 :         const requestData = xmlHttpRequest.get(this);
    2163                 :        236 : 
    2164       [ + ][ + ]:        236 :         if(!requestData['response']) return '';
    2165                 :         18 : 
    2166                 :         18 :         // xhr.spec.1. Let <output> be an empty byte sequence.
    2167                 :         18 :         let output = '';
    2168                 :         18 : 
    2169                 :         18 :         // xhr.spec.2. Let <initialHeaders> be the result of running <sort and combine>...
    2170                 :         18 :         let initialHeaders = requestData['response'].headers;
    2171                 :         18 : 
    2172                 :         18 :         // xhr.spec.3. Let <headers> be the result of sorting initialHeaders in ascending order...
    2173                 :         18 :         let headers = Object.entries(initialHeaders);
    2174                 :         18 : 
    2175            [ + ]:         18 :         headers.sort((a, b) => {
    2176                 :       1961 :                 if(a[0].toUpperCase() > b[0].toUpperCase())
    2177  [ + ][ + ][ + ]:       1961 :                         return 1;
    2178                 :          8 :                 else
    2179                 :          8 :                         return -1;
    2180                 :         18 :         });
    2181                 :         18 : 
    2182                 :         18 :         // xhr.spec.4. For each <header> in <headers>, append <header>’s name, followed by a 0x3A 0x20 byte pair, followed by <header>’s value,
    2183                 :         18 :         //             followed by a 0x0D 0x0A byte pair, to output.
    2184                 :         18 : 
    2185            [ + ]:        236 :         for(let header of headers){
    2186                 :       1130 :                 if(!header[0].toLowerCase().startsWith('set-cookie'))
    2187            [ + ]:       1130 :                         output += header[0] + '\x3A' + '\x20' + header[1] + '\x0D' + '\x0A';
    2188            [ + ]:       1130 :         }
    2189                 :         18 :         return output;
    2190                 :         18 : 
    2191                 :        348 : }; // @endof method XMLHttpRequest.prototype.getAllResponseHeaders
    2192                 :        348 : 
    2193                 :        348 : /**
    2194                 :        348 :  * XMLHttpRequest Living Standard — Last Updated 20 February 2023
    2195                 :        348 :  * url: https://xhr.spec.whatwg.org/#the-overridemimetype()-method
    2196                 :        348 :  *
    2197                 :        348 :  * client.overrideMimeType(mime)
    2198                 :        348 :  * Acts as if the `Content-Type` header value for a response is mime. (It does not change the header.)
    2199                 :        348 :  * Throws an "InvalidStateError" DOMException if state is loading or done.
    2200                 :        348 :  *
    2201                 :        348 :  * The overrideMimeType(mime) method steps are:
    2202                 :        348 :  *   1. If this’s state is loading or done, then throw an "InvalidStateError" DOMException.
    2203                 :        348 :  *   2. Set this’s override MIME type to the result of parsing mime.
    2204                 :        348 :  *   3. If this’s override MIME type is failure, then set this’s override MIME type to application/octet-stream.
    2205                 :        348 :  *
    2206                 :        348 :  * @method    overrideMimeType
    2207                 :        348 :  * @instance
    2208                 :        348 :  * @memberof  module:whatwg-xhr.XMLHttpRequest
    2209                 :        348 :  * @param     {string} mime - MIME type to use instead of the one specified by the server.
    2210                 :        348 :  * @desc      XMLHttpRequest method that specifies a MIME type other than the one provided by the server.
    2211                 :        348 :  * @requires  module:whatwg-misc.parseMIMEType
    2212                 :        348 :  * @requires  module:whatwg-misc.serializeAMimeType
    2213                 :        348 :  */
    2214            [ + ]:        348 : XMLHttpRequest.prototype.overrideMimeType = function overrideMimeType(mime){
    2215                 :          6 : 
    2216                 :          6 :         // @author: validate the number of arguments
    2217                 :          6 :         if(arguments.length < 1)
    2218            [ - ]:          6 :                 throw new TypeError(`XMLHttpRequest.overrideMimeType: At least 1 argument required, but only 0 passed`);        // firefox 102
    2219                 :          6 : 
    2220                 :          6 :         const requestData = xmlHttpRequest.get(this);
    2221                 :          6 : 
    2222                 :          6 :         // xhr.spec.1. If this’s state is loading or done, then throw an "InvalidStateError" DOMException.
    2223            [ + ]:          6 :         if(requestData['readyState'] === this.LOADING || requestData['readyState'] === this.DONE)
    2224       [ + ][ + ]:          6 :                 throw new DOMException(`XMLHttpRequest.overrideMimeType: Cannot call 'overrideMimeType()' on XMLHttpRequest after 'send()' (when its state is LOADING or DONE).`, 'InvalidStateError'); // firefox 102
    2225                 :          5 : 
    2226                 :          5 :         let parsedMime = parseMIMEType(String(mime));
    2227                 :          5 : 
    2228            [ + ]:          6 :         if(parsedMime !== 'failure'){
    2229                 :          2 :                 // xhr.spec.2. Set this’s override MIME type to the result of parsing mime.
    2230                 :          2 :                 requestData['overrideMimeType'] = serializeAMimeType(parsedMime);
    2231            [ + ]:          2 :         }
    2232                 :          3 :         else{
    2233                 :          3 :                 // xhr.spec.3. If this’s override MIME type is failure, then set this’s override MIME type to application/octet-stream.
    2234                 :          3 :                 requestData['overrideMimeType'] = 'application/octet-stream';
    2235                 :          3 :         }
    2236                 :        348 : }; // @endof method XMLHttpRequest.prototype.overrideMimeType
    2237                 :        348 : 
    2238                 :        348 : /**
    2239                 :        348 :  * XMLHttpRequest Living Standard — Last Updated 20 February 2023
    2240                 :        348 :  * url: https://xhr.spec.whatwg.org/#interface-progressevent
    2241                 :        348 :  *
    2242                 :        348 :  * interface ProgressEvent : Event {
    2243                 :        348 :  *   constructor(DOMString type, optional ProgressEventInit eventInitDict = {});
    2244                 :        348 :  *
    2245                 :        348 :  *   readonly attribute boolean lengthComputable;
    2246                 :        348 :  *   readonly attribute unsigned long long loaded;
    2247                 :        348 :  *   readonly attribute unsigned long long total;
    2248                 :        348 :  * };
    2249                 :        348 :  *
    2250                 :        348 :  * dictionary ProgressEventInit : EventInit {
    2251                 :        348 :  *   boolean lengthComputable = false;
    2252                 :        348 :  *   unsigned long long loaded = 0;
    2253                 :        348 :  *   unsigned long long total = 0;
    2254                 :        348 :  * };
    2255                 :        348 :  *
    2256                 :        348 :  * @class     ProgressEvent
    2257                 :        348 :  * @extends   module:whatwg-xhr~Event
    2258                 :        348 :  * @static
    2259                 :        348 :  * @desc      Interface that represents events measuring progress of an underlying process, like an HTTP request for an XMLHttpRequest client.
    2260                 :        348 :  */
    2261                 :        348 : export class ProgressEvent extends Event{
    2262                 :        348 : 
    2263                 :        348 :         /**
    2264                 :        348 :          * @method   constructor
    2265                 :        348 :          * @instance
    2266                 :        348 :          * @memberof module:whatwg-xhr.ProgressEvent
    2267                 :        348 :          * @param    {string} type - A case-sensitive name of the event.
    2268                 :        348 :          * @param    {object} eventInitDict - (Optional) An object that, in addition to the properties defined in Event(), can have lengthComputable, loaded and total.
    2269                 :        348 :          * @desc     Constructs a new ProfressEvent object.
    2270                 :        348 :          */
    2271            [ + ]:        348 :         constructor(type, eventInitDict = {}){
    2272                 :       2301 :                 if(arguments.length < 1)
    2273            [ - ]:       2301 :                         throw new TypeError(`ProgressEvent constructor: At least 1 argument required, but only 0 passed`);      // firefox 102
    2274                 :       2301 : 
    2275                 :       2301 :                 const progressEventData = {};
    2276                 :       2301 : 
    2277                 :       2301 :                 progressEventData['type']             = String(type);
    2278                 :       2301 :                 progressEventData['lengthComputable'] = false;
    2279                 :       2301 :                 progressEventData['loaded']           = 0;
    2280                 :       2301 :                 progressEventData['total']            = 0;
    2281                 :       2301 : 
    2282                 :       2301 :                 if(eventInitDict !== undefined && eventInitDict !== null){
    2283            [ - ]:       2301 :                         if(typeof eventInitDict !== 'object' && typeof eventInitDict !== 'function')
    2284            [ - ]:       2301 :                                 throw new TypeError(`ProgressEvent constructor: Value can't be converted to a dictionary.`);    // firefox 102
    2285                 :       2301 : 
    2286                 :       2301 :                         if(eventInitDict.loaded !== undefined)
    2287       [ + ][ - ]:       2301 :                                 progressEventData['loaded'] = isNaN(eventInitDict.loaded) ? 0 : Number(eventInitDict.loaded);
    2288                 :       2301 : 
    2289                 :       2301 :                         if(eventInitDict.total !== undefined)
    2290       [ + ][ - ]:       2301 :                                 progressEventData['total'] = isNaN(eventInitDict.total) ? 0 : Number(eventInitDict.total);
    2291                 :       2301 : 
    2292                 :       2301 :                         if(eventInitDict.lengthComputable !== undefined)
    2293       [ + ][ + ]:       2301 :                                 progressEventData['lengthComputable'] = Boolean(eventInitDict.lengthComputable);
    2294                 :       1368 :                         else
    2295                 :       1368 :                                 progressEventData['lengthComputable'] = progressEventData['total'] !== 0;
    2296                 :       2301 : 
    2297                 :       2301 :                         let eventInit = {
    2298                 :       2301 :                                 bubbles:    Boolean(eventInitDict['bubbles']),
    2299                 :       2301 :                                 cancelable: Boolean(eventInitDict['cancelable']),
    2300                 :       2301 :                                 composed:   Boolean(eventInitDict['composed'])
    2301                 :       2301 :                         };
    2302                 :       2301 : 
    2303                 :       2301 :                         super(type, eventInit);
    2304            [ - ]:       2301 :                 }
    2305                 :          0 :                 else
    2306                 :          0 :                         super(type);
    2307                 :       2301 : 
    2308                 :       2301 :                 progressEvent.set(this, progressEventData);
    2309                 :       2301 :         }
    2310                 :        348 : 
    2311                 :        348 :         /**
    2312                 :        348 :          * @member   {boolean} lengthComputable
    2313                 :        348 :          * @memberof module:whatwg-xhr.ProgressEvent
    2314                 :        348 :          * @readonly
    2315                 :        348 :          * @default  false
    2316                 :        348 :          * @instance
    2317                 :        348 :          * @desc     A boolean value indicating if the total work to be done, and the amount of work already done, by the underlying process is calculable.
    2318                 :        348 :          */
    2319            [ + ]:        348 :         get lengthComputable(){ return progressEvent.get(this)['lengthComputable']; }
    2320                 :        348 : 
    2321                 :        348 :         /**
    2322                 :        348 :          * @member   {number} loaded
    2323                 :        348 :          * @memberof module:whatwg-xhr.ProgressEvent
    2324                 :        348 :          * @readonly
    2325                 :        348 :          * @default  0
    2326                 :        348 :          * @instance
    2327                 :        348 :          * @desc     A number representing the amount of work already performed by the underlying process.
    2328                 :        348 :          */
    2329            [ + ]:        348 :         get loaded(){ return progressEvent.get(this)['loaded']; }
    2330                 :        348 : 
    2331                 :        348 :         /**
    2332                 :        348 :          * @member   {number} total
    2333                 :        348 :          * @memberof module:whatwg-xhr.ProgressEvent
    2334                 :        348 :          * @readonly
    2335                 :        348 :          * @default  0
    2336                 :        348 :          * @instance
    2337                 :        348 :          * @desc     A number representing the total amount of work that the underlying process is in the progress of performing.
    2338                 :        348 :          */
    2339            [ + ]:        348 :         get total(){ return progressEvent.get(this)['total']; }
    2340                 :        348 : 
    2341                 :        348 : } // @endOf class ProgressEvent extends Event
    2342                 :        348 : 
    2343                 :        348 : Object.defineProperty(ProgressEvent.prototype, 'lengthComputable', {enumerable: true});
    2344                 :        348 : Object.defineProperty(ProgressEvent.prototype, 'loaded', {enumerable: true});
    2345                 :        348 : Object.defineProperty(ProgressEvent.prototype, 'total', {enumerable: true});
    2346                 :        348 : 
    2347                 :        348 : Object.defineProperty(ProgressEvent.prototype, Symbol.toStringTag, {value: 'ProgressEvent', writable: false, enumerable: false, configurable: true});
    2348                 :        348 : 
    2349                 :        348 : /**
    2350                 :        348 :  * XMLHttpRequest Living Standard — Last Updated 20 February 2023
    2351                 :        348 :  * url: https://xhr.spec.whatwg.org/#formdata
    2352                 :        348 :  *
    2353                 :        348 :  * interface FormData {
    2354                 :        348 :  *   constructor(optional HTMLFormElement form, optional HTMLElement? submitter = null);
    2355                 :        348 :  *
    2356                 :        348 :  *   undefined append(USVString name, USVString value);
    2357                 :        348 :  *   undefined append(USVString name, Blob blobValue, optional USVString filename);
    2358                 :        348 :  *   undefined delete(USVString name);
    2359                 :        348 :  *
    2360                 :        348 :  *   FormDataEntryValue?          get(USVString name);
    2361                 :        348 :  *   sequence<FormDataEntryValue> getAll(USVString name);
    2362                 :        348 :  *
    2363                 :        348 :  *   boolean   has(USVString name);
    2364                 :        348 :  *   undefined set(USVString name, USVString value);
    2365                 :        348 :  *   undefined set(USVString name, Blob blobValue, optional USVString filename);
    2366                 :        348 :  *
    2367                 :        348 :  *   iterable<USVString, FormDataEntryValue>;
    2368                 :        348 :  * };
    2369                 :        348 :  *
    2370                 :        348 :  * @class FormData
    2371                 :        348 :  * @static
    2372                 :        348 :  * @desc  An interface that provides a way to construct a set of key/value pairs representing form fields and their values.
    2373                 :        348 :  */
    2374                 :        348 : export class FormData{
    2375                 :        348 :         /**
    2376                 :        348 :          * @method   constructor
    2377                 :        348 :          * @instance
    2378                 :        348 :          * @memberof module:whatwg-xhr.FormData
    2379                 :        348 :          * @param    {FormData}    form     - (Optional) The FormData object will be populated with the form's current keys/values.
    2380                 :        348 :          * @param    {string|Blob} value    - (Optional) A submit button that is a member of the form.
    2381                 :        348 :          * @desc     Constructs a new FormData object.
    2382                 :        348 :          */
    2383                 :        348 :         constructor(form, submitter){
    2384                 :          0 : 
    2385                 :          0 :                 if(arguments.length === 0 || !globalThis.HTMLFormElement){
    2386                 :          0 :                         const entryList = [];
    2387                 :          0 :                         formData.set(this, entryList);
    2388                 :          0 :                 }
    2389                 :          0 :                 else
    2390                 :          0 :                 if(globalThis.HTMLFormElement){
    2391                 :          0 : 
    2392                 :          0 :                         if(form === null || typeof form !== 'object')
    2393                 :          0 :                                 throw new TypeError('FormData constructor: Argument 1 is not an object.');
    2394                 :          0 : 
    2395                 :          0 :                         if(!(form instanceof globalThis.HTMLFormElement))
    2396                 :          0 :                                 throw new TypeError(' FormData constructor: Argument 1 does not implement interface HTMLFormElement.');
    2397                 :          0 :                 }
    2398                 :          0 :         }
    2399                 :        348 : 
    2400                 :        348 :         /**
    2401                 :        348 :          * @method   append
    2402                 :        348 :          * @instance
    2403                 :        348 :          * @memberof module:whatwg-xhr.FormData
    2404                 :        348 :          * @param    {string}      name     - The name of the field whose data is contained in value.
    2405                 :        348 :          * @param    {string|Blob} value    - The field's value, can be a string or Blob, otherwise the value is converted to a string.
    2406                 :        348 :          * @param    {string}      filename - (Optional) The filename reported to the server (a string), when a Blob or File is passed as the second parameter.
    2407                 :        348 :          * @desc     Appends a new value onto an existing key inside a FormData object, or adds the key if it does not already exist.
    2408                 :        348 :          */
    2409                 :        348 :         append(name, value){
    2410                 :          0 :                 // validate the arguments
    2411                 :          0 :                 if(arguments.length < 2)
    2412                 :          0 :                         throw new TypeError(`FormData.append: ${arguments.length} is not a valid argument count for any overload.`);
    2413                 :          0 : 
    2414                 :          0 :                 const entryList = formData.get(this);
    2415                 :          0 :                 const entry = {};
    2416                 :          0 : 
    2417                 :          0 :                 entry[name] = String(value);
    2418                 :          0 :                 entryList.push(entry);
    2419                 :          0 :         }
    2420                 :        348 : 
    2421                 :        348 :         /**
    2422                 :        348 :          * @method   delete
    2423                 :        348 :          * @instance
    2424                 :        348 :          * @memberof module:whatwg-xhr.FormData
    2425                 :        348 :          * @param    {string} name - The name of the key to be deleted.
    2426                 :        348 :          * @desc     Deletes a key and its value(s) from a FormData object.
    2427                 :        348 :          */
    2428                 :        348 :         delete(name){
    2429                 :          0 :                 // validate the arguments
    2430                 :          0 :                 if(arguments.length < 1)
    2431                 :          0 :                         throw new TypeError(`FormData.delete: At least 1 argument required, but only ${arguments.length} passed`);
    2432                 :          0 : 
    2433                 :          0 :                 const entryList = formData.get(this);
    2434                 :          0 :                 for(let i = 0; i < entryList.length; i++)
    2435                 :          0 :                         if(entryList[i][name] !== undefined)
    2436                 :          0 :                                 entryList.splice(i--, 1);
    2437                 :          0 :         }
    2438                 :        348 : 
    2439                 :        348 :         /**
    2440                 :        348 :          * @method   get
    2441                 :        348 :          * @instance
    2442                 :        348 :          * @memberof module:whatwg-xhr.FormData
    2443                 :        348 :          * @param    {string} name - The name of the key to be retrieved.
    2444                 :        348 :          * @return   {string|Blob} Form data entry value.
    2445                 :        348 :          * @desc     Returns the first value associated with a given key from within a FormData object.
    2446                 :        348 :          */
    2447                 :        348 :         get(name){
    2448                 :          0 :                 // validate the arguments
    2449                 :          0 :                 if(arguments.length < 1)
    2450                 :          0 :                         throw new TypeError(`FormData.delete: At least 1 argument required, but only ${arguments.length} passed`);
    2451                 :          0 : 
    2452                 :          0 :                 const entryList = formData.get(this);
    2453                 :          0 :                 for(let i = 0; i < entryList.length; i++)
    2454                 :          0 :                         if(entryList[i][name] !== undefined)
    2455                 :          0 :                                 return entryList[i][name];
    2456                 :          0 : 
    2457                 :          0 :                 return null;
    2458                 :          0 :         }
    2459                 :        348 : 
    2460                 :        348 :         /**
    2461                 :        348 :          * @method   getAll
    2462                 :        348 :          * @instance
    2463                 :        348 :          * @memberof module:whatwg-xhr.FormData
    2464                 :        348 :          * @param    {string} name - The name of the key to be retrieved.
    2465                 :        348 :          * @return   {Array} An array of values whose key matches the specified name, otherwise, an empty list.
    2466                 :        348 :          * @desc     Returns all the values associated with a given key from within a FormData object.
    2467                 :        348 :          */
    2468                 :        348 :         getAll(name){
    2469                 :          0 :                 // validate the arguments
    2470                 :          0 :                 if(arguments.length < 1)
    2471                 :          0 :                         throw new TypeError(`FormData.delete: At least 1 argument required, but only ${arguments.length} passed`);
    2472                 :          0 : 
    2473                 :          0 :                 const result = [];
    2474                 :          0 :                 const entryList = formData.get(this);
    2475                 :          0 :                 for(let i = 0; i < entryList.length; i++)
    2476                 :          0 :                         if(entryList[i][name] !== undefined)
    2477                 :          0 :                                 result.push(entryList[i][name]);
    2478                 :          0 : 
    2479                 :          0 :                 return result;
    2480                 :          0 :         }
    2481                 :        348 : 
    2482                 :        348 :         /**
    2483                 :        348 :          * @method   has
    2484                 :        348 :          * @instance
    2485                 :        348 :          * @memberof module:whatwg-xhr.FormData
    2486                 :        348 :          * @param    {string} name - The name of the key to be retrieved.
    2487                 :        348 :          * @return   {boolean} true if a key of FormData matches the specified name, otherwise, false.
    2488                 :        348 :          * @desc     Returns whether a FormData object contains a certain key.
    2489                 :        348 :          */
    2490                 :        348 :         has(name){
    2491                 :          0 :                 // validate the arguments
    2492                 :          0 :                 if(arguments.length < 1)
    2493                 :          0 :                         throw new TypeError(`FormData.delete: At least 1 argument required, but only ${arguments.length} passed`);
    2494                 :          0 : 
    2495                 :          0 :                 const entryList = formData.get(this);
    2496                 :          0 :                 for(let i = 0; i < entryList.length; i++)
    2497                 :          0 :                         if(entryList[i][name] !== undefined)
    2498                 :          0 :                                 return true;
    2499                 :          0 : 
    2500                 :          0 :                 return false;
    2501                 :          0 :         }
    2502                 :        348 : 
    2503                 :        348 :         /**
    2504                 :        348 :          * @method   set
    2505                 :        348 :          * @instance
    2506                 :        348 :          * @memberof module:whatwg-xhr.FormData
    2507                 :        348 :          * @param    {string}      name     - The name of the field whose data is contained in value.
    2508                 :        348 :          * @param    {string|Blob} value    - The field's value, can be a string or Blob, otherwise the value is converted to a string.
    2509                 :        348 :          * @param    {string}      filename - (Optional) The filename reported to the server (a string), when a Blob or File is passed as the second parameter.
    2510                 :        348 :          * @desc     Sets a new value for an existing key inside a FormData object, or adds the key/value if it does not already exist.
    2511                 :        348 :          */
    2512                 :        348 :         set(name, value){
    2513                 :          0 :                 // validate the arguments
    2514                 :          0 :                 if(arguments.length < 2)
    2515                 :          0 :                         throw new TypeError(`FormData.append: ${arguments.length} is not a valid argument count for any overload.`);
    2516                 :          0 : 
    2517                 :          0 :                 const entryList = formData.get(this);
    2518                 :          0 :                 for(let i = 0; i < entryList.length; i++)
    2519                 :          0 :                         if(entryList[i][name] !== undefined)
    2520                 :          0 :                                 entryList.splice(i, 1);
    2521                 :          0 : 
    2522                 :          0 :                 const entry = {};
    2523                 :          0 : 
    2524                 :          0 :                 entry[name] = String(value);
    2525                 :          0 :                 entryList.push(entry);
    2526                 :          0 :         }
    2527                 :        348 : } // @endof class FormData
    2528                 :        348 : 
    2529                 :        348 : Object.defineProperty(FormData.prototype, Symbol.toStringTag, { value: 'FormData', writable: false, enumerable: false, configurable: true});
    2530                 :        348 : Object.defineProperty(FormData.prototype, Symbol.iterator, {
    2531                 :        348 :         value: function entries(){
    2532                 :          0 :                 const entryList = formData.get(this);
    2533                 :          0 : 
    2534                 :          0 :                 let i = 0;
    2535                 :          0 : 
    2536                 :          0 :                 return{
    2537                 :          0 :                         next(){
    2538                 :          0 :                                 return i < entryList.length ?
    2539                 :          0 :                                         { value: Object.entries(entryList[i++])[0], done: false} :
    2540                 :          0 :                                         { value: undefined, done: true};
    2541                 :          0 :                         },
    2542                 :          0 : 
    2543                 :          0 :                         [Symbol.iterator](){
    2544                 :          0 :                                 return this;
    2545                 :          0 :                         }
    2546                 :          0 :                 }
    2547                 :        348 :         },
    2548                 :        348 :         writable: false, enumerable: false, configurable: true
    2549                 :        348 : });
    2550                 :        348 : 
    2551                 :        348 : /**
    2552                 :        348 :  * XMLHttpRequest Living Standard — Last Updated 20 February 2023
    2553                 :        348 :  * url: https://xhr.spec.whatwg.org/#handle-errors
    2554                 :        348 :  *
    2555                 :        348 :  * To handle errors for an XMLHttpRequest object xhr, run these steps:
    2556                 :        348 :  * 1. If xhr’s send() flag is unset, then return.
    2557                 :        348 :  * 2. If xhr’s timed out flag is set, then run the request error steps for xhr, "timeout", and "TimeoutError" DOMException.
    2558                 :        348 :  * 3. Otherwise, if xhr’s response’s aborted flag is set, run the request error steps for xhr, "abort", and "AbortError" DOMException.
    2559                 :        348 :  * 4. Otherwise, if xhr’s response is a network error, then run the request error steps for xhr, error, and "NetworkError" DOMException.
    2560                 :        348 :  *
    2561                 :        348 :  * @func   handleError
    2562                 :        348 :  * @this   module:whatwg-xhr.XMLHttpRequest
    2563                 :        348 :  * @param  {object} Error object.
    2564                 :        348 :  * @desc   Handle errors for an XMLHttpRequest object, as given by {@link https://xhr.spec.whatwg.org/#handle-errors XHR specs}.
    2565                 :        348 :  */
    2566            [ + ]:        943 : function handleError(error){
    2567                 :        943 : 
    2568                 :        943 :         const requestData = xmlHttpRequest.get(this);
    2569                 :        943 : 
    2570                 :        943 :         // xhr.spec.1. If xhr’s send() flag is unset, then return.
    2571       [ + ][ + ]:        943 :         if(!requestData['sendFlag']){
    2572                 :          1 :                 return;
    2573            [ + ]:          1 :         }
    2574                 :          1 : 
    2575                 :          1 :         // xhr.spec.2. If xhr’s timed out flag is set, then run the request error steps for xhr, "timeout", and "TimeoutError" DOMException.
    2576            [ + ]:        943 :         if(requestData['timeoutFlag']){
    2577                 :          3 :                 requestErrorSteps.call(this, 'timeout', new DOMException('Timeout error', 'TimeoutError'));
    2578            [ + ]:          3 :         }
    2579                 :        447 :         else
    2580                 :        447 :         // xhr.spec.3. If xhr’s response’s aborted flag is set, run the request error steps for xhr, "abort", and "AbortError" DOMException.
    2581       [ + ][ - ]:        447 :         if(requestData['response'] && requestData['_responseAbort']){
    2582                 :          0 :                 requestErrorSteps.call(this, 'abort', new DOMException('Abort error', 'AbortError'));
    2583                 :          0 :         }
    2584                 :        447 :         else
    2585                 :        447 :         // xhr.spec.4. if xhr’s response is a network error, then run the request error steps for xhr, "error", and "NetworkError" DOMException.
    2586            [ + ]:        447 :         if(requestData['response'] === ''){
    2587                 :         38 :                 requestErrorSteps.call(this, 'error', new DOMException('Network error', 'NetworkError'));
    2588                 :         38 :         }
    2589                 :        943 : 
    2590                 :        348 : } // @endof function handleError
    2591                 :        348 : 
    2592                 :        348 : /**
    2593                 :        348 :  * XMLHttpRequest Living Standard — Last Updated 20 February 2023
    2594                 :        348 :  * url: https://xhr.spec.whatwg.org/#request-error-steps
    2595                 :        348 :  *
    2596                 :        348 :  * The request error steps for an XMLHttpRequest object <xhr>, <event>, and optionally <exception> are:
    2597                 :        348 :  * 1. Set <xhr>’s state to done.
    2598                 :        348 :  * 2. Unset <xhr>’s send() flag.
    2599                 :        348 :  * 3. Set <xhr>’s response to a network error.
    2600                 :        348 :  * 4. If <xhr>’s synchronous flag is set, then throw <exception>.
    2601                 :        348 :  * 5. Fire an event named readystatechange at <xhr>.
    2602                 :        348 :  *    Note: At this point it is clear that <xhr>’s synchronous flag is unset.
    2603                 :        348 :  * 6. If <xhr>’s upload complete flag is unset, then:
    2604                 :        348 :  *    1. Set <xhr>’s upload complete flag.
    2605                 :        348 :  *    2. If <xhr>’s upload listener flag is set, then:
    2606                 :        348 :  *       1. Fire a progress event named <event> at <xhr>’s upload object with 0 and 0.
    2607                 :        348 :  *       2. Fire a progress event named 'loadend' at <xhr>’s upload object with 0 and 0.
    2608                 :        348 :  * 7. Fire a progress event named <event> at <xhr> with 0 and 0.
    2609                 :        348 :  * 8. Fire a progress event named 'loadend' at <xhr> with 0 and 0.
    2610                 :        348 :  *
    2611                 :        348 :  * @func   requestErrorSteps
    2612                 :        348 :  * @this   module:whatwg-xhr.XMLHttpRequest
    2613                 :        348 :  * @param  {string} Event type
    2614                 :        348 :  * @param  {object|string} Exception
    2615                 :        348 :  * @desc   Request error steps for an XMLHttpRequest object <xhr>, <event>, and optionally <exception>, as given by {@link https://xhr.spec.whatwg.org/#request-error-steps XHR specs}.
    2616                 :        348 :  */
    2617            [ + ]:         54 : function requestErrorSteps(event, exception){
    2618                 :         54 : 
    2619                 :         54 :         const xhr = this;
    2620                 :         54 :         const requestData = xmlHttpRequest.get(xhr);
    2621                 :         54 : 
    2622                 :         54 :         // xhr.spec.1. Set <xhr>’s state to done.
    2623                 :         54 :         requestData['readyState'] = xhr.DONE;
    2624                 :         54 : 
    2625                 :         54 :         // xhr.spec.2. Unset <xhr>’s send() flag.
    2626                 :         54 :         requestData['sendFlag'] = false;
    2627                 :         54 : 
    2628                 :         54 :         // xhr.spec.3. Set <xhr>’s response to a network error.
    2629                 :         54 :         setResponseToNetworkError.call(xhr);
    2630                 :         54 : 
    2631                 :         54 :         // xhr.spec.4. If <xhr>’s synchronous flag is set, then throw <exception>.
    2632            [ + ]:         54 :         if(!requestData['async']){
    2633                 :         16 :                 throw exception;
    2634            [ + ]:         16 :         }
    2635                 :         22 : 
    2636                 :         22 :         // xhr.spec.5. Fire an event named readystatechange at <xhr>.
    2637                 :         22 :         xhr.dispatchEvent(new Event('readystatechange'));
    2638                 :         22 : 
    2639                 :         22 :         // xhr.spec.6. If <xhr>’s upload complete flag is unset, then:
    2640            [ + ]:         54 :         if(!requestData['uploadCompleteFlag']){
    2641                 :          5 : 
    2642                 :          5 :                 // xhr.spec.6.1. Set <xhr>’s upload complete flag.
    2643                 :          5 :                 requestData['uploadCompleteFlag'] = true;
    2644                 :          5 : 
    2645                 :          5 :                 // xhr.spec.6.2. If <xhr>’s upload listener flag is set, then:
    2646                 :          5 :                 if(requestData['uploadListenerFlag']){
    2647                 :          5 :                         const upload = requestData['upload'];
    2648                 :          5 : 
    2649                 :          5 :                         // xhr.spec.6.2.1. Fire a progress event named <event> at <xhr>’s upload object with 0 and 0.
    2650                 :          5 :                         upload.dispatchEvent(new ProgressEvent(event, {loaded: 0, total: 0}));
    2651                 :          5 : 
    2652                 :          5 :                         // xhr.spec.6.2.2. Fire a progress event named 'loadend' at <xhr>’s upload object with 0 and 0.
    2653                 :          5 :                         upload.dispatchEvent(new ProgressEvent('loadend', {loaded: 0, total: 0}));
    2654                 :          5 :                 }
    2655            [ + ]:          5 :         }
    2656                 :         22 : 
    2657                 :         22 :         // xhr.spec.7. Fire a progress event named <event> at <xhr> with 0 and 0.
    2658                 :         22 :         xhr.dispatchEvent(new ProgressEvent(event, {loaded: 0, total: 0}));
    2659                 :         22 : 
    2660                 :         22 :         // xhr.spec.7. Fire a progress event named 'loadend' at <xhr> with 0 and 0.
    2661                 :         22 :         xhr.dispatchEvent(new ProgressEvent('loadend', {loaded: 0, total: 0}));
    2662                 :         22 : 
    2663                 :        348 : } // @endof function requestErrorSteps
    2664                 :        348 : 
    2665                 :        348 : /**
    2666                 :        348 :  * Fetch Living Standard — Last Updated 17 June 2024
    2667                 :        348 :  * url: https://fetch.spec.whatwg.org/#concept-network-error
    2668                 :        348 :  *
    2669                 :        348 :  * A network error is a response whose type is "error", status is 0, status message is the empty byte sequence, header list is « »,
    2670                 :        348 :  * body is null, and body info is a new response body info.
    2671                 :        348 :  *
    2672                 :        348 :  * @func   setResponseToNetworkError
    2673                 :        348 :  * @this   module:whatwg-xhr.XMLHttpRequest
    2674                 :        348 :  * @desc   Network error is a response whose type is "error", as defined by {@link https://fetch.spec.whatwg.org/#concept-network-error Fetch specs}.
    2675                 :        348 :  */
    2676            [ + ]:        857 : function setResponseToNetworkError(){
    2677                 :        857 : 
    2678                 :        857 :         const requestData = xmlHttpRequest.get(this);
    2679                 :        857 : 
    2680            [ + ]:        857 :         if(requestData['fetchController']){
    2681                 :         31 :                 requestData['fetchController'].destroy();
    2682                 :         31 :                 requestData['fetchController'] = null;
    2683                 :         31 :         }
    2684                 :        857 : 
    2685                 :        857 :         requestData['response'] = '';
    2686                 :        857 : 
    2687                 :        857 :         //      requestData['status'] = 0;
    2688                 :        857 :         //      requestData['statusText'] = '';
    2689                 :        857 : 
    2690                 :        857 :         requestData['requestHeaders'    ] = {};
    2691                 :        857 :         requestData['requestHeadersCase'] = {};
    2692                 :        857 : 
    2693                 :        857 :         requestData['receivedBytes'] = Buffer.alloc(0);
    2694                 :        857 :         requestData['_responseBody'] = null;
    2695                 :        857 : 
    2696                 :        348 : } // @endof function setResponseToNetworkError
    2697                 :        348 : 
    2698                 :        348 : /*
    2699                 :        348 :  * XMLHttpRequest Living Standard — Last Updated 20 February 2023
    2700                 :        348 :  * url: https://xhr.spec.whatwg.org/#response-body
    2701                 :        348 :  *
    2702                 :        348 :  * 3.6.6. Response body
    2703                 :        348 :  *
    2704                 :        348 :  * To get a response MIME type for an XMLHttpRequest object xhr, run these steps:
    2705                 :        348 :  *  1. Let mimeType be the result of <extracting a MIME type> from xhr’s response’s header list.
    2706                 :        348 :  *  2. If mimeType is failure, then set mimeType to text/xml.
    2707                 :        348 :  *  3. Return mimeType.
    2708                 :        348 :  *
    2709                 :        348 :  * To get a final MIME type for an XMLHttpRequest object xhr, run these steps:
    2710                 :        348 :  *  1. If xhr’s <override MIME type> is null, return the result of get a response MIME type for xhr.
    2711                 :        348 :  *  2. Return xhr’s override MIME type.
    2712                 :        348 :  *
    2713                 :        348 :  * To get a final encoding for an XMLHttpRequest object xhr, run these steps:
    2714                 :        348 :  *  1. Let label be null.
    2715                 :        348 :  *  2. Let responseMIME be the result of <get a response MIME type> for xhr.
    2716                 :        348 :  *  3. If responseMIME’s parameters["charset"] exists, then set label to it.
    2717                 :        348 :  *  4. If xhr’s override MIME type’s parameters["charset"] exists, then set label to it.
    2718                 :        348 :  *  5. If label is null, then return null.
    2719                 :        348 :  *  6. Let encoding be the result of getting an encoding from label.
    2720                 :        348 :  *  7. If encoding is failure, then return null.
    2721                 :        348 :  *  8. Return encoding.
    2722                 :        348 :  * The above steps intentionally do not use the get a final MIME type as it would not be web compatible.
    2723                 :        348 :  *
    2724                 :        348 :  * To set a document response for an XMLHttpRequest object xhr, run these steps:
    2725                 :        348 :  *  1. If xhr’s response’s body is null, then return.
    2726                 :        348 :  *  2. Let finalMIME be the result of get a final MIME type for xhr.
    2727                 :        348 :  *  3. If finalMIME is not an HTML MIME type or an XML MIME type, then return.
    2728                 :        348 :  *  4. If xhr’s response type is the empty string and finalMIME is an HTML MIME type, then return.
    2729                 :        348 :  *     Note: This is restricted to xhr’s response type being "document" in order to prevent breaking legacy content.
    2730                 :        348 :  *  5. If finalMIME is an HTML MIME type, then:
    2731                 :        348 :  *     1. Let charset be the result of get a final encoding for xhr.
    2732                 :        348 :  *     2. If charset is null, prescan the first 1024 bytes of xhr’s received bytes and if that does not terminate
    2733                 :        348 :  *        unsuccessfully then let charset be the return value.
    2734                 :        348 :  *     3. If charset is null, then set charset to UTF-8.
    2735                 :        348 :  *     4. Let document be a document that represents the result parsing xhr’s received bytes
    2736                 :        348 :  *        following the rules set forth in the HTML Standard for an HTML parser with scripting
    2737                 :        348 :  *        disabled and a known definite encoding charset. [HTML]
    2738                 :        348 :  *     5. Flag document as an HTML document.
    2739                 :        348 :  *  6. Otherwise, let document be a document that represents the result of running the XML parser
    2740                 :        348 :  *     with XML scripting support disabled on xhr’s received bytes.
    2741                 :        348 :  *     If that fails (unsupported character encoding, namespace well-formedness error, etc.),
    2742                 :        348 :  *     then return null. [HTML]
    2743                 :        348 :  *     Note: Resources referenced will not be loaded and no associated XSLT will be applied.
    2744                 :        348 :  *  7. If charset is null, then set charset to UTF-8.
    2745                 :        348 :  *  8. Set document’s encoding to charset.
    2746                 :        348 :  *  9. Set document’s content type to finalMIME.
    2747                 :        348 :  * 10. Set document’s URL to xhr’s response’s URL.
    2748                 :        348 :  * 11. Set document’s origin to xhr’s relevant settings object’s origin.
    2749                 :        348 :  * 12. Set xhr’s response object to document.
    2750                 :        348 :  *
    2751                 :        348 :  * To get a text response for an XMLHttpRequest object xhr, run these steps:
    2752                 :        348 :  *  1. If xhr’s response’s body is null, then return the empty string.
    2753                 :        348 :  *  2. Let charset be the result of get a final encoding for xhr.
    2754                 :        348 :  *  3. If xhr’s response type is the empty string, charset is null, and the result of get a final MIME type for xhr is an XML MIME type,
    2755                 :        348 :  *     then use the rules set forth in the XML specifications to determine the encoding. Let charset be the determined encoding. [XML] [XML-NAMES]
    2756                 :        348 :  *     This is restricted to xhr’s response type being the empty string to keep the non-legacy response type value "text" simple.
    2757                 :        348 :  *  4. If charset is null, then set charset to UTF-8.
    2758                 :        348 :  *  5. Return the result of running decode on xhr’s received bytes using fallback encoding charset.
    2759                 :        348 :  *  Authors are strongly encouraged to always encode their resources using UTF-8.
    2760                 :        348 :  */
    2761                 :        348 : 
    2762                 :        348 : /**
    2763                 :        348 :  * @func     getResponseMimeType
    2764                 :        348 :  * @this     module:whatwg-xhr.XMLHttpRequest
    2765                 :        348 :  * @return   {string} MIME type.
    2766                 :        348 :  * @desc     Get a response MIME type for an XMLHttpRequest object xhr, as given by {@link https://xhr.spec.whatwg.org/#response-body XHR specs}.
    2767                 :        348 :  * @requires module:helper-content-type.parse
    2768                 :        348 :  */
    2769            [ + ]:        877 : function getResponseMimeType(){
    2770                 :        877 : 
    2771                 :        877 :         const requestData = xmlHttpRequest.get(this);
    2772                 :        877 :         const response = requestData['response'];
    2773                 :        877 : 
    2774                 :        877 :         let mimeType = '';
    2775                 :        877 : 
    2776                 :        877 :         // xhr.spec.1. Let mimeType be the result of <extracting a MIME type> from xhr’s response’s header list.
    2777                 :        877 :         try{
    2778                 :        877 :                 let obj = contentTypeParse(response.headers['content-type']);
    2779                 :        877 :                 mimeType = response.headers['content-type'];
    2780                 :        877 :         }
    2781                 :        877 :         // xhr.spec.2. If mimeType is failure, then set mimeType to text/xml.
    2782            [ + ]:        877 :         catch(e){
    2783                 :         38 :                 mimeType = 'text/xml';
    2784                 :         38 :         }
    2785                 :        877 : 
    2786                 :        877 :         // xhr.spec.3. Return mimeType.
    2787                 :        877 :         return mimeType;
    2788                 :        877 : 
    2789                 :        348 : } // @endof function getResponseMimeType
    2790                 :        348 : 
    2791                 :        348 : /**
    2792                 :        348 :  * @func   getFinalMimeType
    2793                 :        348 :  * @this   module:whatwg-xhr.XMLHttpRequest
    2794                 :        348 :  * @return {string} MIME type.
    2795                 :        348 :  * @desc   Get a final MIME type for an XMLHttpRequest object xhr, as given by {@link https://xhr.spec.whatwg.org/#response-body XHR specs}.
    2796                 :        348 :  */
    2797            [ + ]:        479 : function getFinalMimeType(){
    2798                 :        479 : 
    2799                 :        479 :         const requestData = xmlHttpRequest.get(this);
    2800                 :        479 : 
    2801                 :        479 :         // xhr.spec.1. If xhr’s <override MIME type> is null, return the result of get a response MIME type for xhr.
    2802                 :        479 :         if(requestData['overrideMimeType'] === null)
    2803       [ + ][ + ]:        479 :                 return getResponseMimeType.call(this);
    2804                 :          1 : 
    2805                 :          1 :         // xhr.spec.2. Return xhr’s override MIME type.
    2806                 :          1 :         return requestData['overrideMimeType'];
    2807                 :          1 : 
    2808                 :        348 : } // @endof function getFinalMimeType
    2809                 :        348 : 
    2810                 :        348 : /**
    2811                 :        348 :  * @func   getFinalEncoding
    2812                 :        348 :  * @this   module:whatwg-xhr.XMLHttpRequest
    2813                 :        348 :  * @return {string|null} Final encoding.
    2814                 :        348 :  * @desc   Get a final encoding for an XMLHttpRequest object xhr, as given by {@link https://xhr.spec.whatwg.org/#response-body XHR specs}.
    2815                 :        348 :  * @requires module:helper-content-type.parse
    2816                 :        348 :  */
    2817            [ + ]:        399 : function getFinalEncoding(){
    2818                 :        399 : 
    2819                 :        399 :         const requestData = xmlHttpRequest.get(this);
    2820                 :        399 : 
    2821                 :        399 :         // xhr.spec.1. Let label be null.
    2822                 :        399 :         let label = null;
    2823                 :        399 : 
    2824                 :        399 :         // xhr.spec.2. Let responseMIME be the result of <get a response MIME type> for xhr.
    2825                 :        399 :         let responseMIME = getResponseMimeType.call(this);
    2826                 :        399 : 
    2827                 :        399 :         let obj = null;
    2828                 :        399 :         // xhr.spec.3. If responseMIME’s parameters["charset"] exists, then set label to it.
    2829                 :        399 :         try{
    2830                 :        399 :                 obj = contentTypeParse(responseMIME);
    2831                 :        399 :                 if(obj.parameters && obj.parameters.charset)
    2832            [ + ]:        399 :                         label = obj.parameters.charset;
    2833            [ - ]:        399 :         }catch(e){}
    2834                 :        399 : 
    2835                 :        399 :         // xhr.spec.4. If xhr’s override MIME type’s parameters["charset"] exists, then set label to it.
    2836            [ + ]:        399 :         if(requestData['overrideMimeType']){
    2837                 :          4 :                 try{
    2838                 :          4 :                         obj = contentTypeParse(requestData['overrideMimeType']);
    2839                 :          4 :                         if(obj.parameters && obj.parameters.charset)
    2840            [ + ]:          4 :                                 label = obj.parameters.charset;
    2841                 :          4 :                 }catch(e){}
    2842                 :          4 :         }
    2843                 :        399 : 
    2844                 :        399 :         // xhr.spec.5. If label is null, then return null.
    2845       [ + ][ + ]:        399 :         if(label === null) return null;
    2846                 :         17 : 
    2847                 :         17 :         // xhr.spec.6. Let encoding be the result of getting an encoding from label.
    2848                 :         17 :         let encoding = whatwgEncoding.labelToName(label);
    2849                 :         17 : 
    2850                 :         17 :         // xhr.spec.7. If encoding is failure, then return null.
    2851                 :         17 :         // xhr.spec.8. Return encoding.
    2852                 :         17 :         return encoding;
    2853                 :         17 : 
    2854                 :        348 : } // @endof function getFinalEncoding
    2855                 :        348 : 
    2856                 :        348 : /**
    2857                 :        348 :  * @func     setDocumentResponse
    2858                 :        348 :  * @this     module:whatwg-xhr.XMLHttpRequest
    2859                 :        348 :  * @desc     Set a document response for an XMLHttpRequest object xhr, as given by {@link https://xhr.spec.whatwg.org/#response-body XHR specs}.
    2860                 :        348 :  * @requires module:helper-content-type.parse
    2861                 :        348 :  */
    2862            [ + ]:        213 : function setDocumentResponse(){
    2863                 :        213 : 
    2864                 :        213 :         const requestData = xmlHttpRequest.get(this);
    2865                 :        213 : 
    2866                 :        213 :         // xhr.spec.1. If xhr’s response’s body is null, then return.
    2867            [ + ]:        213 :         if(requestData['receivedBytes'].length === 0) return;
    2868                 :          2 : 
    2869                 :          2 :         // xhr.spec.2. Let <finalMIME> be the result of get a final MIME type for xhr.
    2870                 :          2 :         let finalMIME = getFinalMimeType.call(this);
    2871                 :          2 :         let obj;
    2872                 :          2 : 
    2873                 :          2 :         try{
    2874                 :          2 :                 obj = contentTypeParse(finalMIME);
    2875                 :          2 : 
    2876                 :          2 :                 // xhr.spec.3. If <finalMIME> is not an HTML MIME type or an XML MIME type, then return.
    2877                 :          2 :                 if(
    2878                 :          2 :                         obj.type !== 'text/xml'        &&
    2879            [ + ]:        213 :                         obj.type !== 'application/xml' &&
    2880            [ + ]:        213 :                         !obj.type.endsWith('+xml')     &&
    2881                 :          2 :                         obj.type !== 'text/html'
    2882                 :        213 :                 )
    2883            [ + ]:        213 :                         return;
    2884                 :          1 : 
    2885                 :          1 :                 // xhr.spec.4. If xhr’s response type is the empty string and <finalMIME> is an HTML MIME type, then return.
    2886                 :        213 :                 if(obj.type === 'text/html' && this.responseType === '')
    2887            [ + ]:        213 :                         return;
    2888                 :        213 : 
    2889                 :        213 :                 // xhr.spec.5. If finalMIME is an HTML MIME type, then:
    2890            [ - ]:        213 :                 if(obj.type === 'text/html'){
    2891                 :          0 : 
    2892                 :          0 :                         // xhr.spec.5.1. Let <charset> be the result of get a final encoding for xhr.
    2893                 :          0 :                         let charset = getFinalEncoding.call(this);
    2894                 :          0 : 
    2895                 :          0 :                         // xhr.spec.5.2. If <charset> is null, prescan the first 1024 bytes of xhr’s received bytes and if that does not terminate
    2896                 :          0 :                         //               unsuccessfully then let <charset> be the return value.
    2897                 :          0 :                         if(charset === null){
    2898                 :          0 :                                 charset = htmlEncodingSniffer(requestData['receivedBytes'].subarray(0, 1024));
    2899                 :          0 :                         }
    2900                 :          0 : 
    2901                 :          0 :                         // xhr.spec.5.3. If <charset> is null, then set <charset> to UTF-8.
    2902                 :          0 :                         if(charset === null) charset = 'UTF-8';
    2903                 :          0 : 
    2904                 :          0 :                         // xhr.spec.5.4. Let <document> be a document that represents the result parsing xhr’s received bytes
    2905                 :          0 :                         //               following the rules set forth in the HTML Standard for an HTML parser with scripting
    2906                 :          0 :                         //               disabled and a known definite encoding charset. [HTML]
    2907                 :          0 :                         // xhr.spec.5.5. Flag document as an HTML document.
    2908                 :          0 : 
    2909                 :          0 :                         // @todo...
    2910                 :          0 :                 }
    2911                 :        213 :                 else{
    2912                 :        213 :                         // xhr.spec.6. Otherwise, let document be a document that represents the result of running the XML parser
    2913                 :        213 :                         //             with XML scripting support disabled on xhr’s received bytes.
    2914                 :        213 :                         //             If that fails (unsupported character encoding, namespace well-formedness error, etc.),
    2915                 :        213 :                         //             then return null. [HTML]
    2916                 :        213 :                         // Note: Resources referenced will not be loaded and no associated XSLT will be applied.
    2917                 :        213 : 
    2918                 :        213 :                         // @todo...
    2919                 :        213 :                 }
    2920            [ - ]:        213 :         }catch(e){
    2921                 :          0 :                 return;
    2922                 :          0 :         }
    2923                 :        213 : 
    2924                 :        213 :         // xhr.spec.7. If charset is null, then set charset to UTF-8.
    2925                 :        213 :         // xhr.spec.8. Set document’s encoding to charset.
    2926                 :        213 :         // xhr.spec.9. Set document’s content type to finalMIME.
    2927                 :        213 :         // xhr.spec.10. Set document’s URL to xhr’s response’s URL.
    2928                 :        213 :         // xhr.spec.11. Set document’s origin to xhr’s relevant settings object’s origin.
    2929                 :        213 : 
    2930                 :        213 :         // @todo...
    2931                 :        213 : 
    2932                 :        213 :         // xhr.spec.12. Set xhr’s response object to document.
    2933                 :        213 :         requestData['responseObject'] = null;
    2934                 :        213 : 
    2935                 :        348 : } // @endof function setDocumentResponse
    2936                 :        348 : 
    2937                 :        348 : /**
    2938                 :        348 :  * @func     getTextResponse
    2939                 :        348 :  * @this     module:whatwg-xhr.XMLHttpRequest
    2940                 :        348 :  * @return   {string} Text response.
    2941                 :        348 :  * @desc     Get a text for an XMLHttpRequest object xhr, as given by {@link https://xhr.spec.whatwg.org/#response-body XHR specs}.
    2942                 :        348 :  * @requires module:helper-content-type.parse
    2943                 :        348 :  * @requires module:helper-xml-encoding-sniffer.xmlEncodingSniffer
    2944                 :        348 :  */
    2945            [ + ]:        709 : function getTextResponse(){
    2946                 :        709 : 
    2947                 :        709 :         const requestData = xmlHttpRequest.get(this);
    2948                 :        709 : 
    2949                 :        709 :         // xhr.spec.1. If xhr’s response’s body is null, then return the empty string.
    2950                 :        709 :         // author. if(requestData['_responseBody'] === null)
    2951            [ + ]:        709 :         if(requestData['receivedBytes'].length === 0){
    2952                 :        104 :                 return '';
    2953            [ + ]:        104 :         }
    2954                 :        187 : 
    2955                 :        187 :         // xhr.spec.2. Let charset be the result of get a final encoding for xhr.
    2956                 :        187 :         let charset = getFinalEncoding.call(this);
    2957                 :        187 : 
    2958                 :        187 :         // xhr.spec.3. If xhr’s response type is the empty string, charset is null, and the result of get a final MIME type for xhr is an XML MIME type,
    2959                 :        187 :         //             then use the rules set forth in the XML specifications to determine the encoding. Let charset be the determined encoding. [XML] [XML-NAMES]
    2960                 :        187 :         //             This is restricted to xhr’s response type being the empty string to keep the non-legacy response type value "text" simple.
    2961       [ + ][ + ]:        709 :         if(requestData['responseType'] === '' && charset === null){
    2962                 :        157 :                 let finalMimeType = getFinalMimeType.call(this);
    2963                 :        157 :                 try{
    2964                 :        157 :                         let obj = contentTypeParse(finalMimeType);
    2965  [ + ][ + ][ + ]:        157 :                         if(obj.type === 'text/xml' || obj.type === 'application/xml' || obj.type.endsWith('+xml')){
    2966                 :         24 :                                 // @todo: use the rules set forth in the XML specifications to determine the encoding. Let charset be the determined encoding.
    2967                 :         24 :                                 charset = xmlEncodingSniffer(requestData['receivedBytes']);
    2968                 :         24 :                         }
    2969            [ - ]:        157 :                 }catch(e){}
    2970            [ + ]:        157 :         }
    2971                 :        187 : 
    2972                 :        187 :         // xhr.spec.4. If charset is null, then set charset to UTF-8.
    2973       [ + ][ + ]:        709 :         if(charset === null) charset = 'UTF-8';
    2974                 :        187 : 
    2975                 :        187 :         // xhr.spec.5. Return the result of running decode on xhr’s received bytes using fallback encoding charset.
    2976                 :        187 :         return whatwgEncoding.decode(requestData['receivedBytes'], charset);
    2977                 :        187 : 
    2978                 :        348 : } // @endof function getTextResponse
    2979                 :        348 : 
    2980                 :        348 : /**
    2981                 :        348 :  * @class ClientRequestData
    2982                 :        348 :  * @desc Emulates the node http.ClientRequest for processing data url's.
    2983                 :        348 :  */
    2984                 :        348 : class ClientRequestData{
    2985                 :        348 : 
    2986                 :        348 :         /**
    2987                 :        348 :          * @method   constructor
    2988                 :        348 :          * @instance
    2989                 :        348 :          * @memberof module:whatwg-xhr~ClientRequestData
    2990                 :        348 :          * @param    {object} response - Emulates the http.IncomingMessage object.
    2991                 :        348 :          * @return   {object} ClientRequestData object.
    2992                 :        348 :          * @desc     Constructs a new ClientRequestData object.
    2993                 :        348 :          */
    2994            [ + ]:        348 :         constructor(response){
    2995                 :         13 :                 this.response = response;
    2996                 :         13 :         }
    2997                 :        348 : 
    2998                 :        348 :         /**
    2999                 :        348 :          * @method   destroy
    3000                 :        348 :          * @instance
    3001                 :        348 :          * @memberof module:whatwg-xhr~ClientRequestData
    3002                 :        348 :          * @return   {object} ClientRequestData object.
    3003                 :        348 :          * @desc     Emulates the node http.ClientRequest destroy() method.
    3004                 :        348 :          */
    3005            [ + ]:        348 :         destroy(){
    3006                 :          2 :                 return this;
    3007                 :          2 :         }
    3008                 :        348 : 
    3009                 :        348 :         /**
    3010                 :        348 :          * @method   end
    3011                 :        348 :          * @instance
    3012                 :        348 :          * @memberof module:whatwg-xhr~ClientRequestData
    3013                 :        348 :          * @param    {function} callback - Callback function to invoke.
    3014                 :        348 :          * @return   {object} ClientRequestData object.
    3015                 :        348 :          * @desc     Emulates the node http.ClientRequest end() method.
    3016                 :        348 :          */
    3017            [ + ]:        348 :         end(callback){
    3018                 :         13 :                 if(typeof callback === 'function')
    3019            [ - ]:         13 :                         callback();
    3020                 :         13 : 
    3021                 :         13 :                 return this;
    3022                 :         13 :         }
    3023                 :        348 : 
    3024                 :        348 :         /**
    3025                 :        348 :          * @method   on
    3026                 :        348 :          * @instance
    3027                 :        348 :          * @memberof module:whatwg-xhr~ClientRequestData
    3028                 :        348 :          * @param    {string} type - The event to invoke.
    3029                 :        348 :          * @param    {function} callback - Callback function to invoke.
    3030                 :        348 :          * @return   {object} ClientRequestData object.
    3031                 :        348 :          * @desc     Emulates the node http.ClientRequest on() method.
    3032                 :        348 :          */
    3033            [ + ]:        348 :         on(type, callback){
    3034            [ + ]:         39 :                 if(type === 'response' && typeof callback === 'function')
    3035       [ + ][ + ]:         39 :                         callback(this.response);
    3036                 :         26 :                 else
    3037       [ + ][ + ]:         26 :                 if(type === 'error' && typeof callback === 'function' && this.response.statusCode === 0)
    3038            [ + ]:         26 :                         callback(new ProgressEvent('error'));
    3039                 :         39 : 
    3040                 :         39 :                 return this;
    3041                 :         39 :         }
    3042                 :        348 : } // @endof class ClientRequestData
    3043                 :        348 : 
    3044                 :        348 : /**
    3045                 :        348 :  * @func     requestDataURL
    3046                 :        348 :  * @param    {object} options - Options passed to the node http.request function.
    3047                 :        348 :  * @return   {object} ClientRequestData object.
    3048                 :        348 :  * @desc     Emulates the node http.request function for processing data url's.
    3049                 :        348 :  * @requires module:whatwg-misc.dataURLProcessor
    3050                 :        348 :  * @requires module:whatwg-misc.serializeAMimeType
    3051                 :        348 :  */
    3052            [ + ]:         13 : function requestDataURL(options){
    3053                 :         13 : 
    3054                 :         13 :         let urlStruct = null;
    3055                 :         13 :         let responseDataURL = null;
    3056                 :         13 : 
    3057                 :         13 :         try{
    3058                 :         13 :                 urlStruct = dataURLProcessor(new URL(options.url));
    3059            [ - ]:         13 :         }catch(e){
    3060                 :          0 :                 urlStruct = 'failure';
    3061                 :          0 :         }
    3062                 :         13 : 
    3063            [ + ]:         13 :         if(urlStruct !== 'failure'){
    3064                 :         11 : 
    3065                 :         11 :                 if(options.method.toUpperCase() === 'HEAD')
    3066       [ + ][ + ]:         11 :                         responseDataURL = Readable.from(Buffer.alloc(0));
    3067                 :         10 :                 else
    3068                 :         10 :                         responseDataURL = Readable.from(Buffer.from(urlStruct.body));
    3069                 :         11 : 
    3070                 :         11 :                 responseDataURL.statusCode = 200;
    3071                 :         11 :                 responseDataURL.statusMessage = 'OK';
    3072                 :         11 :                 responseDataURL.url = options.url;
    3073                 :         11 : 
    3074                 :         11 :                 responseDataURL.headers = {
    3075                 :         11 :                         'Content-Type': serializeAMimeType(urlStruct.mimeType),
    3076                 :         11 :                 }
    3077            [ + ]:         11 :         }
    3078                 :          1 :         else{
    3079                 :          1 :                 responseDataURL = Readable.from(Buffer.alloc(0));
    3080                 :          1 : 
    3081                 :          1 :                 responseDataURL.statusCode = 0;
    3082                 :          1 :                 responseDataURL.statusMessage = '';
    3083                 :          1 : 
    3084                 :          1 :                 responseDataURL.headers = {};
    3085                 :          1 :         }
    3086                 :         13 : 
    3087                 :         13 :         return new ClientRequestData(responseDataURL);
    3088                 :         13 : 
    3089                 :        348 : } // @endof function requestDataURL

Generated by: LCOV version 1.14