@@ -560,9 +560,10 @@ Interface of the hooks functions will be unified soon across all hook functions:
560560 options . uri = url . format ( urlObject ) + transaction . fullPath ;
561561 options . method = transaction . request . method ;
562562 options . headers = transaction . request . headers ;
563- options . body = transaction . request . body ;
563+ options . body = Buffer . from ( transaction . request . body , transaction . request . bodyEncoding ) ;
564564 options . proxy = false ;
565565 options . followRedirect = false ;
566+ options . encoding = null ;
566567 return options ;
567568 }
568569
@@ -624,8 +625,8 @@ Not performing HTTP request for '${transaction.name}'.\
624625 // Sets the Content-Length header. Overrides user-provided Content-Length
625626 // header value in case it's out of sync with the real length of the body.
626627 setContentLength ( transaction ) {
627- const { headers } = transaction . request ;
628- const { body } = transaction . request ;
628+ const headers = transaction . request . headers ;
629+ const body = Buffer . from ( transaction . request . body , transaction . request . bodyEncoding ) ;
629630
630631 const contentLengthHeaderName = caseless ( headers ) . has ( 'Content-Length' ) ;
631632 if ( contentLengthHeaderName ) {
@@ -656,14 +657,39 @@ the real body length is 0. Using 0 instead.\
656657 // An actual HTTP request, before validation hooks triggering
657658 // and the response validation is invoked here
658659 performRequestAndValidate ( test , transaction , hooks , callback ) {
660+ if ( transaction . request . body instanceof Buffer ) {
661+ const bodyBytes = transaction . request . body ;
662+
663+ // TODO case insensitive check to either base64 or utf8 or error
664+ if ( transaction . request . bodyEncoding === 'base64' ) {
665+ transaction . request . body = bodyBytes . toString ( 'base64' ) ;
666+ } else if ( transaction . request . bodyEncoding ) {
667+ transaction . request . body = bodyBytes . toString ( ) ;
668+ } else {
669+ const bodyText = bodyBytes . toString ( 'utf8' ) ;
670+ if ( bodyText . includes ( '\ufffd' ) ) {
671+ // U+FFFD is a replacement character in UTF-8 and indicates there
672+ // are some bytes which could not been translated as UTF-8. Therefore
673+ // let's assume the body is in binary format. Transferring raw bytes
674+ // over the Dredd hooks interface (JSON over TCP) is a mess, so let's
675+ // encode it as Base64
676+ transaction . request . body = bodyBytes . toString ( 'base64' ) ;
677+ transaction . request . bodyEncoding = 'base64' ;
678+ } else {
679+ transaction . request . body = bodyText ;
680+ transaction . request . bodyEncoding = 'utf8' ;
681+ }
682+ }
683+ }
684+
659685 if ( transaction . request . body && this . isMultipart ( transaction . request . headers ) ) {
660686 transaction . request . body = this . fixApiBlueprintMultipartBody ( transaction . request . body ) ;
661687 }
662688
663689 this . setContentLength ( transaction ) ;
664690 const requestOptions = this . getRequestOptionsFromTransaction ( transaction ) ;
665691
666- const handleRequest = ( err , res , body ) => {
692+ const handleRequest = ( err , res , bodyBytes ) => {
667693 if ( err ) {
668694 logger . debug ( 'Requesting tested server errored:' , `${ err } ` || err . code ) ;
669695 test . title = transaction . id ;
@@ -681,8 +707,20 @@ the real body length is 0. Using 0 instead.\
681707 headers : res . headers
682708 } ;
683709
684- if ( body ) {
685- transaction . real . body = body ;
710+ if ( bodyBytes ) {
711+ const bodyText = bodyBytes . toString ( 'utf8' ) ;
712+ if ( bodyText . includes ( '\ufffd' ) ) {
713+ // U+FFFD is a replacement character in UTF-8 and indicates there
714+ // are some bytes which could not been translated as UTF-8. Therefore
715+ // let's assume the body is in binary format. Transferring raw bytes
716+ // over the Dredd hooks interface (JSON over TCP) is a mess, so let's
717+ // encode it as Base64
718+ transaction . real . body = bodyBytes . toString ( 'base64' ) ;
719+ transaction . real . bodyEncoding = 'base64' ;
720+ } else {
721+ transaction . real . body = bodyText ;
722+ transaction . real . bodyEncoding = 'utf8' ;
723+ }
686724 } else if ( transaction . expected . body ) {
687725 // Leaving body as undefined skips its validation completely. In case
688726 // there is no real body, but there is one expected, the empty string
0 commit comments