Add parameterized SQL queries with nginx variables

New Feature: sqlite_param Directive
- Allows passing nginx variables as SQL prepared statement parameters
- Supports query parameters ($arg_name), path captures ($1, $2), headers, etc.
- Safe SQL injection protection via rusqlite prepared statements
- Multiple parameters supported (bound in order to ? placeholders)

Implementation:
- New sqlite_param directive for adding query parameters
- Variable resolution using ngx_http_get_variable() FFI
- UTF-8 validation on all variable values
- Updated execute_query() to accept parameter array
- rusqlite::ToSql parameter binding

Examples:
- Book detail by ID: /book?id=1
- Genre filtering: /genre?genre=Programming
- Year range search: /years?min=2015&max=2024

New Files:
- conf/book_detail.conf: Parameter examples configuration
- server_root/book/detail.hbs: Book detail page template
- server_root/genre/genre.hbs: Genre filter page template
- start_book_detail.sh: Quick start script for params example
- README.md: Comprehensive project documentation
- README_PARAMETERS.md: Parameters feature documentation

Configuration:
- MainConfig now supports global_templates_dir
- ModuleConfig extended with query_params Vec
- Handler resolves variables at request time
- Template paths adjusted for exact location matches

All examples tested and working with both static and parameterized queries.
This commit is contained in:
Edward Langley
2025-11-15 15:09:43 -08:00
parent 9132d7485d
commit 7a169e34d5
9 changed files with 1263 additions and 10 deletions

58
conf/book_detail.conf Normal file
View File

@ -0,0 +1,58 @@
# Book Detail Configuration
# Demonstrates using path parameters with the SQLite module
load_module target/debug/libnginx_test.dylib;
worker_processes 1;
events {}
error_log logs/error.log debug;
http {
# Global templates for shared components
sqlite_global_templates "server_root/global_templates";
server {
listen 8081;
root "server_root";
# Book detail page using a path parameter (numbered capture)
# Captures the book ID from the URL and passes it to the SQL query
location = /book {
add_header "Content-Type" "text/html; charset=utf-8";
sqlite_db "book_catalog.db";
sqlite_query "SELECT * FROM books WHERE id = ?";
sqlite_param $arg_id;
sqlite_template "detail.hbs";
}
# Books by genre using query parameter
location = /genre {
add_header "Content-Type" "text/html; charset=utf-8";
sqlite_db "book_catalog.db";
sqlite_query "SELECT * FROM books WHERE genre = ? ORDER BY rating DESC";
sqlite_param $arg_genre;
sqlite_template "genre.hbs";
}
# Search by year range using query parameters
location = /years {
add_header "Content-Type" "text/html; charset=utf-8";
sqlite_db "book_catalog.db";
sqlite_query "SELECT * FROM books WHERE year >= ? AND year <= ? ORDER BY year DESC, title";
sqlite_param $arg_min;
sqlite_param $arg_max;
sqlite_template "list.hbs";
}
# Fallback to all books
location / {
add_header "Content-Type" "text/html; charset=utf-8";
sqlite_db "book_catalog.db";
sqlite_query "SELECT * FROM books ORDER BY rating DESC, title";
sqlite_template "list.hbs";
}
}
}