diff --git a/Cargo.lock b/Cargo.lock index ece7020..e017705 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -142,6 +142,18 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "fallible-streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" + [[package]] name = "filetime" version = "0.2.26" @@ -170,6 +182,12 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "form_urlencoded" version = "1.2.2" @@ -196,6 +214,24 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hashlink" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" +dependencies = [ + "hashbrown", +] + [[package]] name = "home" version = "0.5.12" @@ -346,6 +382,16 @@ dependencies = [ "redox_syscall", ] +[[package]] +name = "libsqlite3-sys" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "133c182a6a2c87864fe97778797e46c7e999672690dc9fa3ee8e241aa4a9c13f" +dependencies = [ + "pkg-config", + "vcpkg", +] + [[package]] name = "linux-raw-sys" version = "0.4.15" @@ -411,6 +457,7 @@ name = "nginx-test" version = "0.1.0" dependencies = [ "ngx", + "rusqlite", ] [[package]] @@ -460,6 +507,12 @@ version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + [[package]] name = "potential_utf" version = "0.1.4" @@ -549,6 +602,20 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rusqlite" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "165ca6e57b20e1351573e3729b958bc62f0e48025386970b6e4d29e7a7e71f3f" +dependencies = [ + "bitflags 2.10.0", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libsqlite3-sys", + "smallvec", +] + [[package]] name = "rustc-hash" version = "1.1.0" @@ -806,6 +873,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" diff --git a/Cargo.toml b/Cargo.toml index e6c7012..a2b2c7c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,3 +8,4 @@ crate-type = ["cdylib"] [dependencies] ngx = "0.4.1" +rusqlite = "0.37.0" \ No newline at end of file diff --git a/conf/howto.conf b/conf/howto.conf index 8ec2481..fd663ad 100644 --- a/conf/howto.conf +++ b/conf/howto.conf @@ -1,12 +1,12 @@ # Add the path to your library here. -load_module %PATH_TO_LIB%; +load_module target/debug/libnginx_test.so; worker_processes 1; events {} #Uncomment and add a log file path if desired -#error_log %PATH_TO_LOG% debug; +error_log logs/error.log debug; http { server { diff --git a/default.nix b/default.nix index 39bacff..7fbeed2 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,8 @@ (import ( - fetchTarball { - url = "https://github.com/edolstra/flake-compat/archive/99f1c2157fba4bfe6211a321fd0ee43199025dbf.tar.gz"; - sha256 = "0x2jn3vrawwv9xp15674wjz9pixwjyj3j771izayl962zziivbx2"; } -) { - src = ./.; -}).defaultNix + fetchTarball { + url = "https://github.com/edolstra/flake-compat/archive/99f1c2157fba4bfe6211a321fd0ee43199025dbf.tar.gz"; + sha256 = "0x2jn3vrawwv9xp15674wjz9pixwjyj3j771izayl962zziivbx2"; + } + ) { + src = ./.; + }).defaultNix diff --git a/flake.nix b/flake.nix index 48a2855..9f95309 100644 --- a/flake.nix +++ b/flake.nix @@ -5,18 +5,40 @@ utils.url = "github:numtide/flake-utils"; }; - outputs = { self, nixpkgs, utils, naersk }: - utils.lib.eachDefaultSystem (system: - let - pkgs = import nixpkgs { inherit system; }; - naersk-lib = pkgs.callPackage naersk { }; - in - { + outputs = { + self, + nixpkgs, + utils, + naersk, + }: + utils.lib.eachDefaultSystem ( + system: let + pkgs = import nixpkgs {inherit system;}; + naersk-lib = pkgs.callPackage naersk {}; + in { defaultPackage = naersk-lib.buildPackage ./.; - devShell = with pkgs; mkShell { - buildInputs = [ cargo rustc rustfmt pre-commit rustPackages.clippy gnumake openssl.dev pkg-config nginx ]; - RUST_SRC_PATH = rustPlatform.rustLibSrc; - }; + devShell = with pkgs; + (mkShell.override {stdenv = pkgs.clangStdenv;}) { + buildInputs = [ + cargo + gnumake + libxcrypt + nginx + openssl.dev + pcre.dev + pkg-config + pkgs.llvmPackages.libclang.lib + rust-analyzer + rustPackages.clippy + rustc + rustfmt + sqlite + zlib.dev + ]; + + LIBCLANG_PATH = "${pkgs.llvmPackages.libclang.lib}/lib"; + RUST_SRC_PATH = rustPlatform.rustLibSrc; + }; } ); } diff --git a/shell.nix b/shell.nix index 77db547..13ba5ce 100644 --- a/shell.nix +++ b/shell.nix @@ -1,7 +1,8 @@ (import ( - fetchTarball { - url = "https://github.com/edolstra/flake-compat/archive/99f1c2157fba4bfe6211a321fd0ee43199025dbf.tar.gz"; - sha256 = "0x2jn3vrawwv9xp15674wjz9pixwjyj3j771izayl962zziivbx2"; } -) { - src = ./.; -}).shellNix + fetchTarball { + url = "https://github.com/edolstra/flake-compat/archive/99f1c2157fba4bfe6211a321fd0ee43199025dbf.tar.gz"; + sha256 = "0x2jn3vrawwv9xp15674wjz9pixwjyj3j771izayl962zziivbx2"; + } + ) { + src = ./.; + }).shellNix diff --git a/src/lib.rs b/src/lib.rs index bababe4..ac44d37 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,14 +1,15 @@ +use std::fmt::{Display, Formatter}; +use std::fmt; +use ngx::core::Buffer; use ngx::ffi::{ - nginx_version, ngx_array_push, ngx_command_t, ngx_conf_t, ngx_http_core_module, - ngx_http_handler_pt, ngx_http_module_t, ngx_http_phases_NGX_HTTP_ACCESS_PHASE, - ngx_http_request_t, ngx_int_t, ngx_module_t, ngx_str_t, ngx_uint_t, NGX_CONF_TAKE1, - NGX_HTTP_LOC_CONF, NGX_HTTP_MODULE, NGX_RS_HTTP_LOC_CONF_OFFSET, NGX_RS_MODULE_SIGNATURE, + NGX_CONF_TAKE1, NGX_HTTP_LOC_CONF, NGX_HTTP_MODULE, NGX_RS_HTTP_LOC_CONF_OFFSET, NGX_RS_MODULE_SIGNATURE, nginx_version, ngx_array_push, ngx_buf_t, ngx_chain_t, ngx_command_t, ngx_conf_t, ngx_http_core_module, ngx_http_discard_request_body, ngx_http_handler_pt, ngx_http_module_t, ngx_http_phases_NGX_HTTP_ACCESS_PHASE, ngx_http_request_t, ngx_int_t, ngx_module_t, ngx_str_t, ngx_uint_t }; use ngx::http::{HTTPModule, MergeConfigError}; use ngx::{core, core::Status, http}; use ngx::{http_request_handler, ngx_log_debug_http, ngx_modules, ngx_null_command, ngx_string}; use std::os::raw::{c_char, c_void}; use std::ptr::addr_of; +use rusqlite::{Connection, Result}; struct Module; @@ -66,7 +67,7 @@ impl http::Merge for ModuleConfig { // Create our "C" module context with function entrypoints for NGINX event loop. This "binds" our // HTTPModule implementation to functions callable from C. -#[no_mangle] +#[unsafe(no_mangle)] static ngx_http_howto_module_ctx: ngx_http_module_t = ngx_http_module_t { preconfiguration: Some(Module::preconfiguration), postconfiguration: Some(Module::postconfiguration), @@ -83,7 +84,7 @@ static ngx_http_howto_module_ctx: ngx_http_module_t = ngx_http_module_t { // this structure and setting our custom configuration command (defined below). ngx_modules!(ngx_http_howto_module); -#[no_mangle] +#[unsafe(no_mangle)] pub static mut ngx_http_howto_module: ngx_module_t = ngx_module_t { ctx_index: ngx_uint_t::max_value(), index: ngx_uint_t::max_value(), @@ -117,7 +118,7 @@ pub static mut ngx_http_howto_module: ngx_module_t = ngx_module_t { // Register and allocate our command structures for directive generation and eventual storage. Be // sure to terminate the array with the ngx_null_command! macro. -#[no_mangle] +#[unsafe(no_mangle)] static mut ngx_http_howto_commands: [ngx_command_t; 2] = [ ngx_command_t { name: ngx_string!("howto"), @@ -130,7 +131,7 @@ static mut ngx_http_howto_commands: [ngx_command_t; 2] = [ ngx_null_command!(), ]; -#[no_mangle] +#[unsafe(no_mangle)] extern "C" fn ngx_http_howto_commands_set_method( cf: *mut ngx_conf_t, _cmd: *mut ngx_command_t, @@ -146,25 +147,97 @@ extern "C" fn ngx_http_howto_commands_set_method( std::ptr::null_mut() } +#[derive(Debug)] +struct Person { + id: u64, + name: String, + address: String +} + +impl Display for Person { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "Person ({}, {}, {})", self.id, self.name, self.address) + } +} + +fn get_person() -> Result> { + let conn = Connection::open("db.sqlite3")?; + let mut stmt = conn.prepare("SELECT id, name, address FROM person")?; + + let person_iter = stmt.query_map([], |row| { + Ok(Person { + id: row.get(0)?, + name: row.get(1)?, + address: row.get(2)?, + }) + })?; + + person_iter.collect() +} + // Implement a request handler. Use the convenience macro, the http_request_handler! macro will // convert the native NGINX request into a Rust Request instance as well as define an extern C // function callable from NGINX. // // The function body is implemented as a Rust closure. http_request_handler!(howto_access_handler, |request: &mut http::Request| { + let m_persons = get_person(); + let co = unsafe { request.get_module_loc_conf::(&*addr_of!(ngx_http_howto_module)) }; let co = co.expect("module config is none"); ngx_log_debug_http!(request, "howto module enabled called"); + + request.discard_request_body(); + + request.set_status(http::HTTPStatus::OK); + + //request.set_content_length_n(buf.len()); + let rc = request.send_header(); + if rc == core::Status::NGX_ERROR || rc > core::Status::NGX_OK || request.header_only() { + return rc; + } + + match co.enabled { true => { - let method = request.method(); + match m_persons { + Ok(persons) => { + for person in persons { + ngx_log_debug_http!(request, "person: {}\n", person); - if method.as_str() == co.method { - return core::Status::NGX_OK; + let s = fmt::format(format_args!("{}", person)); + let mut buf = match request.pool().create_buffer_from_str(s) { + Some(buf) => buf, + None => return http::HTTPStatus::INTERNAL_SERVER_ERROR.into(), + }; + + buf.set_last_buf(request.is_main()); + buf.set_last_in_chain(true); + + let mut out = ngx_chain_t { + buf: buf.as_ngx_buf_mut(), + next: std::ptr::null_mut(), + }; + request.output_filter(&mut out); + } + }, + Err(e) => { + //todo!(); + ngx_log_debug_http!(request, "failed to find persons: {}", e); + + return http::HTTPStatus::INTERNAL_SERVER_ERROR.into() + } } - http::HTTPStatus::FORBIDDEN.into() + + + // let method = request.method(); + + // if method.as_str() == co.method { + // return core::Status::NGX_OK; + // } + Status::NGX_DONE } false => core::Status::NGX_OK, }