1- use std:: { cell:: RefCell , net:: SocketAddr } ;
1+ use std:: { cell:: RefCell , collections :: HashSet , net:: SocketAddr } ;
22
33use async_trait:: async_trait;
44use pingora:: {
@@ -134,16 +134,22 @@ impl ProxyHttp for ScriptedProxy {
134134 upstream_response : & mut ResponseHeader ,
135135 ctx : & mut Self :: CTX ,
136136 ) -> PingoraResult < ( ) > {
137+ let mut inserted = HashSet :: new ( ) ;
137138 for ( name, value) in & ctx. response_headers {
138- upstream_response
139- . insert_header ( name. clone ( ) , value. clone ( ) )
140- . map_err ( |err| {
141- Error :: because (
142- ErrorType :: InternalError ,
143- "failed to apply RustScript response header" ,
144- err,
145- )
146- } ) ?;
139+ let result = if inserted. insert ( name. to_ascii_lowercase ( ) ) {
140+ upstream_response. insert_header ( name. clone ( ) , value. clone ( ) )
141+ } else {
142+ upstream_response
143+ . append_header ( name. clone ( ) , value. clone ( ) )
144+ . map ( |_| ( ) )
145+ } ;
146+ result. map_err ( |err| {
147+ Error :: because (
148+ ErrorType :: InternalError ,
149+ "failed to apply RustScript response header" ,
150+ err,
151+ )
152+ } ) ?;
147153 }
148154 Ok ( ( ) )
149155 }
@@ -248,6 +254,12 @@ fn bind_pingora_hosts(vm: &mut Vm) {
248254 host:: pingora:: request_method_host,
249255 ) ;
250256 vm. bind_static_args_function ( "pingora::request::path" , host:: pingora:: request_path_host) ;
257+ vm. bind_static_args_function ( "pingora::request::query" , host:: pingora:: request_query_host) ;
258+ vm. bind_static_args_function ( "pingora::request::uri" , host:: pingora:: request_uri_host) ;
259+ vm. bind_static_args_function (
260+ "pingora::request::version" ,
261+ host:: pingora:: request_version_host,
262+ ) ;
251263 vm. bind_static_args_function (
252264 "pingora::request::header" ,
253265 host:: pingora:: request_header_host,
@@ -256,6 +268,22 @@ fn bind_pingora_hosts(vm: &mut Vm) {
256268 "pingora::request::insert_header" ,
257269 host:: pingora:: request_insert_header_host,
258270 ) ;
271+ vm. bind_static_args_function (
272+ "pingora::request::append_header" ,
273+ host:: pingora:: request_append_header_host,
274+ ) ;
275+ vm. bind_static_args_function (
276+ "pingora::request::remove_header" ,
277+ host:: pingora:: request_remove_header_host,
278+ ) ;
279+ vm. bind_static_args_function (
280+ "pingora::request::set_method" ,
281+ host:: pingora:: request_set_method_host,
282+ ) ;
283+ vm. bind_static_args_function (
284+ "pingora::request::set_uri" ,
285+ host:: pingora:: request_set_uri_host,
286+ ) ;
259287 vm. bind_static_args_function (
260288 "pingora::response::set_status" ,
261289 host:: pingora:: response_set_status_host,
@@ -268,6 +296,18 @@ fn bind_pingora_hosts(vm: &mut Vm) {
268296 "pingora::response::insert_header" ,
269297 host:: pingora:: response_insert_header_host,
270298 ) ;
299+ vm. bind_static_args_function (
300+ "pingora::response::append_header" ,
301+ host:: pingora:: response_append_header_host,
302+ ) ;
303+ vm. bind_static_args_function (
304+ "pingora::response::remove_header" ,
305+ host:: pingora:: response_remove_header_host,
306+ ) ;
307+ vm. bind_static_args_function (
308+ "pingora::response::header" ,
309+ host:: pingora:: response_header_host,
310+ ) ;
271311}
272312
273313mod host {
@@ -345,16 +385,46 @@ mod host {
345385 return_one ( request_method ( args) )
346386 }
347387
348- /// Returns the live Pingora request path .
388+ /// Returns the path component of the live Pingora request URI .
349389 #[ pd_host_function( name = "pingora::request::path" ) ]
350390 pub ( super ) fn request_path_impl ( ) -> VmResult < String > {
351- with_request ( |request| Ok ( String :: from_utf8_lossy ( request. raw_path ( ) ) . into_owned ( ) ) )
391+ with_request ( |request| Ok ( request. uri . path ( ) . to_string ( ) ) )
352392 }
353393
354394 pub ( crate ) fn request_path_host ( args : & [ Value ] ) -> VmResult < CallOutcome > {
355395 return_one ( request_path ( args) )
356396 }
357397
398+ /// Returns the query component of the live Pingora request URI.
399+ #[ pd_host_function( name = "pingora::request::query" ) ]
400+ pub ( super ) fn request_query_impl ( ) -> VmResult < String > {
401+ with_request ( |request| Ok ( request. uri . query ( ) . unwrap_or ( "" ) . to_string ( ) ) )
402+ }
403+
404+ pub ( crate ) fn request_query_host ( args : & [ Value ] ) -> VmResult < CallOutcome > {
405+ return_one ( request_query ( args) )
406+ }
407+
408+ /// Returns the live Pingora request URI.
409+ #[ pd_host_function( name = "pingora::request::uri" ) ]
410+ pub ( super ) fn request_uri_impl ( ) -> VmResult < String > {
411+ with_request ( |request| Ok ( request. uri . to_string ( ) ) )
412+ }
413+
414+ pub ( crate ) fn request_uri_host ( args : & [ Value ] ) -> VmResult < CallOutcome > {
415+ return_one ( request_uri ( args) )
416+ }
417+
418+ /// Returns the HTTP version of the live Pingora request.
419+ #[ pd_host_function( name = "pingora::request::version" ) ]
420+ pub ( super ) fn request_version_impl ( ) -> VmResult < String > {
421+ with_request ( |request| Ok ( format ! ( "{:?}" , request. version) ) )
422+ }
423+
424+ pub ( crate ) fn request_version_host ( args : & [ Value ] ) -> VmResult < CallOutcome > {
425+ return_one ( request_version ( args) )
426+ }
427+
358428 /// Reads a header from the live Pingora request.
359429 #[ pd_host_function( name = "pingora::request::header" ) ]
360430 pub ( super ) fn request_header_impl ( name : & str ) -> VmResult < String > {
@@ -390,6 +460,66 @@ mod host {
390460 return_one ( request_insert_header ( args) )
391461 }
392462
463+ /// Calls Pingora RequestHeader::append_header on the live request.
464+ #[ pd_host_function( name = "pingora::request::append_header" ) ]
465+ pub ( super ) fn request_append_header_impl ( name : & str , value : & str ) -> VmResult < bool > {
466+ ensure_script_header_allowed ( name) ?;
467+ with_request ( |request| {
468+ request
469+ . append_header ( name. to_string ( ) , value. to_string ( ) )
470+ . map_err ( |err| {
471+ VmError :: HostError ( format ! ( "Pingora request append_header: {err}" ) )
472+ } )
473+ } )
474+ }
475+
476+ pub ( crate ) fn request_append_header_host ( args : & [ Value ] ) -> VmResult < CallOutcome > {
477+ return_one ( request_append_header ( args) )
478+ }
479+
480+ /// Calls Pingora RequestHeader::remove_header on the live request.
481+ #[ pd_host_function( name = "pingora::request::remove_header" ) ]
482+ pub ( super ) fn request_remove_header_impl ( name : & str ) -> VmResult < bool > {
483+ ensure_script_header_allowed ( name) ?;
484+ with_request ( |request| Ok ( request. remove_header ( name) . is_some ( ) ) )
485+ }
486+
487+ pub ( crate ) fn request_remove_header_host ( args : & [ Value ] ) -> VmResult < CallOutcome > {
488+ return_one ( request_remove_header ( args) )
489+ }
490+
491+ /// Calls Pingora RequestHeader::set_method on the live request.
492+ #[ pd_host_function( name = "pingora::request::set_method" ) ]
493+ pub ( super ) fn request_set_method_impl ( method : & str ) -> VmResult < bool > {
494+ with_request ( |request| {
495+ let method = method. parse ( ) . map_err ( |err| {
496+ VmError :: HostError ( format ! ( "Pingora request invalid method: {err}" ) )
497+ } ) ?;
498+ request. set_method ( method) ;
499+ Ok ( true )
500+ } )
501+ }
502+
503+ pub ( crate ) fn request_set_method_host ( args : & [ Value ] ) -> VmResult < CallOutcome > {
504+ return_one ( request_set_method ( args) )
505+ }
506+
507+ /// Calls Pingora RequestHeader::set_uri on the live request.
508+ #[ pd_host_function( name = "pingora::request::set_uri" ) ]
509+ pub ( super ) fn request_set_uri_impl ( uri : & str ) -> VmResult < bool > {
510+ with_request ( |request| {
511+ let uri = uri. parse ( ) . map_err ( |err| {
512+ VmError :: HostError ( format ! ( "Pingora request invalid URI: {err}" ) )
513+ } ) ?;
514+ request. set_uri ( uri) ;
515+ Ok ( true )
516+ } )
517+ }
518+
519+ pub ( crate ) fn request_set_uri_host ( args : & [ Value ] ) -> VmResult < CallOutcome > {
520+ return_one ( request_set_uri ( args) )
521+ }
522+
393523 /// Calls Pingora ResponseHeader::set_status on the live response.
394524 #[ pd_host_function( name = "pingora::response::set_status" ) ]
395525 pub ( super ) fn response_set_status_impl ( status : i64 ) -> VmResult < bool > {
@@ -417,6 +547,23 @@ mod host {
417547 return_one ( response_status ( args) )
418548 }
419549
550+ /// Reads a header from the live Pingora response.
551+ #[ pd_host_function( name = "pingora::response::header" ) ]
552+ pub ( super ) fn response_header_impl ( name : & str ) -> VmResult < String > {
553+ with_response ( |response| {
554+ Ok ( response
555+ . headers
556+ . get ( name)
557+ . and_then ( |value| value. to_str ( ) . ok ( ) )
558+ . unwrap_or ( "" )
559+ . to_string ( ) )
560+ } )
561+ }
562+
563+ pub ( crate ) fn response_header_host ( args : & [ Value ] ) -> VmResult < CallOutcome > {
564+ return_one ( response_header ( args) )
565+ }
566+
420567 /// Calls Pingora ResponseHeader::insert_header on the live response.
421568 #[ pd_host_function( name = "pingora::response::insert_header" ) ]
422569 pub ( super ) fn response_insert_header_impl ( name : & str , value : & str ) -> VmResult < bool > {
@@ -434,5 +581,33 @@ mod host {
434581 pub ( crate ) fn response_insert_header_host ( args : & [ Value ] ) -> VmResult < CallOutcome > {
435582 return_one ( response_insert_header ( args) )
436583 }
584+
585+ /// Calls Pingora ResponseHeader::append_header on the live response.
586+ #[ pd_host_function( name = "pingora::response::append_header" ) ]
587+ pub ( super ) fn response_append_header_impl ( name : & str , value : & str ) -> VmResult < bool > {
588+ ensure_script_header_allowed ( name) ?;
589+ with_response ( |response| {
590+ response
591+ . append_header ( name. to_string ( ) , value. to_string ( ) )
592+ . map_err ( |err| {
593+ VmError :: HostError ( format ! ( "Pingora response append_header: {err}" ) )
594+ } )
595+ } )
596+ }
597+
598+ pub ( crate ) fn response_append_header_host ( args : & [ Value ] ) -> VmResult < CallOutcome > {
599+ return_one ( response_append_header ( args) )
600+ }
601+
602+ /// Calls Pingora ResponseHeader::remove_header on the live response.
603+ #[ pd_host_function( name = "pingora::response::remove_header" ) ]
604+ pub ( super ) fn response_remove_header_impl ( name : & str ) -> VmResult < bool > {
605+ ensure_script_header_allowed ( name) ?;
606+ with_response ( |response| Ok ( response. remove_header ( name) . is_some ( ) ) )
607+ }
608+
609+ pub ( crate ) fn response_remove_header_host ( args : & [ Value ] ) -> VmResult < CallOutcome > {
610+ return_one ( response_remove_header ( args) )
611+ }
437612 }
438613}
0 commit comments