import { HttpClient } from "./httpClient" ; import { HttpHeaders } from "./httpHeaders" ; import { WebResourceLike , TransferProgressEvent } from "./webResource" ; import { HttpOperationResponse } from "./httpOperationResponse" ; import { RestError } from "./restError" ; /**
 * A HttpClient implementation that uses XMLHttpRequest to send HTTP requests.
 */ export class XhrHttpClient implements HttpClient { public sendRequest ( request ) { const xhr = new XMLHttpRequest ( ) ; if ( request . agentSettings ) { throw new Error ( "HTTP agent settings not supported in browser environment" ) ; } if ( request . proxySettings ) { throw new Error ( "HTTP proxy is not supported in browser environment" ) ; } const abortSignal = request . abortSignal ; if ( abortSignal ) { const listener = ( ) => { xhr . abort ( ) ; } ; abortSignal . addEventListener ( "abort" , listener ) ; xhr . addEventListener ( "readystatechange" , ( ) => { if ( xhr . readyState === XMLHttpRequest . DONE ) { abortSignal . removeEventListener ( "abort" , listener ) ; } } ) ; } addProgressListener ( xhr . upload , request . onUploadProgress ) ; addProgressListener ( xhr , request . onDownloadProgress ) ; if ( request . formData ) { const formData = request . formData ; const requestForm = new FormData ( ) ; const appendFormValue = ( key , value ) => { if ( value && value . hasOwnProperty ( "value" ) && value . hasOwnProperty ( "options" ) ) { requestForm . append ( key , value . value , value . options ) ; } else { requestForm . append ( key , value ) ; } } ; for ( const formKey of Object . keys ( formData ) ) { const formValue = formData [ formKey ] ; if ( Array . isArray ( formValue ) ) { for ( let j = 0 ; j < formValue . length ; j ++ ) { appendFormValue ( formKey , formValue [ j ] ) ; } } else { appendFormValue ( formKey , formValue ) ; } } request . body = requestForm ; request . formData = undefined ; const contentType = request . headers . get ( "Content-Type" ) ; if ( contentType && contentType . indexOf ( "multipart/form-data" ) !== - 1 ) { request . headers . remove ( "Content-Type" ) ; } } xhr . open ( request . method , request . url ) ; xhr . timeout = request . timeout ; xhr . withCredentials = request . withCredentials ; for ( const header of request . headers . headersArray ( ) ) { xhr . setRequestHeader ( header . name , header . value ) ; } xhr . responseType = request . streamResponseBody ? "blob" : "text" ; xhr . send ( request . body === undefined ? null : request . body ) ; if ( request . streamResponseBody ) { return new Promise ( ( resolve , reject ) => { xhr . addEventListener ( "readystatechange" , ( ) => { if ( xhr . readyState === XMLHttpRequest . HEADERS_RECEIVED ) { const blobBody = new Promise < Blob > ( ( resolve , reject ) => { xhr . addEventListener ( "load" , ( ) => { resolve ( xhr . response ) ; } ) ; rejectOnTerminalEvent ( request , xhr , reject ) ; } ) ; resolve ( { request , status : xhr . status , headers : parseHeaders ( xhr ) , blobBody , } ) ; } } ) ; rejectOnTerminalEvent ( request , xhr , reject ) ; } ) ; } else { return new Promise ( function ( resolve , reject ) { xhr . addEventListener ( "load" , ( ) => resolve ( { request , status : xhr . status , headers : parseHeaders ( xhr ) , bodyAsText : xhr . responseText , } ) ) ; rejectOnTerminalEvent ( request , xhr , reject ) ; } ) ; } } } function addProgressListener ( xhr , listener ? ) { if ( listener ) { xhr . addEventListener ( "progress" , ( rawEvent ) => listener ( { loadedBytes : rawEvent . loaded , } ) ) ; } } export function parseHeaders ( xhr ) { const responseHeaders = new HttpHeaders ( ) ; const headerLines = xhr . getAllResponseHeaders ( ) . trim ( ) . split ( /[\r\n]+/ ) ; for ( const line of headerLines ) { const index = line . indexOf ( ":" ) ; const headerName = line . slice ( 0 , index ) ; const headerValue = line . slice ( index + 2 ) ; responseHeaders . set ( headerName , headerValue ) ; } return responseHeaders ; } function rejectOnTerminalEvent ( request , xhr , reject ) { xhr . addEventListener ( "error" , ( ) => reject ( new RestError ( `Failed to send request to ${ request . url }` , RestError . REQUEST_SEND_ERROR , undefined , request ) ) ) ; xhr . addEventListener ( "abort" , ( ) => reject ( new RestError ( "The request was aborted" , RestError . REQUEST_ABORTED_ERROR , undefined , request ) ) ) ; xhr . addEventListener ( "timeout" , ( ) => reject ( new RestError ( `timeout of ${ xhr . timeout }ms exceeded` , RestError . REQUEST_SEND_ERROR , undefined , request ) ) ) ; }