import { HttpOperationResponse } from "../httpOperationResponse" ; import { OperationResponse } from "../operationResponse" ; import { OperationSpec , isStreamOperation } from "../operationSpec" ; import { RestError } from "../restError" ; import { Mapper , MapperType } from "../serializer" ; import * as utils from "../util/utils" ; import { parseXML } from "../util/xml" ; import { WebResourceLike } from "../webResource" ; import { BaseRequestPolicy , RequestPolicy , RequestPolicyFactory , RequestPolicyOptionsLike , } from "./requestPolicy" ; /**
 * The content-types that will indicate that an operation response should be deserialized in a
 * particular way.
 */ export interface DeserializationContentTypes { /**
     * The content-types that indicate that an operation response should be deserialized as JSON.
     * Defaults to [ "application/json", "text/json" ].
     */ json ? : string [ ] ; /**
     * The content-types that indicate that an operation response should be deserialized as XML.
     * Defaults to [ "application/xml", "application/atom+xml" ].
     */ xml ? : string [ ] ; } /**
 * Create a new serialization RequestPolicyCreator that will serialized HTTP request bodies as they
 * pass through the HTTP pipeline.
 */ export function deserializationPolicy ( deserializationContentTypes ? ) { return { create : ( nextPolicy , options ) => { return new DeserializationPolicy ( nextPolicy , deserializationContentTypes , options ) ; } , } ; } export const defaultJsonContentTypes = [ "application/json" , "text/json" ] ; export const defaultXmlContentTypes = [ "application/xml" , "application/atom+xml" ] ; /**
 * A RequestPolicy that will deserialize HTTP response bodies and headers as they pass through the
 * HTTP pipeline.
 */ export class DeserializationPolicy extends BaseRequestPolicy { public readonly jsonContentTypes : string [ ] ; public readonly xmlContentTypes : string [ ] ; constructor ( nextPolicy , deserializationContentTypes , options ) { super ( nextPolicy , options ) ; this . jsonContentTypes = ( deserializationContentTypes && deserializationContentTypes . json ) || defaultJsonContentTypes ; this . xmlContentTypes = ( deserializationContentTypes && deserializationContentTypes . xml ) || defaultXmlContentTypes ; } public async sendRequest ( request ) { return this . _nextPolicy . sendRequest ( request ) . then ( ( response ) => deserializeResponseBody ( this . jsonContentTypes , this . xmlContentTypes , response ) ) ; } } function getOperationResponse ( parsedResponse ) { let result ; const request = parsedResponse . request ; const operationSpec = request . operationSpec ; if ( operationSpec ) { const operationResponseGetter = request . operationResponseGetter ; if ( ! operationResponseGetter ) { result = operationSpec . responses [ parsedResponse . status ] ; } else { result = operationResponseGetter ( operationSpec , parsedResponse ) ; } } return result ; } function shouldDeserializeResponse ( parsedResponse ) { const shouldDeserialize = parsedResponse . request . shouldDeserialize ; let result ; if ( shouldDeserialize === undefined ) { result = true ; } else if ( typeof shouldDeserialize === "boolean" ) { result = shouldDeserialize ; } else { result = shouldDeserialize ( parsedResponse ) ; } return result ; } export function deserializeResponseBody ( jsonContentTypes , xmlContentTypes , response ) { return parse ( jsonContentTypes , xmlContentTypes , response ) . then ( ( parsedResponse ) => { const shouldDeserialize = shouldDeserializeResponse ( parsedResponse ) ; if ( shouldDeserialize ) { const operationSpec = parsedResponse . request . operationSpec ; if ( operationSpec && operationSpec . responses ) { const statusCode = parsedResponse . status ; const expectedStatusCodes = Object . keys ( operationSpec . responses ) ; const hasNoExpectedStatusCodes = expectedStatusCodes . length === 0 || ( expectedStatusCodes . length === 1 && expectedStatusCodes [ 0 ] === "default" ) ; const responseSpec = getOperationResponse ( parsedResponse ) ; const isExpectedStatusCode = hasNoExpectedStatusCodes ? 200 <= statusCode && statusCode < 300 : ! ! responseSpec ; if ( ! isExpectedStatusCode ) { const defaultResponseSpec = operationSpec . responses . default ; if ( defaultResponseSpec ) { const initialErrorMessage = isStreamOperation ( operationSpec ) ? `Unexpected status code: ${ statusCode }` : ( parsedResponse . bodyAsText as string ) ; const error = new RestError ( initialErrorMessage ) ; error . statusCode = statusCode ; error . request = utils . stripRequest ( parsedResponse . request ) ; error . response = utils . stripResponse ( parsedResponse ) ; let parsedErrorResponse = parsedResponse . parsedBody ; try { if ( parsedErrorResponse ) { const defaultResponseBodyMapper = defaultResponseSpec . bodyMapper ; if ( defaultResponseBodyMapper && defaultResponseBodyMapper . serializedName === "CloudError" ) { if ( parsedErrorResponse . error ) { parsedErrorResponse = parsedErrorResponse . error ; } if ( parsedErrorResponse . code ) { error . code = parsedErrorResponse . code ; } if ( parsedErrorResponse . message ) { error . message = parsedErrorResponse . message ; } } else { let internalError = parsedErrorResponse ; if ( parsedErrorResponse . error ) { internalError = parsedErrorResponse . error ; } error . code = internalError . code ; if ( internalError . message ) { error . message = internalError . message ; } } if ( defaultResponseBodyMapper ) { let valueToDeserialize = parsedErrorResponse ; if ( operationSpec . isXML && defaultResponseBodyMapper . type . name === MapperType . Sequence ) { valueToDeserialize = typeof parsedErrorResponse === "object" ? parsedErrorResponse [ defaultResponseBodyMapper . xmlElementName ! ] : [ ] ; } error . body = operationSpec . serializer . deserialize ( defaultResponseBodyMapper , valueToDeserialize , "error.body" ) ; } } } catch ( defaultError ) { error . message = `Error \"${ defaultError . message }\" occurred in deserializing the responseBody - \"${ parsedResponse . bodyAsText }\" for the default response.` ; } return Promise . reject ( error ) ; } } else if ( responseSpec ) { if ( responseSpec . bodyMapper ) { let valueToDeserialize = parsedResponse . parsedBody ; if ( operationSpec . isXML && responseSpec . bodyMapper . type . name === MapperType . Sequence ) { valueToDeserialize = typeof valueToDeserialize === "object" ? valueToDeserialize [ responseSpec . bodyMapper . xmlElementName ! ] : [ ] ; } try { parsedResponse . parsedBody = operationSpec . serializer . deserialize ( responseSpec . bodyMapper , valueToDeserialize , "operationRes.parsedBody" ) ; } catch ( error ) { const restError = new RestError ( `Error ${ error } occurred in deserializing the responseBody - ${ parsedResponse . bodyAsText }` ) ; restError . request = utils . stripRequest ( parsedResponse . request ) ; restError . response = utils . stripResponse ( parsedResponse ) ; return Promise . reject ( restError ) ; } } else if ( operationSpec . httpMethod === "HEAD" ) { parsedResponse . parsedBody = response . status >= 200 && response . status < 300 ; } if ( responseSpec . headersMapper ) { parsedResponse . parsedHeaders = operationSpec . serializer . deserialize ( responseSpec . headersMapper , parsedResponse . headers . rawHeaders ( ) , "operationRes.parsedHeaders" ) ; } } } } return Promise . resolve ( parsedResponse ) ; } ) ; } function parse ( jsonContentTypes , xmlContentTypes , operationResponse ) { const errorHandler = ( err ) => { const msg = `Error "${ err }" occurred while parsing the response body - ${ operationResponse . bodyAsText }.` ; const errCode = err . code || RestError . PARSE_ERROR ; const e = new RestError ( msg , errCode , operationResponse . status , operationResponse . request , operationResponse , operationResponse . bodyAsText ) ; return Promise . reject ( e ) ; } ; if ( ! operationResponse . request . streamResponseBody && operationResponse . bodyAsText ) { const text = operationResponse . bodyAsText ; const contentType = operationResponse . headers . get ( "Content-Type" ) || "" ; const contentComponents = ! contentType ? [ ] : contentType . split ( ";" ) . map ( ( component ) => component . toLowerCase ( ) ) ; if ( contentComponents . length === 0 || contentComponents . some ( ( component ) => jsonContentTypes . indexOf ( component ) !== - 1 ) ) { return new Promise < HttpOperationResponse > ( ( resolve ) => { operationResponse . parsedBody = JSON . parse ( text ) ; resolve ( operationResponse ) ; } ) . catch ( errorHandler ) ; } else if ( contentComponents . some ( ( component ) => xmlContentTypes . indexOf ( component ) !== - 1 ) ) { return parseXML ( text ) . then ( ( body ) => { operationResponse . parsedBody = body ; return operationResponse ; } ) . catch ( errorHandler ) ; } } return Promise . resolve ( operationResponse ) ; }