@@ -3,8 +3,6 @@ use crate::error::ErrorStatus;
33use crate :: wd:: { self , WebDriverCompatibleCommand } ;
44use crate :: { error, Client } ;
55use base64:: Engine ;
6- use futures_util:: future:: { self , Either } ;
7- use futures_util:: { FutureExt , TryFutureExt } ;
86use http_body_util:: combinators:: BoxBody ;
97use http_body_util:: BodyExt ;
108use hyper_util:: client:: legacy:: connect;
@@ -683,11 +681,7 @@ where
683681 capabilities : session_config,
684682 } ;
685683
686- match client
687- . issue ( WebDriverCommand :: NewSession ( spec) )
688- . map ( Self :: map_handshake_response)
689- . await
690- {
684+ match Self :: map_handshake_response ( client. issue ( WebDriverCommand :: NewSession ( spec) ) . await ) {
691685 Ok ( new_session_response) => {
692686 client. new_session_response =
693687 Some ( wd:: NewSessionResponse :: from_wd ( new_session_response) ) ;
@@ -710,150 +704,132 @@ where
710704 & self ,
711705 cmd : Box < impl WebDriverCompatibleCommand + Send + ' static + ?Sized > ,
712706 ) -> impl Future < Output = Result < Json , error:: CmdError > > {
713- // TODO: make this an async fn
714- // will take some doing as returned future must be independent of self
715- let url = match cmd . endpoint ( & self . wdb , self . session . as_deref ( ) ) {
716- Ok ( url ) => url ,
717- Err ( e ) => return Either :: Right ( future :: err ( error :: CmdError :: from ( e ) ) ) ,
718- } ;
719-
720- let ( method, mut body) = cmd. method_and_body ( & url) ;
721-
722- // issue the command to the webdriver server
723- let mut req = hyper:: Request :: builder ( ) ;
724- req = req. method ( method) . uri ( url. as_str ( ) ) ;
725- if let Some ( ref s) = self . ua {
726- req = req. header ( hyper:: header:: USER_AGENT , s. to_owned ( ) ) ;
727- }
728- // because https://github.com/hyperium/hyper/pull/727
729- if !url. username ( ) . is_empty ( ) || url. password ( ) . is_some ( ) {
730- req = req. header (
731- hyper:: header:: AUTHORIZATION ,
732- format ! (
733- "Basic {}" ,
734- base64:: engine:: general_purpose:: STANDARD . encode( & format!(
735- "{}:{}" ,
736- url. username( ) ,
737- url. password( ) . unwrap_or( "" )
738- ) )
739- ) ,
740- ) ;
741- }
707+ let input = cmd
708+ . endpoint ( & self . wdb , self . session . as_deref ( ) )
709+ . map ( |url| ( url , self . ua . clone ( ) , self . client . clone ( ) ) ) ;
710+
711+ async move {
712+ let ( url , ua , client ) = input? ;
713+
714+ let ( method, mut body) = cmd. method_and_body ( & url) ;
715+
716+ // issue the command to the webdriver server
717+ let mut req = hyper:: Request :: builder ( ) ;
718+ req = req. method ( method) . uri ( url. as_str ( ) ) ;
719+ if let Some ( ref s) = ua {
720+ req = req. header ( hyper:: header:: USER_AGENT , s) ;
721+ }
722+ // because https://github.com/hyperium/hyper/pull/727
723+ if !url. username ( ) . is_empty ( ) || url. password ( ) . is_some ( ) {
724+ req = req. header (
725+ hyper:: header:: AUTHORIZATION ,
726+ format ! (
727+ "Basic {}" ,
728+ base64:: engine:: general_purpose:: STANDARD . encode( & format!(
729+ "{}:{}" ,
730+ url. username( ) ,
731+ url. password( ) . unwrap_or( "" )
732+ ) )
733+ ) ,
734+ ) ;
735+ }
742736
743- let json_mime: mime:: Mime = "application/json; charset=utf-8"
744- . parse :: < mime:: Mime > ( )
745- . unwrap_or ( mime:: APPLICATION_JSON ) ;
737+ let json_mime: mime:: Mime = "application/json; charset=utf-8"
738+ . parse :: < mime:: Mime > ( )
739+ . unwrap_or ( mime:: APPLICATION_JSON ) ;
746740
747- let req = if let Some ( body) = body. take ( ) {
748- req = req. header ( hyper:: header:: CONTENT_TYPE , json_mime. as_ref ( ) ) ;
749- req = req. header ( hyper:: header:: CONTENT_LENGTH , body. len ( ) ) ;
750- self . client . request ( req. body ( BoxBody :: new ( body) ) . unwrap ( ) )
751- } else {
752- self . client . request (
741+ let body = if let Some ( body) = body. take ( ) {
742+ req = req. header ( hyper:: header:: CONTENT_TYPE , json_mime. as_ref ( ) ) ;
743+ req = req. header ( hyper:: header:: CONTENT_LENGTH , body. len ( ) ) ;
744+ req. body ( BoxBody :: new ( body) ) . unwrap ( )
745+ } else {
753746 req. body ( BoxBody :: new ( http_body_util:: Empty :: new ( ) ) )
754- . unwrap ( ) ,
755- )
756- } ;
747+ . unwrap ( )
748+ } ;
757749
758- let f = req
759- . map_err ( error:: CmdError :: from)
760- . and_then ( move |res| {
761- // keep track of result status (.body() consumes self -- ugh)
762- let status = res. status ( ) ;
763-
764- // check that the server sent us json
765- let ctype = res
766- . headers ( )
767- . get ( hyper:: header:: CONTENT_TYPE )
768- . and_then ( |ctype| ctype. to_str ( ) . ok ( ) ?. parse :: < mime:: Mime > ( ) . ok ( ) ) ;
769-
770- // What did the server send us?
771- res. into_body ( )
772- . collect ( )
773- . map_ok ( |body| body. to_bytes ( ) )
774- . map_ok ( move |body| ( body, ctype, status) )
775- . map_err ( |e| -> error:: CmdError { e. into ( ) } )
776- } )
777- . map ( |r| {
778- let ( body, ctype, status) = r?;
779-
780- // Too bad we can't stream into a String :(
781- let body =
782- String :: from_utf8 ( body. to_vec ( ) ) . expect ( "non utf-8 response from webdriver" ) ;
783-
784- if let Some ( ctype) = ctype {
785- if ctype. type_ ( ) == mime:: APPLICATION_JSON . type_ ( )
786- && ctype. subtype ( ) == mime:: APPLICATION_JSON . subtype ( )
787- {
788- Ok ( ( body, status) )
789- } else {
790- // nope, something else...
791- Err ( error:: CmdError :: NotJson ( body) )
792- }
793- } else {
794- // WebDriver host sent us something weird...
795- Err ( error:: CmdError :: NotJson ( body) )
796- }
797- } )
798- . map ( move |r| {
799- let ( body, status) = r?;
800- let is_success = status. is_success ( ) ;
801-
802- // https://www.w3.org/TR/webdriver/#dfn-send-a-response
803- // NOTE: the standard specifies that even errors use the "Send a Response" steps
804- let body = match serde_json:: from_str ( & * body) ? {
805- Json :: Object ( mut v) => v
806- . remove ( "value" )
807- . ok_or ( error:: CmdError :: NotW3C ( Json :: Object ( v) ) ) ,
808- v => Err ( error:: CmdError :: NotW3C ( v) ) ,
809- } ?;
810-
811- if is_success {
812- return Ok ( body) ;
813- }
750+ let res = client. request ( body) . await ?;
751+ // keep track of result status (.body() consumes self -- ugh)
752+ let status = res. status ( ) ;
814753
815- // https://www.w3.org/TR/webdriver/#dfn-send-an-error
816- // https://www.w3.org/TR/webdriver/#handling-errors
817- let mut body = match body {
818- Json :: Object ( o) => o,
819- j => return Err ( error:: CmdError :: NotW3C ( j) ) ,
820- } ;
754+ // check that the server sent us json
755+ let ctype = res
756+ . headers ( )
757+ . get ( hyper:: header:: CONTENT_TYPE )
758+ . and_then ( |ctype| ctype. to_str ( ) . ok ( ) ?. parse :: < mime:: Mime > ( ) . ok ( ) ) ;
759+
760+ // What did the server send us?
761+ let body = res. into_body ( ) . collect ( ) . await ?. to_bytes ( ) ;
821762
822- // phantomjs injects a *huge* field with the entire screen contents -- remove that
823- body. remove ( "screen ") ;
763+ // Too bad we can't stream into a String :(
764+ let body = String :: from_utf8 ( body. to_vec ( ) ) . expect ( "non utf-8 response from webdriver ") ;
824765
825- if !body. contains_key ( "error" )
826- || !body. contains_key ( "message" )
827- || !body[ "error" ] . is_string ( )
828- || !body[ "message" ] . is_string ( )
766+ if let Some ( ctype) = ctype {
767+ if ctype. type_ ( ) != mime:: APPLICATION_JSON . type_ ( )
768+ || ctype. subtype ( ) != mime:: APPLICATION_JSON . subtype ( )
829769 {
830- return Err ( error:: CmdError :: NotW3C ( Json :: Object ( body) ) ) ;
770+ // nope, something else...
771+ return Err ( error:: CmdError :: NotJson ( body) ) ;
831772 }
773+ } else {
774+ // WebDriver host sent us something weird...
775+ return Err ( error:: CmdError :: NotJson ( body) ) ;
776+ }
832777
833- let Some ( es) = body[ "error" ] . as_str ( ) else {
834- return Err ( error:: CmdError :: NotW3C ( Json :: Object ( body) ) ) ;
835- } ;
836- let es = es. parse ( ) ?;
778+ let is_success = status. is_success ( ) ;
837779
838- let message = match body. remove ( "message" ) {
839- Some ( Json :: String ( x) ) => x,
840- _ => String :: new ( ) ,
841- } ;
780+ // https://www.w3.org/TR/webdriver/#dfn-send-a-response
781+ // NOTE: the standard specifies that even errors use the "Send a Response" steps
782+ let body = match serde_json:: from_str ( & body) ? {
783+ Json :: Object ( mut v) => v
784+ . remove ( "value" )
785+ . ok_or ( error:: CmdError :: NotW3C ( Json :: Object ( v) ) ) ,
786+ v => Err ( error:: CmdError :: NotW3C ( v) ) ,
787+ } ?;
842788
843- let mut wd_error = error:: WebDriver :: new ( es, message) ;
789+ if is_success {
790+ return Ok ( body) ;
791+ }
844792
845- // Add the stacktrace if there is one.
846- if let Some ( Json :: String ( x) ) = body. remove ( "stacktrace" ) {
847- wd_error = wd_error. with_stacktrace ( x) ;
848- }
793+ // https://www.w3.org/TR/webdriver/#dfn-send-an-error
794+ // https://www.w3.org/TR/webdriver/#handling-errors
795+ let mut body = match body {
796+ Json :: Object ( o) => o,
797+ j => return Err ( error:: CmdError :: NotW3C ( j) ) ,
798+ } ;
849799
850- // Some commands may annotate errors with extra data.
851- if let Some ( x) = body. remove ( "data" ) {
852- wd_error = wd_error. with_data ( x) ;
853- }
854- Err ( error:: CmdError :: from_webdriver_error ( wd_error) )
855- } ) ;
800+ // phantomjs injects a *huge* field with the entire screen contents -- remove that
801+ body. remove ( "screen" ) ;
802+
803+ if !body. contains_key ( "error" )
804+ || !body. contains_key ( "message" )
805+ || !body[ "error" ] . is_string ( )
806+ || !body[ "message" ] . is_string ( )
807+ {
808+ return Err ( error:: CmdError :: NotW3C ( Json :: Object ( body) ) ) ;
809+ }
810+
811+ let Some ( es) = body[ "error" ] . as_str ( ) else {
812+ return Err ( error:: CmdError :: NotW3C ( Json :: Object ( body) ) ) ;
813+ } ;
814+ let es = es. parse ( ) ?;
815+
816+ let message = match body. remove ( "message" ) {
817+ Some ( Json :: String ( x) ) => x,
818+ _ => String :: new ( ) ,
819+ } ;
820+
821+ let mut wd_error = error:: WebDriver :: new ( es, message) ;
856822
857- Either :: Left ( f)
823+ // Add the stacktrace if there is one.
824+ if let Some ( Json :: String ( x) ) = body. remove ( "stacktrace" ) {
825+ wd_error = wd_error. with_stacktrace ( x) ;
826+ }
827+
828+ // Some commands may annotate errors with extra data.
829+ if let Some ( x) = body. remove ( "data" ) {
830+ wd_error = wd_error. with_data ( x) ;
831+ }
832+ Err ( error:: CmdError :: from_webdriver_error ( wd_error) )
833+ }
858834 }
859835}
0 commit comments