@@ -26,11 +26,6 @@ mod payload;
2626mod placeholders;
2727mod ua;
2828
29- // Placeholders used for interpolating --http-success
30- const HTTP_USERNAME_VAR : & str = "{$username}" ;
31- const HTTP_PASSWORD_VAR : & str = "{$password}" ;
32- const HTTP_PAYLOAD_VAR : & str = "{$payload}" ;
33-
3429const HTTP_LOWERCASE_PLACEHOLDERS : & [ & str ] = & [ "{payload}" , "{username}" , "{password}" ] ;
3530const HTTP_UPPERCASE_PLACEHOLDERS : & [ & str ] = & [ "{PAYLOAD}" , "{USERNAME}" , "{PASSWORD}" ] ;
3631
@@ -79,7 +74,7 @@ pub(crate) struct HTTP {
7974 real_target : Option < String > ,
8075 user_agent : Option < String > ,
8176
82- success_expression : String ,
77+ success_expression : evalexpr :: Node < evalexpr :: DefaultNumericTypes > ,
8378
8479 enum_ext : String ,
8580 enum_ext_placeholder : String ,
@@ -103,8 +98,8 @@ impl HTTP {
10398 csrf : None ,
10499 domain : String :: new ( ) ,
105100 workstation : String :: new ( ) ,
106- success_expression : String :: new ( ) ,
107101 enum_ext : String :: new ( ) ,
102+ success_expression : evalexpr:: build_operator_tree ( "" ) . unwrap ( ) ,
108103 enum_ext_placeholder : String :: new ( ) ,
109104 method : Method :: GET ,
110105 headers : HeaderMap :: default ( ) ,
@@ -238,11 +233,11 @@ impl HTTP {
238233 builder
239234 }
240235
241- async fn is_success_response (
236+ async fn build_response_context (
242237 & self ,
243238 creds : & Credentials ,
244239 response : Response ,
245- ) -> Option < Success > {
240+ ) -> Result < ( u16 , String , usize , HashMapContext < DefaultNumericTypes > ) , Error > {
246241 let status = response. status ( ) . as_u16 ( ) ;
247242
248243 let mut context = HashMapContext :: < DefaultNumericTypes > :: new ( ) ;
@@ -265,14 +260,14 @@ impl HTTP {
265260
266261 context
267262 . set_value ( header_var_name, Value :: from ( value. to_str ( ) . unwrap ( ) ) )
268- . unwrap ( ) ;
263+ . map_err ( |e| e . to_string ( ) ) ? ;
269264 }
270265
271266 // always set content_type
272267 if !content_type_set {
273268 context
274269 . set_value ( String :: from ( "content_type" ) , Value :: from ( "" ) )
275- . unwrap ( ) ;
270+ . map_err ( |e| e . to_string ( ) ) ? ;
276271 }
277272
278273 // add response status, body, size and content type to the context
@@ -281,13 +276,13 @@ impl HTTP {
281276
282277 context
283278 . set_value ( String :: from ( "status" ) , Value :: from_int ( status as i64 ) )
284- . unwrap ( ) ;
279+ . map_err ( |e| e . to_string ( ) ) ? ;
285280 context
286281 . set_value ( String :: from ( "body" ) , Value :: from ( body) )
287- . unwrap ( ) ;
282+ . map_err ( |e| e . to_string ( ) ) ? ;
288283 context
289284 . set_value ( String :: from ( "size" ) , Value :: from_int ( size as i64 ) )
290- . unwrap ( ) ;
285+ . map_err ( |e| e . to_string ( ) ) ? ;
291286
292287 // the builtin contains function is for searching a string within a tuple of strings,
293288 // let's override it to something that makes more sense
@@ -305,37 +300,61 @@ impl HTTP {
305300 }
306301 } ) ,
307302 )
308- . unwrap ( ) ;
309-
310- // replace placeholders with actual values
311- let success_expression = self
312- . success_expression
313- . replace ( HTTP_USERNAME_VAR , & creds. username )
314- . replace ( HTTP_PASSWORD_VAR , & creds. password )
315- . replace ( HTTP_PAYLOAD_VAR , creds. single ( ) ) ;
316-
317- match eval_boolean_with_context ( & success_expression, & context) {
318- Ok ( result) => {
319- if result {
320- Some ( Success {
321- status,
322- content_type,
323- size,
324- } )
325- } else {
303+ . map_err ( |e| e. to_string ( ) ) ?;
304+
305+ // set placeholders with actual values
306+ context
307+ . set_value (
308+ String :: from ( "username" ) ,
309+ Value :: from ( creds. username . clone ( ) ) ,
310+ )
311+ . map_err ( |e| e. to_string ( ) ) ?;
312+ context
313+ . set_value (
314+ String :: from ( "password" ) ,
315+ Value :: from ( creds. password . clone ( ) ) ,
316+ )
317+ . map_err ( |e| e. to_string ( ) ) ?;
318+ context
319+ . set_value ( String :: from ( "payload" ) , Value :: from ( creds. single ( ) ) )
320+ . map_err ( |e| e. to_string ( ) ) ?;
321+
322+ Ok ( ( status, content_type, size, context) )
323+ }
324+
325+ async fn is_success_response (
326+ & self ,
327+ creds : & Credentials ,
328+ response : Response ,
329+ ) -> Option < Success > {
330+ let built = self . build_response_context ( creds, response) . await ;
331+ if let Ok ( ( status, content_type, size, context) ) = built {
332+ match self . success_expression . eval_boolean_with_context ( & context) {
333+ Ok ( result) => {
334+ if result {
335+ Some ( Success {
336+ status,
337+ content_type,
338+ size,
339+ } )
340+ } else {
341+ None
342+ }
343+ }
344+ Err ( e) => {
345+ #[ cfg( test) ]
346+ println ! (
347+ "error evaluating expression '{}': {}" ,
348+ self . success_expression, e
349+ ) ;
350+ #[ cfg( not( test) ) ]
351+ log:: error!( "error evaluating success expression: {}" , e) ;
326352 None
327353 }
328354 }
329- Err ( e) => {
330- #[ cfg( test) ]
331- println ! (
332- "error evaluating expression '{}': {}" ,
333- success_expression, e
334- ) ;
335- #[ cfg( not( test) ) ]
336- log:: error!( "error evaluating success expression: {}" , e) ;
337- None
338- }
355+ } else {
356+ log:: error!( "error building response context: {}" , built. err( ) . unwrap( ) ) ;
357+ None
339358 }
340359 }
341360
@@ -865,7 +884,13 @@ impl Plugin for HTTP {
865884 None
866885 } ;
867886
868- self . success_expression = opts. http . http_success . clone ( ) ;
887+ self . success_expression =
888+ evalexpr:: build_operator_tree ( & opts. http . http_success ) . map_err ( |e| {
889+ format ! (
890+ "error parsing success expression '{}': {}" ,
891+ opts. http. http_success, e
892+ )
893+ } ) ?;
869894
870895 self . enum_ext = opts. http . http_enum_ext . clone ( ) ;
871896 self . enum_ext_placeholder = opts. http . http_enum_ext_placeholder . clone ( ) ;
0 commit comments