diff --git a/3p/wl.h b/3p/wl.h index 0db07d8..b15b7d6 100644 --- a/3p/wl.h +++ b/3p/wl.h @@ -87,4 +87,4 @@ void wl_push_array (WL_Runtime *rt, int cap); void wl_push_map (WL_Runtime *rt, int cap); void wl_push_arg (WL_Runtime *rt, int idx); void wl_insert (WL_Runtime *rt); -void wl_append (WL_Runtime *rt); +void wl_append (WL_Runtime *rt); \ No newline at end of file diff --git a/cweb.h b/cweb.h index c158595..ccfc756 100644 --- a/cweb.h +++ b/cweb.h @@ -1,8 +1,8 @@ /* -Copyright © 2025 Francesco Cozzuto +Copyright � 2025 Francesco Cozzuto Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the “Software”), +copy of this software and associated documentation files (the �Software�), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the @@ -11,7 +11,7 @@ Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS +THE SOFTWARE IS PROVIDED �AS IS�, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR @@ -26,14 +26,14 @@ OTHER DEALINGS IN THE SOFTWARE. // src/main.h //////////////////////////////////////////////////////////////////////////////////////// -#line 1 "src/main.h" +//#line 1 "src/main.h" #include #include #define CWEB_ENABLE_DATABASE #define CWEB_ENABLE_TEMPLATE -#define CWEB_STR(X) (CWEB_String) { (X), (int) sizeof(X)-1 } +#define CWEB_STR(X) ((CWEB_String) { (X), (int) sizeof(X)-1 }) typedef struct { char *ptr; @@ -258,6 +258,9 @@ int cweb_enable_database(CWEB *cweb, CWEB_String database_file, CWEB_String sche // Log all evaluated SQL statements to stdout void cweb_trace_sql(CWEB *cweb, bool enable); +// TODO: comment +void cweb_enable_template_cache(CWEB *cweb, bool enable); + // Pause execution until a request is available. // TODO: When does this function return NULL? CWEB_Request *cweb_wait(CWEB *cweb); @@ -275,6 +278,9 @@ int cweb_get_user_id(CWEB_Request *req); // If the ID is -1, the session is deleted. int cweb_set_user_id(CWEB_Request *req, int user_id); +// TODO: comment +CWEB_String cweb_get_path(CWEB_Request *req); + // Returns the request parameter with the specified name // If the request uses POST, the parameter is taken from the body, // else it's taken from the URL. If the parameter is not present, @@ -299,13 +305,18 @@ void cweb_respond_basic(CWEB_Request *req, int status, CWEB_String content); void cweb_respond_redirect(CWEB_Request *req, CWEB_String target); // Responds to the request by evaluating a WL template file -void cweb_respond_template(CWEB_Request *req, int status, CWEB_String template_file, int resource_id); +void cweb_respond_template_impl(CWEB_Request *req, int status, CWEB_String template_file, CWEB_VArgs args); + +// Helper +#define cweb_respond_template(req, status, template_file, ...) \ + cweb_respond_template_impl((req), (status), (template_file), CWEB_VARGS(__VA_ARGS__)) // Evaluates an SQL INSERT statement and returns the ID of the last inserted row. On error -1 is returned int64_t cweb_database_insert_impl(CWEB *cweb, char *fmt, CWEB_VArgs args); // Helper -#define cweb_database_insert(cweb, fmt, ...) cweb_database_insert_impl((cweb), (fmt), CWEB_VARGS(__VA_ARGS__)) +#define cweb_database_insert(cweb, fmt, ...) \ + cweb_database_insert_impl((cweb), (fmt), CWEB_VARGS(__VA_ARGS__)) // Iterator over database rows typedef struct { void *handle; } CWEB_QueryResult; @@ -347,7 +358,7 @@ int cweb_check_password(CWEB_String pass, CWEB_PasswordHash hash); // 3p/chttp.h //////////////////////////////////////////////////////////////////////////////////////// -#line 1 "3p/chttp.h" +//#line 1 "3p/chttp.h" #ifndef HTTP_AMALGAMATION #define HTTP_AMALGAMATION @@ -357,7 +368,7 @@ int cweb_check_password(CWEB_String pass, CWEB_PasswordHash hash); // src/basic.h //////////////////////////////////////////////////////////////////////////////////////// -#line 1 "src/basic.h" +//#line 1 "src/basic.h" #ifndef CHTTP_BASIC_INCLUDED #define CHTTP_BASIC_INCLUDED @@ -444,7 +455,7 @@ void print_bytes(HTTP_String prefix, HTTP_String src); // src/parse.h //////////////////////////////////////////////////////////////////////////////////////// -#line 1 "src/parse.h" +//#line 1 "src/parse.h" #ifndef PARSE_INCLUDED #define PARSE_INCLUDED @@ -550,7 +561,7 @@ int http_get_param_i (HTTP_String body, HTTP_String str); // src/engine.h //////////////////////////////////////////////////////////////////////////////////////// -#line 1 "src/engine.h" +//#line 1 "src/engine.h" #ifndef HTTP_ENGINE_INCLUDED #define HTTP_ENGINE_INCLUDED @@ -678,7 +689,7 @@ void http_engine_undo (HTTP_Engine *eng); // src/cert.h //////////////////////////////////////////////////////////////////////////////////////// -#line 1 "src/cert.h" +//#line 1 "src/cert.h" #ifndef CERT_INCLUDED #define CERT_INCLUDED @@ -709,7 +720,7 @@ int http_create_test_certificate(HTTP_String C, HTTP_String O, HTTP_String CN, // src/client.h //////////////////////////////////////////////////////////////////////////////////////// -#line 1 "src/client.h" +//#line 1 "src/client.h" #ifndef CLIENT_INCLUDED #define CLIENT_INCLUDED @@ -813,7 +824,7 @@ HTTP_Response *http_post(HTTP_String url, // src/server.h //////////////////////////////////////////////////////////////////////////////////////// -#line 1 "src/server.h" +//#line 1 "src/server.h" #ifndef HTTP_SERVER_INCLUDED #define HTTP_SERVER_INCLUDED @@ -854,7 +865,7 @@ void http_response_builder_done (HTTP_ResponseBuilder res); // src/router.h //////////////////////////////////////////////////////////////////////////////////////// -#line 1 "src/router.h" +//#line 1 "src/router.h" #ifndef HTTP_ROUTER_INCLUDED #define HTTP_ROUTER_INCLUDED @@ -879,7 +890,7 @@ int http_serve (char *addr, int port, HTTP_Router *router); // 3p/chttp.c //////////////////////////////////////////////////////////////////////////////////////// -#line 1 "3p/chttp.c" +//#line 1 "3p/chttp.c" #ifndef HTTP_NOINCLUDE #include "chttp.h" #endif @@ -888,7 +899,7 @@ int http_serve (char *addr, int port, HTTP_Router *router); // src/sec.h //////////////////////////////////////////////////////////////////////////////////////// -#line 1 "src/sec.h" +//#line 1 "src/sec.h" #ifndef SEC_INCLUDED #define SEC_INCLUDED @@ -949,7 +960,7 @@ void secure_context_free(SecureContext *sec); // src/socket_raw.h //////////////////////////////////////////////////////////////////////////////////////// -#line 1 "src/socket_raw.h" +//#line 1 "src/socket_raw.h" #ifndef SOCKET_RAW_INCLUDED #define SOCKET_RAW_INCLUDED @@ -990,7 +1001,7 @@ RAW_SOCKET listen_socket(HTTP_String addr, uint16_t port, bool reuse_addr, int b // src/socket.h //////////////////////////////////////////////////////////////////////////////////////// -#line 1 "src/socket.h" +//#line 1 "src/socket.h" #ifndef SOCKET_INCLUDED #define SOCKET_INCLUDED @@ -1071,7 +1082,7 @@ void* socket_get_user_data(Socket *sock); // src/socket_pool.h //////////////////////////////////////////////////////////////////////////////////////// -#line 1 "src/socket_pool.h" +//#line 1 "src/socket_pool.h" #ifndef SOCKET_POOL_INCLUDED #define SOCKET_POOL_INCLUDED @@ -1137,7 +1148,7 @@ bool socket_pool_secure(SocketPool *pool, SocketHandle handle); // src/basic.c //////////////////////////////////////////////////////////////////////////////////////// -#line 1 "src/basic.c" +//#line 1 "src/basic.c" #include #include @@ -1246,7 +1257,7 @@ void print_bytes(HTTP_String prefix, HTTP_String src) // src/parse.c //////////////////////////////////////////////////////////////////////////////////////// -#line 1 "src/parse.c" +//#line 1 "src/parse.c" #include #include #include @@ -2553,7 +2564,7 @@ int http_get_param_i(HTTP_String body, HTTP_String str) // src/engine.c //////////////////////////////////////////////////////////////////////////////////////// -#line 1 "src/engine.c" +//#line 1 "src/engine.c" #include #include #include @@ -3547,7 +3558,7 @@ void http_engine_undo(HTTP_Engine *eng) // src/cert.c //////////////////////////////////////////////////////////////////////////////////////// -#line 1 "src/cert.c" +//#line 1 "src/cert.c" #include #include #include @@ -3722,7 +3733,7 @@ int http_create_test_certificate(HTTP_String C, HTTP_String O, HTTP_String CN, // src/sec.c //////////////////////////////////////////////////////////////////////////////////////// -#line 1 "src/sec.c" +//#line 1 "src/sec.c" #ifndef HTTP_AMALGAMATION #include "sec.h" #endif @@ -3948,7 +3959,7 @@ int secure_context_add_cert(SecureContext *sec, // src/socket_raw.c //////////////////////////////////////////////////////////////////////////////////////// -#line 1 "src/socket_raw.c" +//#line 1 "src/socket_raw.c" #include #ifdef _WIN32 @@ -4060,7 +4071,7 @@ RAW_SOCKET listen_socket(HTTP_String addr, uint16_t port, bool reuse_addr, int b // src/socket.c //////////////////////////////////////////////////////////////////////////////////////// -#line 1 "src/socket.c" +//#line 1 "src/socket.c" #include // snprintf #include #include @@ -4856,7 +4867,7 @@ void *socket_get_user_data(Socket *sock) // src/socket_pool.c //////////////////////////////////////////////////////////////////////////////////////// -#line 1 "src/socket_pool.c" +//#line 1 "src/socket_pool.c" #include #include @@ -5219,7 +5230,7 @@ bool socket_pool_secure(SocketPool *pool, SocketHandle handle) // src/client.c //////////////////////////////////////////////////////////////////////////////////////// -#line 1 "src/client.c" +//#line 1 "src/client.c" #include #include #include @@ -5678,7 +5689,7 @@ HTTP_Response *http_post(HTTP_String url, HTTP_String *headers, int num_headers, // src/server.c //////////////////////////////////////////////////////////////////////////////////////// -#line 1 "src/server.c" +//#line 1 "src/server.c" #include #include #include @@ -5991,7 +6002,7 @@ void http_response_builder_done(HTTP_ResponseBuilder res) // src/router.c //////////////////////////////////////////////////////////////////////////////////////// -#line 1 "src/router.c" +//#line 1 "src/router.c" #include #include #include @@ -6458,7 +6469,7 @@ int http_serve(char *addr, int port, HTTP_Router *router) // 3p/wl.h //////////////////////////////////////////////////////////////////////////////////////// -#line 1 "3p/wl.h" +//#line 1 "3p/wl.h" #include #include @@ -6554,7 +6565,7 @@ void wl_append (WL_Runtime *rt); // 3p/wl.c //////////////////////////////////////////////////////////////////////////////////////// -#line 1 "3p/wl.c" +//#line 1 "3p/wl.c" #include #include #include @@ -12437,7 +12448,7 @@ void wl_runtime_dump(WL_Runtime *rt) // 3p/crypt_blowfish.h //////////////////////////////////////////////////////////////////////////////////////// -#line 1 "3p/crypt_blowfish.h" +//#line 1 "3p/crypt_blowfish.h" /* * Written by Solar Designer in 2000-2011. * No copyright is claimed, and the software is hereby placed in the public @@ -12470,7 +12481,7 @@ extern char *_crypt_gensalt_blowfish_rn(const char *prefix, // 3p/crypt_blowfish.c //////////////////////////////////////////////////////////////////////////////////////// -#line 1 "3p/crypt_blowfish.c" +//#line 1 "3p/crypt_blowfish.c" /* * The crypt_blowfish homepage is: * @@ -13385,7 +13396,7 @@ char *_crypt_gensalt_blowfish_rn(const char *prefix, unsigned long count, // src/main.c //////////////////////////////////////////////////////////////////////////////////////// -#line 1 "src/main.c" +//#line 1 "src/main.c" #include #include #include @@ -13489,6 +13500,7 @@ struct CWEB { #ifdef CWEB_ENABLE_TEMPLATE TemplateCache *tpcache; + bool enable_template_cache; #endif bool allow_insecure_login; @@ -14334,6 +14346,7 @@ CWEB *cweb_init(CWEB_String addr, uint16_t port) free(cweb); return NULL; } + cweb->enable_template_cache = true; #endif cweb->session_storage = session_storage_init(1024); @@ -14401,6 +14414,11 @@ void cweb_trace_sql(CWEB *cweb, bool enable) #endif } +void cweb_enable_template_cache(CWEB *cweb, bool enable) +{ + cweb->enable_template_cache = enable; +} + int cweb_enable_database(CWEB *cweb, CWEB_String database_file, CWEB_String schema_file) { #ifdef CWEB_ENABLE_DATABASE @@ -14478,6 +14496,12 @@ bool cweb_match_endpoint(CWEB_Request *req, CWEB_String str) return http_streq(req->req->url.path, (HTTP_String) { str.ptr, str.len }); } +CWEB_String cweb_get_path(CWEB_Request *req) +{ + HTTP_String path = req->req->url.path; + return (CWEB_String) { path.ptr, path.len }; +} + CWEB_String cweb_get_param_s(CWEB_Request *req, CWEB_String name) { HTTP_String src = req->req->url.query; @@ -14843,47 +14867,18 @@ static int query_routine(WL_Runtime *rt, SQLiteCache *dbcache) return 0; } -static void push_sysvar(WL_Runtime *rt, WL_String name, SQLiteCache *dbcache, CWEB_String csrf, int user_id, int resource_id) -{ - (void) dbcache; - - if (wl_streq(name, "login_user_id", -1)) { - - if (user_id < 0) - wl_push_none(rt); - else - wl_push_s64(rt, user_id); - - } else if (wl_streq(name, "resource_id", -1)) { - - if (resource_id < 0) - wl_push_none(rt); - else - wl_push_s64(rt, resource_id); - - } else if (wl_streq(name, "csrf", -1)) { - - if (csrf.len == 0) - wl_push_none(rt); - else - wl_push_str(rt, (WL_String) { csrf.ptr, csrf.len }); - } -} - -static void push_syscall(WL_Runtime *rt, WL_String name, SQLiteCache *dbcache) -{ - if (wl_streq(name, "query", -1)) { - query_routine(rt, dbcache); - return; - } -} - -static int get_or_create_program(TemplateCache *cache, WL_String path, WL_Arena *arena, WL_Program *program) +static int get_or_create_program(TemplateCache *cache, WL_String path, bool force_create, WL_Arena *arena, WL_Program *program) { if (cache == NULL) return -1; int i = template_cache_lookup(cache, path); + + if (cache->pool[i].pathlen != -1 && force_create) { + cache->pool[i].pathlen = -1; + free(cache->pool[i].program.ptr); + } + if (cache->pool[i].pathlen == -1) { WL_Program program; @@ -14909,7 +14904,7 @@ static int get_or_create_program(TemplateCache *cache, WL_String path, WL_Arena } #endif -void cweb_respond_template(CWEB_Request *req, int status, CWEB_String template_file, int resource_id) +void cweb_respond_template_impl(CWEB_Request *req, int status, CWEB_String template_file, CWEB_VArgs args) { #ifdef CWEB_ENABLE_TEMPLATE http_response_builder_status(req->builder, status); @@ -14922,7 +14917,7 @@ void cweb_respond_template(CWEB_Request *req, int status, CWEB_String template_f } WL_Program program; - ret = get_or_create_program(req->cweb->tpcache, (WL_String) { template_file.ptr, template_file.len }, &req->arena, &program); + ret = get_or_create_program(req->cweb->tpcache, (WL_String) { template_file.ptr, template_file.len }, !req->cweb->enable_template_cache, &req->arena, &program); if (ret < 0) { http_response_builder_undo(req->builder); http_response_builder_status(req->builder, 500); @@ -14958,11 +14953,65 @@ void cweb_respond_template(CWEB_Request *req, int status, CWEB_String template_f return; case WL_EVAL_SYSVAR: - push_sysvar(rt, result.str, req->cweb->dbcache, req->csrf, req->user_id, resource_id); + if (wl_streq(result.str, "login_user_id", -1)) { + + if (req->user_id < 0) + wl_push_none(rt); + else + wl_push_s64(rt, req->user_id); + + } else if (wl_streq(result.str, "csrf", -1)) { + + if (req->csrf.len == 0) + wl_push_none(rt); + else + wl_push_str(rt, (WL_String) { req->csrf.ptr, req->csrf.len }); + } break; case WL_EVAL_SYSCALL: - push_syscall(rt, result.str, req->cweb->dbcache); + if (wl_streq(result.str, "query", -1)) { + query_routine(rt, req->cweb->dbcache); + break; + } + if (wl_streq(result.str, "args", -1)) { + + if (wl_arg_count(rt) != 1) { + // TODO + break; + } + + int64_t idx; + if (!wl_arg_s64(rt, 0, &idx)) { + // TODO + break; + } + + if (idx < 0 || idx >= args.len) { + // TODO + break; + } + + CWEB_VArg arg = args.ptr[idx]; + switch (arg.type) { + case CWEB_VARG_TYPE_C : wl_push_s64(rt, arg.c); break; + case CWEB_VARG_TYPE_S : wl_push_s64(rt, arg.s); break; + case CWEB_VARG_TYPE_I : wl_push_s64(rt, arg.i); break; + case CWEB_VARG_TYPE_L : wl_push_s64(rt, arg.l); break; + case CWEB_VARG_TYPE_LL : wl_push_s64(rt, arg.ll); break; + case CWEB_VARG_TYPE_SC : wl_push_s64(rt, arg.sc); break; + case CWEB_VARG_TYPE_SS : wl_push_s64(rt, arg.ss); break; + case CWEB_VARG_TYPE_SI : wl_push_s64(rt, arg.si); break; + case CWEB_VARG_TYPE_SL : wl_push_s64(rt, arg.sl); break; + case CWEB_VARG_TYPE_SLL: wl_push_s64(rt, arg.sll); break; + case CWEB_VARG_TYPE_F : wl_push_f64(rt, arg.f); break; + case CWEB_VARG_TYPE_D : wl_push_s64(rt, arg.d); break; + case CWEB_VARG_TYPE_B : if (arg.b) wl_push_true(rt); else wl_push_false(rt); break; + case CWEB_VARG_TYPE_STR: wl_push_str(rt, (WL_String) { arg.str.ptr, arg.str.len }); break; + default:break; + } + break; + } break; case WL_EVAL_OUTPUT: diff --git a/src/main.c b/src/main.c index 0fa77d6..8e5edf1 100644 --- a/src/main.c +++ b/src/main.c @@ -101,6 +101,7 @@ struct CWEB { #ifdef CWEB_ENABLE_TEMPLATE TemplateCache *tpcache; + bool enable_template_cache; #endif bool allow_insecure_login; @@ -672,7 +673,7 @@ static int sqlite3utils_prepare(SQLiteCache *cache, sqlite3_stmt **pstmt, char * if (cache->items[i].stmt == NULL) { sqlite3_stmt *stmt; - int ret = sqlite3_prepare_v2(cache->db, fmt, -1, &stmt, NULL); + int ret = sqlite3_prepare_v2(cache->db, fmt, fmtlen, &stmt, NULL); if (ret != SQLITE_OK) { fprintf(stderr, "Failed to prepare statement: %s (%s:%d)\n", sqlite3_errmsg(cache->db), __FILE__, __LINE__); // TODO return ret; @@ -946,6 +947,7 @@ CWEB *cweb_init(CWEB_String addr, uint16_t port) free(cweb); return NULL; } + cweb->enable_template_cache = true; #endif cweb->session_storage = session_storage_init(1024); @@ -1013,6 +1015,11 @@ void cweb_trace_sql(CWEB *cweb, bool enable) #endif } +void cweb_enable_template_cache(CWEB *cweb, bool enable) +{ + cweb->enable_template_cache = enable; +} + int cweb_enable_database(CWEB *cweb, CWEB_String database_file, CWEB_String schema_file) { #ifdef CWEB_ENABLE_DATABASE @@ -1090,6 +1097,12 @@ bool cweb_match_endpoint(CWEB_Request *req, CWEB_String str) return http_streq(req->req->url.path, (HTTP_String) { str.ptr, str.len }); } +CWEB_String cweb_get_path(CWEB_Request *req) +{ + HTTP_String path = req->req->url.path; + return (CWEB_String) { path.ptr, path.len }; +} + CWEB_String cweb_get_param_s(CWEB_Request *req, CWEB_String name) { HTTP_String src = req->req->url.query; @@ -1455,47 +1468,18 @@ static int query_routine(WL_Runtime *rt, SQLiteCache *dbcache) return 0; } -static void push_sysvar(WL_Runtime *rt, WL_String name, SQLiteCache *dbcache, CWEB_String csrf, int user_id, int resource_id) -{ - (void) dbcache; - - if (wl_streq(name, "login_user_id", -1)) { - - if (user_id < 0) - wl_push_none(rt); - else - wl_push_s64(rt, user_id); - - } else if (wl_streq(name, "resource_id", -1)) { - - if (resource_id < 0) - wl_push_none(rt); - else - wl_push_s64(rt, resource_id); - - } else if (wl_streq(name, "csrf", -1)) { - - if (csrf.len == 0) - wl_push_none(rt); - else - wl_push_str(rt, (WL_String) { csrf.ptr, csrf.len }); - } -} - -static void push_syscall(WL_Runtime *rt, WL_String name, SQLiteCache *dbcache) -{ - if (wl_streq(name, "query", -1)) { - query_routine(rt, dbcache); - return; - } -} - -static int get_or_create_program(TemplateCache *cache, WL_String path, WL_Arena *arena, WL_Program *program) +static int get_or_create_program(TemplateCache *cache, WL_String path, bool force_create, WL_Arena *arena, WL_Program *program) { if (cache == NULL) return -1; int i = template_cache_lookup(cache, path); + + if (cache->pool[i].pathlen != -1 && force_create) { + cache->pool[i].pathlen = -1; + free(cache->pool[i].program.ptr); + } + if (cache->pool[i].pathlen == -1) { WL_Program program; @@ -1521,7 +1505,7 @@ static int get_or_create_program(TemplateCache *cache, WL_String path, WL_Arena } #endif -void cweb_respond_template(CWEB_Request *req, int status, CWEB_String template_file, int resource_id) +void cweb_respond_template_impl(CWEB_Request *req, int status, CWEB_String template_file, CWEB_VArgs args) { #ifdef CWEB_ENABLE_TEMPLATE http_response_builder_status(req->builder, status); @@ -1534,7 +1518,7 @@ void cweb_respond_template(CWEB_Request *req, int status, CWEB_String template_f } WL_Program program; - ret = get_or_create_program(req->cweb->tpcache, (WL_String) { template_file.ptr, template_file.len }, &req->arena, &program); + ret = get_or_create_program(req->cweb->tpcache, (WL_String) { template_file.ptr, template_file.len }, !req->cweb->enable_template_cache, &req->arena, &program); if (ret < 0) { http_response_builder_undo(req->builder); http_response_builder_status(req->builder, 500); @@ -1570,11 +1554,65 @@ void cweb_respond_template(CWEB_Request *req, int status, CWEB_String template_f return; case WL_EVAL_SYSVAR: - push_sysvar(rt, result.str, req->cweb->dbcache, req->csrf, req->user_id, resource_id); + if (wl_streq(result.str, "login_user_id", -1)) { + + if (req->user_id < 0) + wl_push_none(rt); + else + wl_push_s64(rt, req->user_id); + + } else if (wl_streq(result.str, "csrf", -1)) { + + if (req->csrf.len == 0) + wl_push_none(rt); + else + wl_push_str(rt, (WL_String) { req->csrf.ptr, req->csrf.len }); + } break; case WL_EVAL_SYSCALL: - push_syscall(rt, result.str, req->cweb->dbcache); + if (wl_streq(result.str, "query", -1)) { + query_routine(rt, req->cweb->dbcache); + break; + } + if (wl_streq(result.str, "args", -1)) { + + if (wl_arg_count(rt) != 1) { + // TODO + break; + } + + int64_t idx; + if (!wl_arg_s64(rt, 0, &idx)) { + // TODO + break; + } + + if (idx < 0 || idx >= args.len) { + // TODO + break; + } + + CWEB_VArg arg = args.ptr[idx]; + switch (arg.type) { + case CWEB_VARG_TYPE_C : wl_push_s64(rt, arg.c); break; + case CWEB_VARG_TYPE_S : wl_push_s64(rt, arg.s); break; + case CWEB_VARG_TYPE_I : wl_push_s64(rt, arg.i); break; + case CWEB_VARG_TYPE_L : wl_push_s64(rt, arg.l); break; + case CWEB_VARG_TYPE_LL : wl_push_s64(rt, arg.ll); break; + case CWEB_VARG_TYPE_SC : wl_push_s64(rt, arg.sc); break; + case CWEB_VARG_TYPE_SS : wl_push_s64(rt, arg.ss); break; + case CWEB_VARG_TYPE_SI : wl_push_s64(rt, arg.si); break; + case CWEB_VARG_TYPE_SL : wl_push_s64(rt, arg.sl); break; + case CWEB_VARG_TYPE_SLL: wl_push_s64(rt, arg.sll); break; + case CWEB_VARG_TYPE_F : wl_push_f64(rt, arg.f); break; + case CWEB_VARG_TYPE_D : wl_push_s64(rt, arg.d); break; + case CWEB_VARG_TYPE_B : if (arg.b) wl_push_true(rt); else wl_push_false(rt); break; + case CWEB_VARG_TYPE_STR: wl_push_str(rt, (WL_String) { arg.str.ptr, arg.str.len }); break; + default:break; + } + break; + } break; case WL_EVAL_OUTPUT: diff --git a/src/main.h b/src/main.h index ff1a2f3..60da087 100644 --- a/src/main.h +++ b/src/main.h @@ -4,7 +4,7 @@ #define CWEB_ENABLE_DATABASE #define CWEB_ENABLE_TEMPLATE -#define CWEB_STR(X) (CWEB_String) { (X), (int) sizeof(X)-1 } +#define CWEB_STR(X) ((CWEB_String) { (X), (int) sizeof(X)-1 }) typedef struct { char *ptr; @@ -229,6 +229,9 @@ int cweb_enable_database(CWEB *cweb, CWEB_String database_file, CWEB_String sche // Log all evaluated SQL statements to stdout void cweb_trace_sql(CWEB *cweb, bool enable); +// TODO: comment +void cweb_enable_template_cache(CWEB *cweb, bool enable); + // Pause execution until a request is available. // TODO: When does this function return NULL? CWEB_Request *cweb_wait(CWEB *cweb); @@ -246,6 +249,9 @@ int cweb_get_user_id(CWEB_Request *req); // If the ID is -1, the session is deleted. int cweb_set_user_id(CWEB_Request *req, int user_id); +// TODO: comment +CWEB_String cweb_get_path(CWEB_Request *req); + // Returns the request parameter with the specified name // If the request uses POST, the parameter is taken from the body, // else it's taken from the URL. If the parameter is not present, @@ -270,13 +276,18 @@ void cweb_respond_basic(CWEB_Request *req, int status, CWEB_String content); void cweb_respond_redirect(CWEB_Request *req, CWEB_String target); // Responds to the request by evaluating a WL template file -void cweb_respond_template(CWEB_Request *req, int status, CWEB_String template_file, int resource_id); +void cweb_respond_template_impl(CWEB_Request *req, int status, CWEB_String template_file, CWEB_VArgs args); + +// Helper +#define cweb_respond_template(req, status, template_file, ...) \ + cweb_respond_template_impl((req), (status), (template_file), CWEB_VARGS(__VA_ARGS__)) // Evaluates an SQL INSERT statement and returns the ID of the last inserted row. On error -1 is returned int64_t cweb_database_insert_impl(CWEB *cweb, char *fmt, CWEB_VArgs args); // Helper -#define cweb_database_insert(cweb, fmt, ...) cweb_database_insert_impl((cweb), (fmt), CWEB_VARGS(__VA_ARGS__)) +#define cweb_database_insert(cweb, fmt, ...) \ + cweb_database_insert_impl((cweb), (fmt), CWEB_VARGS(__VA_ARGS__)) // Iterator over database rows typedef struct { void *handle; } CWEB_QueryResult;