2121 * THE SOFTWARE.
2222 */
2323
24+ import { Blob } from 'buffer' ;
2425import * as http from 'http' ;
2526import * as https from 'https' ;
27+ import DOMException from './domexception' ;
28+ import File from './file' ;
2629import FormData from './formdata' ;
2730import ProgressEvent from './progressevent' ;
28- import DOMException from './webidl/domexception' ;
2931import XMLHttpRequestEventTarget from './xmlhttprequesteventtarget' ;
3032import XMLHttpRequestUpload from './xmlhttprequestupload' ;
3133
@@ -77,12 +79,11 @@ const FORBIDDEN_RESPONSE_HEADERS = ['set-cookie', 'set-cookie2'];
7779 */
7880const HTTP_HEADER_FIELD_NAME_REGEXP = / [ ! # $ % & ' * + - . ^ _ ` | ~ a - z 0 - 9 ] + / ;
7981
80- export type BodyInit =
81- | ArrayBuffer
82- | Buffer
82+ export type XMLHttpRequestBodyInit =
83+ | Blob
84+ | BufferSource
8385 | FormData
8486 | URLSearchParams
85- | Uint8Array
8687 | string ;
8788
8889export type XMLHttpRequestResponseType =
@@ -478,24 +479,62 @@ export default class XMLHttpRequest extends XMLHttpRequestEventTarget {
478479 /**
479480 * @see {@link https://xhr.spec.whatwg.org/#the-send()-method XMLHttpRequest Standard - 4.5.6. The send() method }
480481 */
481- send ( body : BodyInit | null = null ) : void {
482+ send ( body : XMLHttpRequestBodyInit | null = null ) : void {
482483 if ( this . readyState !== XMLHttpRequest . OPENED || ! this . #client) {
483484 // TODO: Add human readable message.
484485 throw new DOMException ( '' , 'InvalidStateError' ) ;
485486 }
486487
487- if ( body ) {
488- const bodyInit =
489- body instanceof ArrayBuffer || body instanceof Uint8Array
490- ? Buffer . from ( body )
491- : body ;
488+ if ( body && ! [ 'GET' , 'HEAD' ] . includes ( this . #client. method ) ) {
489+ let chunk = new Blob ( [ ] ) ;
492490
493- if ( typeof bodyInit === 'string' || bodyInit instanceof Buffer ) {
494- const length = Buffer . isBuffer ( bodyInit )
495- ? bodyInit . length
496- : Buffer . byteLength ( bodyInit ) ;
491+ if (
492+ body instanceof ArrayBuffer ||
493+ ArrayBuffer . isView ( body ) ||
494+ body instanceof Blob
495+ ) {
496+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
497+ // @ts -ignore
498+ chunk = new Blob ( [ body ] ) ;
499+ } else if ( body instanceof URLSearchParams ) {
500+ chunk = new Blob ( [ body . toString ( ) ] , {
501+ type : 'application/x-www-form-urlencoded; charset=UTF-8'
502+ } ) ;
503+ } else if ( body instanceof FormData ) {
504+ const boundary = '------xxxxx' ;
497505
498- this . #client. setHeader ( 'Content-Length' , length ) ;
506+ let chunk = new Blob ( [ ] , {
507+ type : `multipart/form-data; boundary=${ boundary } `
508+ } ) ;
509+ for ( const [ name , value ] of body ) {
510+ if ( value instanceof File ) {
511+ chunk = new Blob (
512+ [
513+ chunk ,
514+ `Content-Disposition: form-data; name="${ name } "; filename="${ value . name } "\r\n` ,
515+ '\r\n' ,
516+ value ,
517+ `\r\n`
518+ ] ,
519+ { type : chunk . type }
520+ ) ;
521+ } else {
522+ chunk = new Blob (
523+ [
524+ chunk ,
525+ `${ boundary } \r\n` ,
526+ `Content-Disposition: form-data; name="${ name } "\r\n` ,
527+ '\r\n' ,
528+ `${ value } \r\n`
529+ ] ,
530+ { type : chunk . type }
531+ ) ;
532+ }
533+ }
534+
535+ chunk = new Blob ( [ chunk , `${ boundary } \r\n` ] , { type : chunk . type } ) ;
536+ } else {
537+ chunk = new Blob ( [ body ] , { type : 'text/plain' } ) ;
499538 }
500539
501540 this . #client. addListener ( 'socket' , ( socket ) => {
@@ -511,6 +550,12 @@ export default class XMLHttpRequest extends XMLHttpRequestEventTarget {
511550 } ) ;
512551 } ) ;
513552
553+ if ( chunk . type ) {
554+ this . setRequestHeader ( 'Content-Type' , chunk . type ) ;
555+ }
556+
557+ this . setRequestHeader ( 'Content-Length' , chunk . size . toString ( ) ) ;
558+
514559 this . #client. write ( body ) ;
515560 }
516561
0 commit comments