Last active
August 24, 2023 19:27
-
-
Save ac000/268faacbd1b545d8c45ea5303ee6fdd4 to your computer and use it in GitHub Desktop.
Rust echo-request WebAssembly demo application before and after Rust bindings (luw_) wrapper (uwr_)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* SPDX-License-Identifier: Apache-2.0 */ | |
/* | |
* Copyright (C) Andrew Clayton | |
* Copyright (C) Timo Stark | |
* Copyright (C) F5, Inc. | |
*/ | |
// Include RAW FFI Bindings. | |
// @todo: Replace this with the new native Rust API | |
use unit_wasm::ffi::*; | |
use std::ffi::CStr; | |
use std::os::raw::c_char; | |
use std::os::raw::c_void; | |
use std::ptr; | |
// Buffer of some size to store the copy of the request | |
static mut REQUEST_BUF: *mut u8 = ptr::null_mut(); | |
#[no_mangle] | |
pub extern "C" fn luw_module_end_handler() { | |
unsafe { | |
luw_free(REQUEST_BUF as *mut c_void); | |
} | |
} | |
#[no_mangle] | |
pub extern "C" fn luw_module_init_handler() { | |
unsafe { | |
REQUEST_BUF = luw_malloc(luw_mem_get_init_size().try_into().unwrap()) | |
as *mut u8; | |
} | |
} | |
pub extern "C" fn hdr_iter_func( | |
ctx: *mut luw_ctx_t, | |
name: *const c_char, | |
value: *const c_char, | |
_data: *mut c_void, | |
) -> bool { | |
unsafe { | |
luw_mem_writep( | |
ctx, | |
"%s = %s\n\0".as_ptr() as *const c_char, | |
name, | |
value, | |
); | |
} | |
return true; | |
} | |
#[no_mangle] | |
pub extern "C" fn luw_request_handler(addr: *mut u8) -> i32 { | |
// Need a initalization | |
// | |
// It sucks that rust needs this, this is supposed to be | |
// an opaque structure and the structure is 0-initialised | |
// in luw_init_ctx(); | |
let mut ctx_: luw_ctx_t = luw_ctx_t { | |
addr: ptr::null_mut(), | |
mem: ptr::null_mut(), | |
req: ptr::null_mut(), | |
resp: ptr::null_mut(), | |
resp_hdr: ptr::null_mut(), | |
resp_offset: 0, | |
req_buf: ptr::null_mut(), | |
hdrp: ptr::null_mut(), | |
reqp: ptr::null_mut(), | |
}; | |
let ctx: *mut luw_ctx_t = &mut ctx_; | |
unsafe { | |
// Initialise the context structure. | |
// | |
// addr is the address of the previously allocated memory shared | |
// between the module and unit. | |
// | |
// The response data will be stored @ addr + offset (of 4096 bytes). | |
// This will leave some space for the response headers. | |
luw_init_ctx(ctx, addr, 4096); | |
// Allocate memory to store the request and copy the request data. | |
luw_set_req_buf(ctx, &mut REQUEST_BUF, luw_srb_flags_t_LUW_SRB_NONE); | |
// Define the Response Body Text. | |
luw_mem_writep( | |
ctx, | |
" * Welcome to WebAssembly in Rust on Unit! \ | |
[libunit-wasm (%d.%d.%d/%#0.8x)] \ | |
*\n\n\0" | |
.as_ptr() as *const c_char, | |
LUW_VERSION_MAJOR, | |
LUW_VERSION_MINOR, | |
LUW_VERSION_PATCH, | |
LUW_VERSION_NUMBER, | |
); | |
luw_mem_writep(ctx, "[Request Info]\n\0".as_ptr() as *const c_char); | |
luw_mem_writep( | |
ctx, | |
"REQUEST_PATH = %s\n\0".as_ptr() as *const c_char, | |
luw_get_http_path(ctx) as *const c_char, | |
); | |
luw_mem_writep( | |
ctx, | |
"METHOD = %s\n\0".as_ptr() as *const c_char, | |
luw_get_http_method(ctx) as *const c_char, | |
); | |
luw_mem_writep( | |
ctx, | |
"VERSION = %s\n\0".as_ptr() as *const c_char, | |
luw_get_http_version(ctx) as *const c_char, | |
); | |
luw_mem_writep( | |
ctx, | |
"QUERY = %s\n\0".as_ptr() as *const c_char, | |
luw_get_http_query(ctx) as *const c_char, | |
); | |
luw_mem_writep( | |
ctx, | |
"REMOTE = %s\n\0".as_ptr() as *const c_char, | |
luw_get_http_remote(ctx) as *const c_char, | |
); | |
luw_mem_writep( | |
ctx, | |
"LOCAL_ADDR = %s\n\0".as_ptr() as *const c_char, | |
luw_get_http_local_addr(ctx) as *const c_char, | |
); | |
luw_mem_writep( | |
ctx, | |
"LOCAL_PORT = %s\n\0".as_ptr() as *const c_char, | |
luw_get_http_local_port(ctx) as *const c_char, | |
); | |
luw_mem_writep( | |
ctx, | |
"SERVER_NAME = %s\n\0".as_ptr() as *const c_char, | |
luw_get_http_server_name(ctx) as *const c_char, | |
); | |
luw_mem_writep( | |
ctx, | |
"\n[Request Headers]\n\0".as_ptr() as *const c_char, | |
); | |
luw_http_hdr_iter(ctx, Some(hdr_iter_func), ptr::null_mut()); | |
let method = CStr::from_ptr(luw_get_http_method(ctx)).to_str().unwrap(); | |
if method == "POST" || method == "PUT" { | |
luw_mem_writep( | |
ctx, | |
"\n[%s data]\n\0".as_ptr() as *const c_char, | |
luw_get_http_method(ctx) as *const c_char, | |
); | |
luw_mem_writep_data( | |
ctx, | |
luw_get_http_content(ctx), | |
luw_get_http_content_len(ctx), | |
); | |
luw_mem_writep(ctx, "\n\0".as_ptr() as *const c_char); | |
} | |
let content_len = format!("{}\0", luw_get_response_data_size(ctx)); | |
// Init Response Headers | |
// | |
// Needs the context, number of headers about to add as well as | |
// the offset where to store the headers. In this case we are | |
// storing the response headers at the beginning of our shared | |
// memory at offset 0. | |
luw_http_init_headers(ctx, 2, 0); | |
luw_http_add_header( | |
ctx, | |
0, | |
"Content-Type\0".as_ptr() as *const c_char, | |
"text/plain\0".as_ptr() as *const c_char, | |
); | |
luw_http_add_header( | |
ctx, | |
1, | |
"Content-Length\0".as_ptr() as *const c_char, | |
content_len.as_ptr() as *const c_char, | |
); | |
// This calls nxt_wasm_send_headers() in Unit | |
luw_http_send_headers(ctx); | |
// This calls nxt_wasm_send_response() in Unit | |
luw_http_send_response(ctx); | |
// This calls nxt_wasm_response_end() in Unit | |
luw_http_response_end(); | |
} | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* SPDX-License-Identifier: Apache-2.0 */ | |
/* | |
* Copyright (C) Andrew Clayton | |
* Copyright (C) Timo Stark | |
* Copyright (C) F5, Inc. | |
*/ | |
// Include RAW FFI Bindings. | |
// @todo: Replace this with the new native Rust API | |
use unit_wasm::ffi::*; | |
use std::ffi::CStr; | |
use std::os::raw::c_char; | |
use std::os::raw::c_void; | |
use std::ptr::null_mut; | |
// Buffer of some size to store the copy of the request | |
static mut REQUEST_BUF: *mut u8 = null_mut(); | |
#[no_mangle] | |
pub extern "C" fn luw_module_end_handler() { | |
unsafe { | |
uwr_free(REQUEST_BUF); | |
} | |
} | |
#[no_mangle] | |
pub extern "C" fn luw_module_init_handler() { | |
unsafe { | |
REQUEST_BUF = uwr_malloc(uwr_mem_get_init_size()); | |
} | |
} | |
pub extern "C" fn hdr_iter_func( | |
ctx: *mut luw_ctx_t, | |
name: *const c_char, | |
value: *const c_char, | |
_data: *mut c_void, | |
) -> bool { | |
uwr_write_str!(ctx, "{} = {}\n", C2S!(name), C2S!(value)); | |
return true; | |
} | |
#[no_mangle] | |
pub extern "C" fn luw_request_handler(addr: *mut u8) -> i32 { | |
// Declare a 0-initialised context structure | |
let ctx = &mut UWR_CTX_INITIALIZER(); | |
// Initialise the context structure. | |
// | |
// addr is the address of the previously allocated memory shared | |
// between the module and unit. | |
// | |
// The response data will be stored @ addr + offset (of 4096 bytes). | |
// This will leave some space for the response headers. | |
uwr_init_ctx(ctx, addr, 4096); | |
// Set where we will copy the request into | |
unsafe { | |
uwr_set_req_buf(ctx, &mut REQUEST_BUF, LuwSrbFlags::LUW_SRB_NONE); | |
} | |
// Define the Response Body Text. | |
uwr_write_str!( | |
ctx, | |
" * Welcome to WebAssembly in Rust on Unit! \ | |
[libunit-wasm ({}.{}.{}/{:#010x})] *\n\n", | |
LUW_VERSION_MAJOR, | |
LUW_VERSION_MINOR, | |
LUW_VERSION_PATCH, | |
LUW_VERSION_NUMBER, | |
); | |
uwr_write_str!(ctx, "[Request Info]\n"); | |
uwr_write_str!(ctx, "REQUEST_PATH = {}\n", uwr_get_http_path(ctx)); | |
uwr_write_str!(ctx, "METHOD = {}\n", uwr_get_http_method(ctx)); | |
uwr_write_str!(ctx, "VERSION = {}\n", uwr_get_http_version(ctx)); | |
uwr_write_str!(ctx, "QUERY = {}\n", uwr_get_http_query(ctx)); | |
uwr_write_str!(ctx, "REMOTE = {}\n", uwr_get_http_remote(ctx)); | |
uwr_write_str!(ctx, "LOCAL_ADDR = {}\n", uwr_get_http_local_addr(ctx)); | |
uwr_write_str!(ctx, "LOCAL_PORT = {}\n", uwr_get_http_local_port(ctx)); | |
uwr_write_str!(ctx, "SERVER_NAME = {}\n", uwr_get_http_server_name(ctx)); | |
uwr_write_str!(ctx, "\n[Request Headers]\n"); | |
uwr_http_hdr_iter(ctx, Some(hdr_iter_func), null_mut()); | |
let method = uwr_get_http_method(ctx); | |
if method == "POST" || method == "PUT" { | |
uwr_write_str!(ctx, "\n[{} data]\n", method); | |
uwr_mem_write_buf( | |
ctx, | |
uwr_get_http_content(ctx), | |
uwr_get_http_content_len(ctx), | |
); | |
uwr_write_str!(ctx, "\n"); | |
} | |
// Init Response Headers | |
// | |
// Needs the context, number of headers about to add as well as | |
// the offset where to store the headers. In this case we are | |
// storing the response headers at the beginning of our shared | |
// memory at offset 0. | |
uwr_http_init_headers(ctx, 2, 0); | |
uwr_http_add_header(ctx, 0, "Content-Type", "text/plain"); | |
uwr_http_add_header( | |
ctx, | |
1, | |
"Content-Length", | |
&format!("{}", uwr_get_response_data_size(ctx)), | |
); | |
// This calls nxt_wasm_send_headers() in Unit | |
uwr_http_send_headers(ctx); | |
// This calls nxt_wasm_send_response() in Unit | |
uwr_http_send_response(ctx); | |
// This calls nxt_wasm_response_end() in Unit | |
uwr_http_response_end(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Changes include :-