@@ -433,6 +433,8 @@ namespace ccfapp
433433 JS_SetOpaque (tables_, &args.tx );
434434 JS_SetPropertyStr (ctx, global_obj, " tables" , tables_);
435435
436+ auto request = JS_NewObject (ctx);
437+
436438 auto headers = JS_NewObject (ctx);
437439 for (auto & [header_name, header_value] :
438440 args.rpc_ctx ->get_request_headers ())
@@ -443,17 +445,29 @@ namespace ccfapp
443445 header_name.c_str (),
444446 JS_NewStringLen (ctx, header_value.c_str (), header_value.size ()));
445447 }
446- JS_SetPropertyStr (ctx, global_obj , " headers" , headers);
448+ JS_SetPropertyStr (ctx, request , " headers" , headers);
447449
448450 const auto & request_query = args.rpc_ctx ->get_request_query ();
449451 auto query_str =
450452 JS_NewStringLen (ctx, request_query.c_str (), request_query.size ());
451- JS_SetPropertyStr (ctx, global_obj, " query" , query_str);
453+ JS_SetPropertyStr (ctx, request, " query" , query_str);
454+
455+ auto params = JS_NewObject (ctx);
456+ for (auto & [param_name, param_value] :
457+ args.rpc_ctx ->get_request_path_params ())
458+ {
459+ JS_SetPropertyStr (
460+ ctx,
461+ params,
462+ param_name.c_str (),
463+ JS_NewStringLen (ctx, param_value.c_str (), param_value.size ()));
464+ }
465+ JS_SetPropertyStr (ctx, request, " params" , params);
452466
453467 const auto & request_body = args.rpc_ctx ->get_request_body ();
454468 auto body_ = JS_NewObjectClass (ctx, body_class_id);
455469 JS_SetOpaque (body_, (void *)&request_body);
456- JS_SetPropertyStr (ctx, global_obj , " body" , body_);
470+ JS_SetPropertyStr (ctx, request , " body" , body_);
457471
458472 JS_FreeValue (ctx, global_obj);
459473
@@ -507,9 +521,10 @@ namespace ccfapp
507521 }
508522
509523 // Call exported function
510- int argc = 0 ;
511- JSValueConst* argv = nullptr ;
524+ int argc = 1 ;
525+ JSValueConst* argv = (JSValueConst*)&request ;
512526 auto val = JS_Call (ctx, export_func, JS_UNDEFINED , argc, argv);
527+ JS_FreeValue (ctx, request);
513528 JS_FreeValue (ctx, export_func);
514529
515530 if (JS_IsException (val))
@@ -520,13 +535,22 @@ namespace ccfapp
520535 return ;
521536 }
522537
523- // Handle return value
524- std::string response_content_type;
538+ // Handle return value: {body, headers, statusCode}
539+ if (!JS_IsObject (val))
540+ {
541+ args.rpc_ctx ->set_response_status (HTTP_STATUS_INTERNAL_SERVER_ERROR );
542+ args.rpc_ctx ->set_response_body (
543+ " Invalid endpoint function return value" );
544+ return ;
545+ }
546+
547+ // Response body (also sets a default response content-type header)
548+ auto response_body_js = JS_GetPropertyStr (ctx, val, " body" );
525549 std::vector<uint8_t > response_body;
526550 size_t buf_size;
527551 size_t buf_offset;
528- JSValue typed_array_buffer =
529- JS_GetTypedArrayBuffer ( ctx, val , &buf_offset, &buf_size, nullptr );
552+ JSValue typed_array_buffer = JS_GetTypedArrayBuffer (
553+ ctx, response_body_js , &buf_offset, &buf_size, nullptr );
530554 uint8_t * array_buffer;
531555 if (!JS_IsException (typed_array_buffer))
532556 {
@@ -538,26 +562,33 @@ namespace ccfapp
538562 }
539563 else
540564 {
541- array_buffer = JS_GetArrayBuffer (ctx, &buf_size, val );
565+ array_buffer = JS_GetArrayBuffer (ctx, &buf_size, response_body_js );
542566 }
543567 if (array_buffer)
544568 {
545- response_content_type = http::headervalues::contenttype::OCTET_STREAM ;
569+ args.rpc_ctx ->set_response_header (
570+ http::headers::CONTENT_TYPE ,
571+ http::headervalues::contenttype::OCTET_STREAM );
546572 response_body =
547573 std::vector<uint8_t >(array_buffer, array_buffer + buf_size);
548574 }
549575 else
550576 {
551577 const char * cstr = nullptr ;
552- if (JS_IsString (val ))
578+ if (JS_IsString (response_body_js ))
553579 {
554- response_content_type = http::headervalues::contenttype::TEXT ;
555- cstr = JS_ToCString (ctx, val);
580+ args.rpc_ctx ->set_response_header (
581+ http::headers::CONTENT_TYPE ,
582+ http::headervalues::contenttype::TEXT );
583+ cstr = JS_ToCString (ctx, response_body_js);
556584 }
557585 else
558586 {
559- response_content_type = http::headervalues::contenttype::JSON ;
560- JSValue rval = JS_JSONStringify (ctx, val, JS_NULL , JS_NULL );
587+ args.rpc_ctx ->set_response_header (
588+ http::headers::CONTENT_TYPE ,
589+ http::headervalues::contenttype::JSON );
590+ JSValue rval =
591+ JS_JSONStringify (ctx, response_body_js, JS_NULL , JS_NULL );
561592 cstr = JS_ToCString (ctx, rval);
562593 JS_FreeValue (ctx, rval);
563594 }
@@ -566,16 +597,58 @@ namespace ccfapp
566597
567598 response_body = std::vector<uint8_t >(str.begin (), str.end ());
568599 }
600+ JS_FreeValue (ctx, response_body_js);
601+ args.rpc_ctx ->set_response_body (std::move (response_body));
602+
603+ // Response headers
604+ auto response_headers_js = JS_GetPropertyStr (ctx, val, " headers" );
605+ if (JS_IsObject (response_headers_js))
606+ {
607+ uint32_t prop_count = 0 ;
608+ JSPropertyEnum* props = nullptr ;
609+ JS_GetOwnPropertyNames (
610+ ctx,
611+ &props,
612+ &prop_count,
613+ response_headers_js,
614+ JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY );
615+ for (size_t i = 0 ; i < prop_count; i++)
616+ {
617+ auto prop_name = props[i].atom ;
618+ auto prop_name_cstr = JS_AtomToCString (ctx, prop_name);
619+ auto prop_val = JS_GetProperty (ctx, response_headers_js, prop_name);
620+ auto prop_val_cstr = JS_ToCString (ctx, prop_val);
621+ if (!prop_val_cstr)
622+ {
623+ args.rpc_ctx ->set_response_status (
624+ HTTP_STATUS_INTERNAL_SERVER_ERROR );
625+ args.rpc_ctx ->set_response_body (" Invalid header value type" );
626+ return ;
627+ }
628+ args.rpc_ctx ->set_response_header (prop_name_cstr, prop_val_cstr);
629+ JS_FreeCString (ctx, prop_name_cstr);
630+ JS_FreeCString (ctx, prop_val_cstr);
631+ JS_FreeValue (ctx, prop_val);
632+ }
633+ js_free (ctx, props);
634+ }
635+ JS_FreeValue (ctx, response_headers_js);
636+
637+ // Response status code
638+ int response_status_code = HTTP_STATUS_OK ;
639+ auto status_code_js = JS_GetPropertyStr (ctx, val, " statusCode" );
640+ if (JS_VALUE_GET_TAG (status_code_js) == JS_TAG_INT )
641+ {
642+ response_status_code = JS_VALUE_GET_INT (status_code_js);
643+ }
644+ JS_FreeValue (ctx, status_code_js);
645+ args.rpc_ctx ->set_response_status (response_status_code);
569646
570647 JS_FreeValue (ctx, val);
571648
572649 JS_FreeContext (ctx);
573650 JS_FreeRuntime (rt);
574651
575- args.rpc_ctx ->set_response_status (HTTP_STATUS_OK );
576- args.rpc_ctx ->set_response_body (std::move (response_body));
577- args.rpc_ctx ->set_response_header (
578- http::headers::CONTENT_TYPE , response_content_type);
579652 return ;
580653 };
581654
0 commit comments