Bug fix
This commit is contained in:
@@ -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);
|
||||
@@ -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 <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#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 <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -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 <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
@@ -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 <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
@@ -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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -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 <string.h>
|
||||
|
||||
#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 <stdio.h> // snprintf
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
@@ -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 <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
@@ -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 <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
@@ -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 <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
@@ -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 <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
@@ -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 <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
@@ -6554,7 +6565,7 @@ void wl_append (WL_Runtime *rt);
|
||||
// 3p/wl.c
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#line 1 "3p/wl.c"
|
||||
//#line 1 "3p/wl.c"
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
@@ -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 <solar at openwall.com> 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 <stdio.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
@@ -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:
|
||||
|
||||
+79
-41
@@ -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:
|
||||
|
||||
+14
-3
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user