@@ -4,27 +4,30 @@ use base::{
44 traits:: Server as ServerTrait ,
55} ;
66use http_body_util:: { BodyExt , Full } ;
7+ use hyper:: server:: conn:: http1;
78use hyper:: { Request , Response } ;
89use hyper:: {
910 StatusCode ,
1011 body:: { Bytes , Incoming } ,
1112} ;
12- use hyper:: {
13- header:: { HeaderName , HeaderValue } ,
14- server:: conn:: http1,
15- } ;
1613use hyper_util:: rt:: TokioIo ;
17- use std :: collections :: HashMap ;
14+ use serde_json :: json ;
1815use std:: convert:: Infallible ;
1916use std:: net:: SocketAddr ;
2017use std:: sync:: Arc ;
2118use tokio:: net:: TcpListener ;
2219use tonic:: async_trait;
23- use tucana:: shared:: { AdapterConfiguration , RuntimeFeature , value:: Kind } ;
24- use tucana:: shared:: { Struct , ValidationFlow , Value } ;
25- use tucana:: shared:: { Translation , value:: Kind :: StructValue } ;
20+ use tucana:: shared:: {
21+ AdapterConfiguration , RuntimeFeature , Struct , Translation , ValidationFlow , Value ,
22+ helper:: { path:: get_string, value:: ToValue } ,
23+ value:: Kind ,
24+ } ;
25+
26+ use crate :: response:: { error_to_http_response, value_to_http_response} ;
2627
2728mod config;
29+ mod content_type;
30+ mod response;
2831mod route;
2932
3033#[ tokio:: main]
@@ -72,163 +75,43 @@ struct HttpServer {
7275 addr : Option < SocketAddr > ,
7376}
7477
75- fn json_error ( status : StatusCode , msg : & str ) -> Response < Full < Bytes > > {
76- let body = format ! ( r#"{{"error": "{}"}}"# , msg) ;
77- Response :: builder ( )
78- . status ( status)
79- . header ( "content-type" , "application/json" )
80- . body ( Full :: new ( Bytes :: from ( body) ) )
81- . unwrap ( )
82- }
83-
84- fn build_response (
85- status : StatusCode ,
86- headers : HashMap < String , String > ,
87- body : Vec < u8 > ,
88- ) -> Response < Full < Bytes > > {
89- let mut builder = Response :: builder ( ) . status ( status) ;
90-
91- {
92- let h = builder. headers_mut ( ) . unwrap ( ) ;
93- for ( k, v) in headers {
94- let name = match HeaderName :: from_bytes ( k. as_bytes ( ) ) {
95- Ok ( n) => n,
96- Err ( _) => {
97- log:: warn!( "Dropping invalid header name: {}" , k) ;
98- continue ;
99- }
100- } ;
101-
102- let value = match HeaderValue :: from_str ( & v) {
103- Ok ( v) => v,
104- Err ( _) => {
105- log:: warn!( "Dropping invalid header value for {}: {:?}" , k, v) ;
106- continue ;
107- }
108- } ;
109-
110- h. insert ( name, value) ;
111- }
112- }
113-
114- builder. body ( Full :: new ( Bytes :: from ( body) ) ) . unwrap ( )
115- }
116-
11778async fn execute_flow_to_hyper_response (
11879 flow : ValidationFlow ,
119- body : Vec < u8 > ,
80+ body : Value ,
12081 store : Arc < base:: store:: AdapterStore > ,
12182) -> Response < Full < Bytes > > {
122- let value: Option < Value > = if body. is_empty ( ) {
123- None
124- } else {
125- match prost:: Message :: decode ( body. as_slice ( ) ) {
126- Ok ( v) => Some ( v) ,
127- Err ( e) => {
128- log:: warn!( "Failed to decode request body as protobuf Value: {}" , e) ;
129- return json_error (
130- StatusCode :: BAD_REQUEST ,
131- "Failed to decode request body as protobuf Value" ,
132- ) ;
133- }
134- }
135- } ;
136-
137- match store. validate_and_execute_flow ( flow, value) . await {
83+ match store. validate_and_execute_flow ( flow, Some ( body) ) . await {
13884 Some ( result) => {
13985 log:: debug!( "Received Result: {:?}" , result) ;
140- let Value {
141- kind : Some ( StructValue ( Struct { fields } ) ) ,
142- } = result
143- else {
144- return json_error (
145- StatusCode :: INTERNAL_SERVER_ERROR ,
146- "Flow result was not a struct" ,
147- ) ;
148- } ;
14986
150- let Some ( headers_val) = fields. get ( "headers" ) else {
151- return json_error (
152- StatusCode :: INTERNAL_SERVER_ERROR ,
153- "Flow result missing headers" ,
154- ) ;
155- } ;
156- let Some ( status_code_val) = fields. get ( "status_code" ) else {
157- return json_error (
158- StatusCode :: INTERNAL_SERVER_ERROR ,
159- "Flow result missing status_code" ,
160- ) ;
161- } ;
162- let Some ( payload_val) = fields. get ( "payload" ) else {
163- return json_error (
164- StatusCode :: INTERNAL_SERVER_ERROR ,
165- "Flow result missing payload" ,
166- ) ;
167- } ;
168-
169- // headers struct
170- let Value {
87+ if let Value {
17188 kind :
17289 Some ( Kind :: StructValue ( Struct {
173- fields : header_fields ,
90+ fields : result_fields ,
17491 } ) ) ,
175- } = headers_val
176- else {
177- return json_error (
178- StatusCode :: INTERNAL_SERVER_ERROR ,
179- "headers was not a list of header entries" ,
180- ) ;
181- } ;
182-
183- let http_headers: HashMap < String , String > = header_fields
184- . iter ( )
185- . filter_map ( |( k, v) | {
186- if let Value {
187- kind : Some ( Kind :: StringValue ( x) ) ,
188- } = v
189- {
190- Some ( ( k. clone ( ) , x. clone ( ) ) )
191- } else {
192- None
193- }
194- } )
195- . collect ( ) ;
196-
197- // status_code number
198- let Some ( Kind :: NumberValue ( code) ) = status_code_val. kind else {
199- return json_error (
200- StatusCode :: INTERNAL_SERVER_ERROR ,
201- "status_code was not a number" ,
202- ) ;
203- } ;
204-
205- // payload -> json bytes
206- let json_val = tucana:: shared:: helper:: value:: to_json_value ( payload_val. clone ( ) ) ;
207- let json = serde_json:: to_vec_pretty ( & json_val) . unwrap_or_else ( |err| {
208- let fallback = serde_json:: json!( {
209- "error" : format!( "Serialization failed: {}" , err) ,
210- } ) ;
211- serde_json:: to_vec ( & fallback)
212- . unwrap_or_else ( |_| br#"{"error":"Serialization failed"}"# . to_vec ( ) )
213- } ) ;
214-
215- let http_code = match code. number {
216- Some ( num) => match num {
217- tucana:: shared:: number_value:: Number :: Integer ( int) => int as u16 ,
218- tucana:: shared:: number_value:: Number :: Float ( float) => float as u16 ,
219- } ,
220- None => {
221- return json_error ( StatusCode :: INTERNAL_SERVER_ERROR , "Flow execution failed" ) ;
92+ } = & result
93+ {
94+ if result_fields. contains_key ( "name" )
95+ && result_fields. contains_key ( "message" )
96+ && !result_fields. contains_key ( "payload" )
97+ && !result_fields. contains_key ( "headers" )
98+ {
99+ log:: debug!( "Detected a RuntimeError" ) ;
100+ let name = get_string ( "name" , & result) ;
101+ let message = get_string ( "message" , & result) ;
102+
103+ return error_to_http_response (
104+ StatusCode :: INTERNAL_SERVER_ERROR ,
105+ format ! ( "{}: {}" , name. unwrap( ) , message. unwrap( ) ) . as_str ( ) ,
106+ ) ;
222107 }
223- } ;
108+ }
224109
225- let status =
226- StatusCode :: from_u16 ( http_code) . unwrap_or ( StatusCode :: INTERNAL_SERVER_ERROR ) ;
227- build_response ( status, http_headers, json)
110+ value_to_http_response ( result)
228111 }
229112 None => {
230113 log:: error!( "flow execution failed" ) ;
231- json_error ( StatusCode :: INTERNAL_SERVER_ERROR , "Flow execution failed" )
114+ error_to_http_response ( StatusCode :: INTERNAL_SERVER_ERROR , "Flow execution failed" )
232115 }
233116 }
234117}
@@ -239,22 +122,41 @@ pub async fn handle_request(
239122) -> Result < Response < Full < Bytes > > , Infallible > {
240123 let method = req. method ( ) . clone ( ) ;
241124 let path = req. uri ( ) . path ( ) . to_string ( ) ;
125+ let headers = req. headers ( ) . clone ( ) ;
242126
243127 // Read full body
244128 let body_bytes = match BodyExt :: collect ( req. into_body ( ) ) . await {
245129 Ok ( collected) => collected. to_bytes ( ) . to_vec ( ) ,
246130 Err ( err) => {
247131 log:: error!( "Failed to read request body: {}" , err) ;
248- return Ok ( json_error (
132+ return Ok ( error_to_http_response (
249133 StatusCode :: BAD_REQUEST ,
250134 "Failed to read request body" ,
251135 ) ) ;
252136 }
253137 } ;
254138
139+ let request_body_value = match content_type:: parse_body_from_headers ( & headers, & body_bytes) {
140+ Ok ( value) => value,
141+ Err ( err) => {
142+ log:: warn!( "Failed to parse request body: {}" , err) ;
143+ let status_code = match err {
144+ content_type:: BodyParseError :: UnsupportedContentType { .. } => {
145+ StatusCode :: UNSUPPORTED_MEDIA_TYPE
146+ }
147+ _ => StatusCode :: BAD_REQUEST ,
148+ } ;
149+
150+ return Ok ( error_to_http_response ( status_code, & err. to_string ( ) ) ) ;
151+ }
152+ } ;
153+
255154 // slug matching
256155 let Some ( slug) = route:: extract_slug_from_path ( & path) else {
257- return Ok ( json_error ( StatusCode :: BAD_REQUEST , "Missing slug in path" ) ) ;
156+ return Ok ( error_to_http_response (
157+ StatusCode :: BAD_REQUEST ,
158+ "Missing slug in path" ,
159+ ) ) ;
258160 } ;
259161
260162 let pattern = format ! ( "REST.{}.*" , slug) ;
@@ -265,9 +167,42 @@ pub async fn handle_request(
265167
266168 let resp = match store. get_possible_flow_match ( pattern, route) . await {
267169 FlowIdentifyResult :: Single ( flow) => {
268- execute_flow_to_hyper_response ( flow, body_bytes, store) . await
170+ let mut header_fields = std:: collections:: HashMap :: new ( ) ;
171+ let mut fields = std:: collections:: HashMap :: new ( ) ;
172+
173+ for ( name, value) in headers. iter ( ) {
174+ let key = name. as_str ( ) . to_owned ( ) ;
175+ let value_str = value
176+ . to_str ( )
177+ . map ( str:: to_owned)
178+ . unwrap_or_else ( |_| String :: from_utf8_lossy ( value. as_bytes ( ) ) . into_owned ( ) ) ;
179+
180+ header_fields. insert ( key, value_str. to_value ( ) ) ;
181+ }
182+
183+ match request_body_value {
184+ Some ( v) => {
185+ fields. insert ( String :: from ( "payload" ) , v) ;
186+ }
187+ None => { }
188+ } ;
189+
190+ fields. insert (
191+ String :: from ( "headers" ) ,
192+ Value {
193+ kind : Some ( Kind :: StructValue ( Struct {
194+ fields : header_fields,
195+ } ) ) ,
196+ } ,
197+ ) ;
198+
199+ let input = Value {
200+ kind : Some ( Kind :: StructValue ( Struct { fields } ) ) ,
201+ } ;
202+
203+ execute_flow_to_hyper_response ( flow, input, store) . await
269204 }
270- _ => json_error ( StatusCode :: NOT_FOUND , "No flow found for path" ) ,
205+ _ => error_to_http_response ( StatusCode :: NOT_FOUND , "No flow found for path" ) ,
271206 } ;
272207
273208 Ok ( resp)
0 commit comments