1- use magnus:: { gc , DataTypeFunctions , RHash , RString , TypedData , value :: Opaque } ;
1+ use magnus:: { r_hash :: ForEach , wrap , RHash , RString , Error as MagnusError } ;
22
3+ use hyper:: { header:: HeaderName , Response as HyperResponse , StatusCode } ;
4+ use http_body_util:: Full ;
5+ use bytes:: Bytes ;
36// Response object returned to Ruby; holds reference to the opaque ruby types for the headers and body.
4- #[ derive( TypedData ) ]
5- #[ magnus( class = "HyperRuby::Response" , mark) ]
7+ #[ wrap( class = "HyperRuby::Response" ) ]
68pub struct Response {
7- pub status : u16 ,
8- pub headers : Opaque < RHash > ,
9- pub body : Opaque < RString > ,
10- }
11-
12- impl DataTypeFunctions for Response {
13- fn mark ( & self , marker : & gc:: Marker ) {
14- marker. mark ( self . headers ) ;
15- marker. mark ( self . body ) ;
16- }
9+ pub response : HyperResponse < Full < Bytes > >
1710}
1811
1912impl Response {
20- pub fn new ( status : u16 , headers : RHash , body : RString ) -> Self {
21- Self {
22- status,
23- headers : headers. into ( ) ,
24- body : body. into ( ) ,
13+ pub fn new ( status : u16 , headers : RHash , body : RString ) -> Result < Self , MagnusError > {
14+ let mut builder = HyperResponse :: builder ( )
15+ . status ( status) ;
16+
17+ let builder_headers = builder. headers_mut ( ) . unwrap ( ) ;
18+ headers. foreach ( |key : String , value : String | {
19+ let header_name = HeaderName :: try_from ( key) . unwrap ( ) ;
20+ builder_headers. insert ( header_name, value. try_into ( ) . unwrap ( ) ) ;
21+ Ok ( ForEach :: Continue )
22+ } ) . unwrap ( ) ;
23+
24+ if body. len ( ) > 0 {
25+ // safe because RString will not be cleared here before we copy the bytes into our own Vector.
26+ unsafe {
27+ // copy directly to bytes here so we don't have to worry about encoding checks
28+ let rust_body = Bytes :: copy_from_slice ( body. as_slice ( ) ) ;
29+ match builder. body ( Full :: new ( rust_body) ) {
30+ Ok ( response) => Ok ( Self { response } ) ,
31+ Err ( _) => Err ( MagnusError :: new ( magnus:: exception:: runtime_error ( ) , "Failed to create response" ) )
32+ }
33+ }
34+ } else {
35+ match builder. body ( Full :: new ( Bytes :: new ( ) ) ) {
36+ Ok ( response) => Ok ( Self { response } ) ,
37+ Err ( _) => Err ( MagnusError :: new ( magnus:: exception:: runtime_error ( ) , "Failed to create response" ) )
38+ }
2539 }
2640 }
2741}
0 commit comments