Reorganize files and fix compiler errors

This commit is contained in:
2025-09-23 09:50:20 +02:00
parent 45a9a4e9a1
commit 0790a11b00
13 changed files with 587 additions and 12428 deletions
+1 -1
View File
@@ -16,7 +16,7 @@ sqlite3.o: demo/sqlite3.c
gcc -o $@ -c $< gcc -o $@ -c $<
cozisnews$(EXT): demo/main.c cweb.c cweb.h sqlite3.o cozisnews$(EXT): demo/main.c cweb.c cweb.h sqlite3.o
gcc -o $@ demo/main.c cweb.c sqlite3.o $(FLAGS) gcc -o $@ demo/main.c demo/chttp.c demo/wl.c cweb.c sqlite3.o $(FLAGS) -Idemo
clean: clean:
rm *.o *.out *.exe rm *.o *.out *.exe
+2 -8
View File
@@ -35,14 +35,8 @@ header.save("cweb.h")
source = Amalgamator() source = Amalgamator()
source.append_text("#include \"cweb.h\"\n") source.append_text("#include \"cweb.h\"\n")
source.append_text("#define WL_NOINCLUDE\n")
source.append_text("#define HTTP_NOINCLUDE\n")
source.append_text("#define CRYPT_BLOWFISH_NOINCLUDE") source.append_text("#define CRYPT_BLOWFISH_NOINCLUDE")
source.append_file("3p/chttp.h") source.append_file("src/crypt_blowfish.h")
source.append_file("3p/chttp.c") source.append_file("src/crypt_blowfish.c")
source.append_file("3p/crypt_blowfish.h")
source.append_file("3p/crypt_blowfish.c")
source.append_file("3p/wl.h")
source.append_file("3p/wl.c")
source.append_file("src/main.c") source.append_file("src/main.c")
source.save("cweb.c") source.save("cweb.c")
+248 -12195
View File
File diff suppressed because it is too large Load Diff
+65 -36
View File
@@ -10,6 +10,9 @@
#include <stdint.h> #include <stdint.h>
#include <stdbool.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 { typedef struct {
@@ -143,16 +146,16 @@ CWEB_VArg cweb_varg_from_ps (short *ps);
CWEB_VArg cweb_varg_from_pi (int *pi); CWEB_VArg cweb_varg_from_pi (int *pi);
CWEB_VArg cweb_varg_from_pl (long *pl); CWEB_VArg cweb_varg_from_pl (long *pl);
CWEB_VArg cweb_varg_from_pll (long long *pll); CWEB_VArg cweb_varg_from_pll (long long *pll);
CWEB_VArg cweb_varg_from_psc (char *psc); CWEB_VArg cweb_varg_from_psc (signed char *psc);
CWEB_VArg cweb_varg_from_pss (short *pss); CWEB_VArg cweb_varg_from_pss (signed short *pss);
CWEB_VArg cweb_varg_from_psi (int *psi); CWEB_VArg cweb_varg_from_psi (signed int *psi);
CWEB_VArg cweb_varg_from_psl (long *psl); CWEB_VArg cweb_varg_from_psl (signed long *psl);
CWEB_VArg cweb_varg_from_psll (long long *psll); CWEB_VArg cweb_varg_from_psll (signed long long *psll);
CWEB_VArg cweb_varg_from_puc (char *puc); CWEB_VArg cweb_varg_from_puc (unsigned char *puc);
CWEB_VArg cweb_varg_from_pus (short *pus); CWEB_VArg cweb_varg_from_pus (unsigned short *pus);
CWEB_VArg cweb_varg_from_pui (int *pui); CWEB_VArg cweb_varg_from_pui (unsigned int *pui);
CWEB_VArg cweb_varg_from_pul (long *pul); CWEB_VArg cweb_varg_from_pul (unsigned long *pul);
CWEB_VArg cweb_varg_from_pull (long long *pull); CWEB_VArg cweb_varg_from_pull (unsigned long long *pull);
CWEB_VArg cweb_varg_from_pf (float *pf); CWEB_VArg cweb_varg_from_pf (float *pf);
CWEB_VArg cweb_varg_from_pd (double *pd); CWEB_VArg cweb_varg_from_pd (double *pd);
CWEB_VArg cweb_varg_from_pb (bool *pb); CWEB_VArg cweb_varg_from_pb (bool *pb);
@@ -230,51 +233,77 @@ void cweb_free(CWEB *cweb);
int cweb_enable_database(CWEB *cweb, CWEB_String file); int cweb_enable_database(CWEB *cweb, CWEB_String file);
// Pause execution until a request is available.
// TODO: When does this function return NULL?
CWEB_Request *cweb_wait(CWEB *cweb); CWEB_Request *cweb_wait(CWEB *cweb);
////////////////////////////////////// // Returns true iff the request matches the specified endpoint
// Session
CWEB_String cweb_get_session_csrf(CWEB_Request *req);
int cweb_get_session_user_id(CWEB_Request *req);
int cweb_set_session_user_id(CWEB_Request *req, int user_id);
//////////////////////////////////////
// Request
bool cweb_match_endpoint(CWEB_Request *req, CWEB_String str); bool cweb_match_endpoint(CWEB_Request *req, CWEB_String str);
// Returns the CSRF token associated to the current session
CWEB_String cweb_get_csrf(CWEB_Request *req);
// Returns the user ID for the current session, or -1 if there is no session
int cweb_get_user_id(CWEB_Request *req);
// Sets the user ID for the current session (it must be a positive integer).
// If the ID is -1, the session is deleted.
int cweb_set_user_id(CWEB_Request *req, int user_id);
// 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,
// an empty string is returned.
CWEB_String cweb_get_param_s(CWEB_Request *req, CWEB_String name); CWEB_String cweb_get_param_s(CWEB_Request *req, CWEB_String name);
// Like cweb_get_param_s, but also parser the argument as an integer.
// If parsing fails or the parameter is missing, -1 is returned.
int cweb_get_param_i(CWEB_Request *req, CWEB_String name); int cweb_get_param_i(CWEB_Request *req, CWEB_String name);
////////////////////////////////////// // Create a string by evaluating a format. Memory is allocated from the arena of the request.
// Response // If the arena is full, an empty string is returned.
CWEB_String cweb_format_impl(CWEB_Request *req, char *fmt, CWEB_VArgs args); CWEB_String cweb_format_impl(CWEB_Request *req, char *fmt, CWEB_VArgs args);
// Helper
#define cweb_format(req, fmt, ...) cweb_format_impl((req), (fmt), CWEB_VARGS(__VA_ARGS__)) #define cweb_format(req, fmt, ...) cweb_format_impl((req), (fmt), CWEB_VARGS(__VA_ARGS__))
// Responds to the specified request with the given status code and content
void cweb_respond_basic(CWEB_Request *req, int status, CWEB_String content); void cweb_respond_basic(CWEB_Request *req, int status, CWEB_String content);
// Responds to the request by redirecting the client to the given target
void cweb_respond_redirect(CWEB_Request *req, CWEB_String target); 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(CWEB_Request *req, int status, CWEB_String template_file, int resource_id);
////////////////////////////////////// // Evaluates an SQL INSERT statement and returns the ID of the last inserted row. On error -1 is returned
// Database int64_t cweb_database_insert_impl(CWEB *cweb, char *fmt, CWEB_VArgs args);
typedef struct {
void *handle;
} CWEB_QueryResult;
int64_t cweb_database_insert_impl(CWEB *cweb, const char *fmt, CWEB_VArgs args);
CWEB_QueryResult cweb_database_select_impl(CWEB *cweb, const char *fmt, CWEB_VArgs args);
int cweb_next_query_row_impl(CWEB_QueryResult *res, CWEB_VArgs args);
void cweb_free_query_result(CWEB_QueryResult *res);
// 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;
// Evaluates an SQL SELECT statement, returning a scanner over the returned rows.
// You don't have to check for errors with this function
CWEB_QueryResult cweb_database_select_impl(CWEB *cweb, char *fmt, CWEB_VArgs args);
// Helper
#define cweb_database_select(cweb, fmt, ...) cweb_database_select_impl((cweb), (fmt), CWEB_VARGS(__VA_ARGS__)) #define cweb_database_select(cweb, fmt, ...) cweb_database_select_impl((cweb), (fmt), CWEB_VARGS(__VA_ARGS__))
// Returns the next row from the query result iterator.
int cweb_next_query_row_impl(CWEB_QueryResult *res, CWEB_VArgs args);
// Helper
#define cweb_next_query_row(res, ...) cweb_next_query_row_impl((res), CWEB_VARGS(__VA_ARGS__)) #define cweb_next_query_row(res, ...) cweb_next_query_row_impl((res), CWEB_VARGS(__VA_ARGS__))
////////////////////////////////////// // Frees the result of a database query
// Password void cweb_free_query_result(CWEB_QueryResult *res);
// Calculates the bcrypt hash of the specified password
int cweb_hash_password(char *pass, int passlen, int cost, CWEB_PasswordHash *hash); int cweb_hash_password(char *pass, int passlen, int cost, CWEB_PasswordHash *hash);
// Checks whether the password matches the given hash
int cweb_check_password(char *pass, int passlen, CWEB_PasswordHash hash); int cweb_check_password(char *pass, int passlen, CWEB_PasswordHash hash);
#endif // CWEB_AMALGAMATION #endif // CWEB_AMALGAMATION
+1 -6
View File
@@ -1648,15 +1648,10 @@ HTTP_String http_get_param(HTTP_String body, HTTP_String str, char *mem, int cap
return HTTP_STR(""); return HTTP_STR("");
} }
static bool is_digit(char c)
{
return c >= '0' && c <= '9';
}
int http_get_param_i(HTTP_String body, HTTP_String str) int http_get_param_i(HTTP_String body, HTTP_String str)
{ {
char buf[128]; char buf[128];
HTTP_String out = http_get_param(body, str, buf, SIZEOF(buf)); HTTP_String out = http_get_param(body, str, buf, (int) sizeof(buf));
if (out.len == 0 || !is_digit(out.ptr[0])) if (out.len == 0 || !is_digit(out.ptr[0]))
return -1; return -1;
View File
+25 -14
View File
@@ -140,7 +140,7 @@ static int user_exists(CWEB *cweb, CWEB_String name, CWEB_String pass)
static void endpoint_api_login(CWEB *cweb, CWEB_Request *req) static void endpoint_api_login(CWEB *cweb, CWEB_Request *req)
{ {
if (cweb_get_session_user_id(req) != -1) { if (cweb_get_user_id(req) != -1) {
cweb_respond_redirect(req, CWEB_STR("/index")); cweb_respond_redirect(req, CWEB_STR("/index"));
return; return;
} }
@@ -157,7 +157,7 @@ static void endpoint_api_login(CWEB *cweb, CWEB_Request *req)
cweb_respond_basic(req, 200, CWEB_STR("<div class=\"error\">Invalid credentials</div>")); cweb_respond_basic(req, 200, CWEB_STR("<div class=\"error\">Invalid credentials</div>"));
return; return;
} }
if (cweb_set_session_user_id(req, ret) < 0) { if (cweb_set_user_id(req, ret) < 0) {
// TODO // TODO
} }
@@ -166,7 +166,7 @@ static void endpoint_api_login(CWEB *cweb, CWEB_Request *req)
static void endpoint_api_signup(CWEB *cweb, CWEB_Request *req) static void endpoint_api_signup(CWEB *cweb, CWEB_Request *req)
{ {
if (cweb_get_session_user_id(req) != -1) { if (cweb_get_user_id(req) != -1) {
cweb_respond_redirect(req, CWEB_STR("/index")); cweb_respond_redirect(req, CWEB_STR("/index"));
return; return;
} }
@@ -199,20 +199,22 @@ static void endpoint_api_signup(CWEB *cweb, CWEB_Request *req)
cweb_respond_basic(req, 400, CWEB_STR("<div class=\"error\">Internal error</div>")); cweb_respond_basic(req, 400, CWEB_STR("<div class=\"error\">Internal error</div>"));
return; return;
} }
cweb_set_session_user_id(req, insert_id); cweb_set_user_id(req, insert_id);
cweb_respond_redirect(req, CWEB_STR("/index")); cweb_respond_redirect(req, CWEB_STR("/index"));
} }
static void endpoint_api_logout(CWEB *cweb, CWEB_Request *req) static void endpoint_api_logout(CWEB *cweb, CWEB_Request *req)
{ {
cweb_set_session_user_id(req, -1); (void) cweb;
cweb_set_user_id(req, -1);
cweb_respond_redirect(req, CWEB_STR("/index")); cweb_respond_redirect(req, CWEB_STR("/index"));
} }
static void endpoint_api_post(CWEB *cweb, CWEB_Request *req) static void endpoint_api_post(CWEB *cweb, CWEB_Request *req)
{ {
int user_id = cweb_get_session_user_id(req); int user_id = cweb_get_user_id(req);
if (user_id == -1) { if (user_id == -1) {
cweb_respond_redirect(req, CWEB_STR("/index")); cweb_respond_redirect(req, CWEB_STR("/index"));
return; return;
@@ -223,7 +225,7 @@ static void endpoint_api_post(CWEB *cweb, CWEB_Request *req)
CWEB_String content = cweb_get_param_s(req, CWEB_STR("content")); CWEB_String content = cweb_get_param_s(req, CWEB_STR("content"));
CWEB_String csrf = cweb_get_param_s(req, CWEB_STR("csrf")); CWEB_String csrf = cweb_get_param_s(req, CWEB_STR("csrf"));
if (!cweb_streq(cweb_get_session_csrf(req), csrf)) { if (!cweb_streq(cweb_get_csrf(req), csrf)) {
cweb_respond_basic(req, 400, CWEB_STR("Invalid request")); cweb_respond_basic(req, 400, CWEB_STR("Invalid request"));
return; return;
} }
@@ -264,7 +266,7 @@ static void endpoint_api_post(CWEB *cweb, CWEB_Request *req)
static void endpoint_api_comment(CWEB *cweb, CWEB_Request *req) static void endpoint_api_comment(CWEB *cweb, CWEB_Request *req)
{ {
int user_id = cweb_get_session_user_id(req); int user_id = cweb_get_user_id(req);
if (user_id == -1) { if (user_id == -1) {
cweb_respond_basic(req, 200, CWEB_STR("<div class=\"error\">You are not logged in</div>")); cweb_respond_basic(req, 200, CWEB_STR("<div class=\"error\">You are not logged in</div>"));
return; return;
@@ -275,7 +277,7 @@ static void endpoint_api_comment(CWEB *cweb, CWEB_Request *req)
CWEB_String content = cweb_get_param_s(req, CWEB_STR("content")); CWEB_String content = cweb_get_param_s(req, CWEB_STR("content"));
CWEB_String csrf2 = cweb_get_param_s(req, CWEB_STR("csrf")); CWEB_String csrf2 = cweb_get_param_s(req, CWEB_STR("csrf"));
if (!cweb_streq(cweb_get_session_csrf(req), csrf2)) { if (!cweb_streq(cweb_get_csrf(req), csrf2)) {
cweb_respond_basic(req, 200, CWEB_STR("<div class=\"error\">Invalid request</div>")); cweb_respond_basic(req, 200, CWEB_STR("<div class=\"error\">Invalid request</div>"));
return; return;
} }
@@ -299,12 +301,16 @@ static void endpoint_api_comment(CWEB *cweb, CWEB_Request *req)
static void endpoint_index(CWEB *cweb, CWEB_Request *req) static void endpoint_index(CWEB *cweb, CWEB_Request *req)
{ {
(void) cweb;
cweb_respond_template(req, 200, CWEB_STR("pages/index.wl"), -1); cweb_respond_template(req, 200, CWEB_STR("pages/index.wl"), -1);
} }
static void endpoint_write(CWEB *cweb, CWEB_Request *req) static void endpoint_write(CWEB *cweb, CWEB_Request *req)
{ {
if (cweb_get_session_user_id(req) == -1) { (void) cweb;
if (cweb_get_user_id(req) == -1) {
cweb_respond_redirect(req, CWEB_STR("/index")); cweb_respond_redirect(req, CWEB_STR("/index"));
return; return;
} }
@@ -314,7 +320,9 @@ static void endpoint_write(CWEB *cweb, CWEB_Request *req)
static void endpoint_login(CWEB *cweb, CWEB_Request *req) static void endpoint_login(CWEB *cweb, CWEB_Request *req)
{ {
if (cweb_get_session_user_id(req) != -1) { (void) cweb;
if (cweb_get_user_id(req) != -1) {
cweb_respond_redirect(req, CWEB_STR("/index")); cweb_respond_redirect(req, CWEB_STR("/index"));
return; return;
} }
@@ -324,7 +332,9 @@ static void endpoint_login(CWEB *cweb, CWEB_Request *req)
static void endpoint_signup(CWEB *cweb, CWEB_Request *req) static void endpoint_signup(CWEB *cweb, CWEB_Request *req)
{ {
if (cweb_get_session_user_id(req) != -1) { (void) cweb;
if (cweb_get_user_id(req) != -1) {
cweb_respond_redirect(req, CWEB_STR("/index")); cweb_respond_redirect(req, CWEB_STR("/index"));
return; return;
} }
@@ -340,8 +350,7 @@ static void endpoint_post(CWEB *cweb, CWEB_Request *req)
return; return;
} }
CWEB_QueryResult res = cweb_database_select(cweb, CWEB_QueryResult res = cweb_database_select(cweb, "SELECT COUNT(*) FROM Posts WHERE id=?", post_id);
"SELECT COUNT(*) FROM Posts WHERE id=?", post_id);
int num; int num;
if (cweb_next_query_row(&res, &num) != 1) { if (cweb_next_query_row(&res, &num) != 1) {
@@ -366,6 +375,8 @@ static void endpoint_post(CWEB *cweb, CWEB_Request *req)
static void endpoint_fallback(CWEB *cweb, CWEB_Request *req) static void endpoint_fallback(CWEB *cweb, CWEB_Request *req)
{ {
(void) cweb;
cweb_respond_template(req, 404, CWEB_STR("pages/notfound.wl"), -1); cweb_respond_template(req, 404, CWEB_STR("pages/notfound.wl"), -1);
} }
View File
View File
+228 -154
View File
@@ -1,7 +1,4 @@
#include "sqlite3.h" #include <stdio.h>
#include "wl.h"
#include "chttp.h"
#include "cweb.h"
#ifdef __linux__ #ifdef __linux__
#include <errno.h> #include <errno.h>
@@ -12,6 +9,25 @@
#include <windows.h> #include <windows.h>
#endif #endif
#ifdef CWEB_ENABLE_DATABASE
#include "sqlite3.h"
#endif
#ifdef CWEB_ENABLE_TEMPLATE
#include "wl.h"
#endif
#include "chttp.h"
#include "cweb.h"
#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
#define ASSERT(X) {if (!(X)) { __builtin_trap(); }}
#define TRACE(X, ...) ((void) 0)
#define SIZEOF(X) (int) (sizeof(X)/sizeof((X)[0]))
#ifdef CWEB_ENABLE_TEMPLATE
typedef struct { typedef struct {
char path[1<<8]; char path[1<<8];
int pathlen; int pathlen;
@@ -27,12 +43,16 @@ typedef struct {
static TemplateCache *template_cache_init(int capacity_log2); static TemplateCache *template_cache_init(int capacity_log2);
static void template_cache_free(TemplateCache *cache); static void template_cache_free(TemplateCache *cache);
#endif
typedef struct SessionStorage SessionStorage; typedef struct SessionStorage SessionStorage;
#ifdef CWEB_ENABLE_DATABASE
typedef struct SQLiteCache SQLiteCache; typedef struct SQLiteCache SQLiteCache;
static SQLiteCache* sqlite_cache_init(sqlite3 *db, int capacity_log2); static SQLiteCache* sqlite_cache_init(sqlite3 *db, int capacity_log2);
static void sqlite_cache_free(SQLiteCache *cache); static void sqlite_cache_free(SQLiteCache *cache);
static sqlite3* sqlite_cache_getdb(SQLiteCache *cache);
static int sqlite3utils_prepare(SQLiteCache *cache, static int sqlite3utils_prepare(SQLiteCache *cache,
sqlite3_stmt **pstmt, char *fmt, int fmtlen); sqlite3_stmt **pstmt, char *fmt, int fmtlen);
@@ -43,26 +63,7 @@ static int sqlite3utils_prepare_and_bind_impl(SQLiteCache *cache,
#define sqlite3utils_prepare_and_bind(cache, pstmt, fmt, ...) \ #define sqlite3utils_prepare_and_bind(cache, pstmt, fmt, ...) \
sqlite3utils_prepare_and_bind_impl((cache), (pstmt), (fmt), VARGS(__VA_ARGS__)) sqlite3utils_prepare_and_bind_impl((cache), (pstmt), (fmt), VARGS(__VA_ARGS__))
struct CWEB { #endif
HTTP_Server *server;
int pool_cap;
char *pool;
// Login
SessionStorage *session_storage;
// Database
sqlite3 *db;
SQLiteCache *dbcache;
// Template
TemplateCache *tpcache;
bool allow_insecure_login;
CWEB_Request req;
};
struct CWEB_Request { struct CWEB_Request {
@@ -80,6 +81,29 @@ struct CWEB_Request {
CWEB_String csrf; CWEB_String csrf;
}; };
struct CWEB {
HTTP_Server *server;
int pool_cap;
char *pool;
// Login
SessionStorage *session_storage;
#ifdef CWEB_ENABLE_DATABASE
sqlite3 *db;
SQLiteCache *dbcache;
#endif
#ifdef CWEB_ENABLE_TEMPLATE
TemplateCache *tpcache;
#endif
bool allow_insecure_login;
CWEB_Request req;
};
/////////////////////////// ///////////////////////////
bool cweb_streq(CWEB_String a, CWEB_String b) bool cweb_streq(CWEB_String a, CWEB_String b)
@@ -118,22 +142,94 @@ CWEB_VArg cweb_varg_from_ps (short *ps) { return (CWEB_VArg) { CWEB_VA
CWEB_VArg cweb_varg_from_pi (int *pi) { return (CWEB_VArg) { CWEB_VARG_TYPE_PI, .pi=pi }; } CWEB_VArg cweb_varg_from_pi (int *pi) { return (CWEB_VArg) { CWEB_VARG_TYPE_PI, .pi=pi }; }
CWEB_VArg cweb_varg_from_pl (long *pl) { return (CWEB_VArg) { CWEB_VARG_TYPE_PL, .pl=pl }; } CWEB_VArg cweb_varg_from_pl (long *pl) { return (CWEB_VArg) { CWEB_VARG_TYPE_PL, .pl=pl }; }
CWEB_VArg cweb_varg_from_pll (long long *pll) { return (CWEB_VArg) { CWEB_VARG_TYPE_PLL, .pll=pll }; } CWEB_VArg cweb_varg_from_pll (long long *pll) { return (CWEB_VArg) { CWEB_VARG_TYPE_PLL, .pll=pll }; }
CWEB_VArg cweb_varg_from_psc (char *psc) { return (CWEB_VArg) { CWEB_VARG_TYPE_PSC, .psc=psc }; } CWEB_VArg cweb_varg_from_psc (signed char *psc) { return (CWEB_VArg) { CWEB_VARG_TYPE_PSC, .psc=psc }; }
CWEB_VArg cweb_varg_from_pss (short *pss) { return (CWEB_VArg) { CWEB_VARG_TYPE_PSS, .pss=pss }; } CWEB_VArg cweb_varg_from_pss (signed short *pss) { return (CWEB_VArg) { CWEB_VARG_TYPE_PSS, .pss=pss }; }
CWEB_VArg cweb_varg_from_psi (int *psi) { return (CWEB_VArg) { CWEB_VARG_TYPE_PSI, .psi=psi }; } CWEB_VArg cweb_varg_from_psi (signed int *psi) { return (CWEB_VArg) { CWEB_VARG_TYPE_PSI, .psi=psi }; }
CWEB_VArg cweb_varg_from_psl (long *psl) { return (CWEB_VArg) { CWEB_VARG_TYPE_PSL, .psl=psl }; } CWEB_VArg cweb_varg_from_psl (signed long *psl) { return (CWEB_VArg) { CWEB_VARG_TYPE_PSL, .psl=psl }; }
CWEB_VArg cweb_varg_from_psll (long long *psll) { return (CWEB_VArg) { CWEB_VARG_TYPE_PSLL, .psll=psll }; } CWEB_VArg cweb_varg_from_psll (signed long long *psll) { return (CWEB_VArg) { CWEB_VARG_TYPE_PSLL, .psll=psll }; }
CWEB_VArg cweb_varg_from_puc (char *puc) { return (CWEB_VArg) { CWEB_VARG_TYPE_PUC, .puc=puc }; } CWEB_VArg cweb_varg_from_puc (unsigned char *puc) { return (CWEB_VArg) { CWEB_VARG_TYPE_PUC, .puc=puc }; }
CWEB_VArg cweb_varg_from_pus (short *pus) { return (CWEB_VArg) { CWEB_VARG_TYPE_PUS, .pus=pus }; } CWEB_VArg cweb_varg_from_pus (unsigned short *pus) { return (CWEB_VArg) { CWEB_VARG_TYPE_PUS, .pus=pus }; }
CWEB_VArg cweb_varg_from_pui (int *pui) { return (CWEB_VArg) { CWEB_VARG_TYPE_PUI, .pui=pui }; } CWEB_VArg cweb_varg_from_pui (unsigned int *pui) { return (CWEB_VArg) { CWEB_VARG_TYPE_PUI, .pui=pui }; }
CWEB_VArg cweb_varg_from_pul (long *pul) { return (CWEB_VArg) { CWEB_VARG_TYPE_PUL, .pul=pul }; } CWEB_VArg cweb_varg_from_pul (unsigned long *pul) { return (CWEB_VArg) { CWEB_VARG_TYPE_PUL, .pul=pul }; }
CWEB_VArg cweb_varg_from_pull (long long *pull) { return (CWEB_VArg) { CWEB_VARG_TYPE_PULL, .pull=pull }; } CWEB_VArg cweb_varg_from_pull (unsigned long long *pull) { return (CWEB_VArg) { CWEB_VARG_TYPE_PULL, .pull=pull }; }
CWEB_VArg cweb_varg_from_pf (float *pf) { return (CWEB_VArg) { CWEB_VARG_TYPE_PF, .pf=pf }; } CWEB_VArg cweb_varg_from_pf (float *pf) { return (CWEB_VArg) { CWEB_VARG_TYPE_PF, .pf=pf }; }
CWEB_VArg cweb_varg_from_pd (double *pd) { return (CWEB_VArg) { CWEB_VARG_TYPE_PD, .pd=pd }; } CWEB_VArg cweb_varg_from_pd (double *pd) { return (CWEB_VArg) { CWEB_VARG_TYPE_PD, .pd=pd }; }
CWEB_VArg cweb_varg_from_pb (bool *pb) { return (CWEB_VArg) { CWEB_VARG_TYPE_PB, .pb=pb }; } CWEB_VArg cweb_varg_from_pb (bool *pb) { return (CWEB_VArg) { CWEB_VARG_TYPE_PB, .pb=pb }; }
CWEB_VArg cweb_varg_from_pstr (CWEB_String *pstr) { return (CWEB_VArg) { CWEB_VARG_TYPE_PSTR, .pstr=pstr }; } CWEB_VArg cweb_varg_from_pstr (CWEB_String *pstr) { return (CWEB_VArg) { CWEB_VARG_TYPE_PSTR, .pstr=pstr }; }
CWEB_VArg cweb_varg_from_phash(CWEB_PasswordHash *phash) { return (CWEB_VArg) { CWEB_VARG_TYPE_PHASH, .phash=phash }; } CWEB_VArg cweb_varg_from_phash(CWEB_PasswordHash *phash) { return (CWEB_VArg) { CWEB_VARG_TYPE_PHASH, .phash=phash }; }
/////////////////////////////////////////////////////////////////
// FILE SYSTEM
////////////////////////////////////////////////////////////////
typedef struct LoadedFile LoadedFile;
struct LoadedFile {
LoadedFile* next;
int len;
char data[];
};
static LoadedFile *load_file(CWEB_String path)
{
char buf[1<<10];
if (path.len >= (int) sizeof(buf))
return NULL;
memcpy(buf, path.ptr, path.len);
buf[path.len] = '\0';
FILE *stream = fopen(buf, "rb");
if (stream == NULL)
return NULL;
int ret = fseek(stream, 0, SEEK_END);
if (ret) {
fclose(stream);
return NULL;
}
long tmp = ftell(stream);
if (tmp < 0 || tmp > INT_MAX) {
fclose(stream);
return NULL;
}
int len = (int) tmp;
ret = fseek(stream, 0, SEEK_SET);
if (ret) {
fclose(stream);
return NULL;
}
LoadedFile *result = malloc(sizeof(LoadedFile) + len + 1);
if (result == NULL) {
fclose(stream);
return NULL;
}
result->next = NULL;
result->len = len;
int read_len = fread(result->data, 1, len+1, stream);
if (read_len != len || ferror(stream) || !feof(stream)) {
fclose(stream);
free(result);
return NULL;
}
result->data[len] = '\0';
fclose(stream);
return result;
}
static void free_loaded_files(LoadedFile *loaded_file)
{
while (loaded_file) {
LoadedFile *next = loaded_file->next;
free(loaded_file);
loaded_file = next;
}
}
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// RANDOM // RANDOM
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
@@ -242,7 +338,7 @@ static int hex_digit_to_int(char c)
static void unpack_token(char *src, int srclen, char *dst, int dstlen) static void unpack_token(char *src, int srclen, char *dst, int dstlen)
{ {
assert(2 * srclen == dstlen); ASSERT(2 * srclen == dstlen);
for (int i = 0; i < srclen; i++) { for (int i = 0; i < srclen; i++) {
static const char table[] = "0123456789abcdef"; static const char table[] = "0123456789abcdef";
@@ -258,7 +354,7 @@ static int pack_token(char *src, int srclen, char *dst, int dstlen)
if (srclen & 1) if (srclen & 1)
return -1; return -1;
assert(srclen == 2 * dstlen); ASSERT(srclen == 2 * dstlen);
for (int i = 0; i < srclen; i += 2) { for (int i = 0; i < srclen; i += 2) {
int high = src[i+0]; int high = src[i+0];
@@ -381,7 +477,7 @@ static int delete_session(SessionStorage *storage, CWEB_String sess)
Session *found = lookup_session_slot(storage, sess, false); Session *found = lookup_session_slot(storage, sess, false);
if (found == NULL) if (found == NULL)
return false; return false;
assert(found->user >= 0); ASSERT(found->user >= 0);
found->user = -2; found->user = -2;
storage->count--; storage->count--;
return 0; return 0;
@@ -392,7 +488,7 @@ static int find_session(SessionStorage *storage, CWEB_String sess, CWEB_String *
Session *found = lookup_session_slot(storage, sess, false); Session *found = lookup_session_slot(storage, sess, false);
if (found == NULL) if (found == NULL)
return -1; return -1;
assert(found->user >= 0); ASSERT(found->user >= 0);
*pcsrf = (CWEB_String) { found->csrf, CSRF_TOKEN_SIZE }; *pcsrf = (CWEB_String) { found->csrf, CSRF_TOKEN_SIZE };
*puser = found->user; *puser = found->user;
return 0; return 0;
@@ -402,6 +498,8 @@ static int find_session(SessionStorage *storage, CWEB_String sess, CWEB_String *
// DATABASE // DATABASE
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
#ifdef CWEB_ENABLE_DATABASE
typedef struct { typedef struct {
char *str; char *str;
int len; int len;
@@ -443,11 +541,6 @@ static void sqlite_cache_free(SQLiteCache *cache)
free(cache); free(cache);
} }
static sqlite3 *sqlite_cache_getdb(SQLiteCache *cache)
{
return cache->db;
}
static unsigned long djb2(char *src, int len) static unsigned long djb2(char *src, int len)
{ {
char *ptr = src; char *ptr = src;
@@ -460,7 +553,7 @@ static unsigned long djb2(char *src, int len)
return hash; return hash;
} }
static int lookup(SQLiteCache *cache, char *fmt, int fmtlen) static int sqlite_cache_lookup(SQLiteCache *cache, char *fmt, int fmtlen)
{ {
int mask = (1 << cache->capacity_log2) - 1; int mask = (1 << cache->capacity_log2) - 1;
int hash = djb2(fmt, fmtlen); int hash = djb2(fmt, fmtlen);
@@ -486,7 +579,7 @@ static int sqlite3utils_prepare(SQLiteCache *cache, sqlite3_stmt **pstmt, char *
if (fmtlen < 0) if (fmtlen < 0)
fmtlen = strlen(fmt); fmtlen = strlen(fmt);
int i = lookup(cache, fmt, fmtlen); int i = sqlite_cache_lookup(cache, fmt, fmtlen);
if (cache->items[i].stmt == NULL) { if (cache->items[i].stmt == NULL) {
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
@@ -543,6 +636,9 @@ static int sqlite3utils_prepare_and_bind_impl(SQLiteCache *cache,
case CWEB_VARG_TYPE_D : ret = sqlite3_bind_double(stmt, i+1, arg.d); break; case CWEB_VARG_TYPE_D : ret = sqlite3_bind_double(stmt, i+1, arg.d); break;
case CWEB_VARG_TYPE_B : ret = sqlite3_bind_int (stmt, i+1, arg.b); break; case CWEB_VARG_TYPE_B : ret = sqlite3_bind_int (stmt, i+1, arg.b); break;
case CWEB_VARG_TYPE_STR: ret = sqlite3_bind_text (stmt, i+1, arg.str.ptr, arg.str.len, NULL); break; case CWEB_VARG_TYPE_STR: ret = sqlite3_bind_text (stmt, i+1, arg.str.ptr, arg.str.len, NULL); break;
default:
// TODO
break;
} }
if (ret != SQLITE_OK) { if (ret != SQLITE_OK) {
sqlite3_reset(stmt); sqlite3_reset(stmt);
@@ -554,8 +650,11 @@ static int sqlite3utils_prepare_and_bind_impl(SQLiteCache *cache,
return SQLITE_OK; return SQLITE_OK;
} }
int64_t cweb_database_insert_impl(CWEB *cweb, const char *fmt, CWEB_VArgs args) #endif // CWEB_ENABLE_DATABASE
int64_t cweb_database_insert_impl(CWEB *cweb, char *fmt, CWEB_VArgs args)
{ {
#ifdef CWEB_ENABLE_DATABASE
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
int ret = sqlite3utils_prepare_and_bind_impl(cweb->dbcache, &stmt, fmt, args); int ret = sqlite3utils_prepare_and_bind_impl(cweb->dbcache, &stmt, fmt, args);
if (ret != SQLITE_OK) if (ret != SQLITE_OK)
@@ -575,20 +674,28 @@ int64_t cweb_database_insert_impl(CWEB *cweb, const char *fmt, CWEB_VArgs args)
sqlite3_reset(stmt); sqlite3_reset(stmt);
return insert_id; return insert_id;
#else
return -1;
#endif
} }
CWEB_QueryResult cweb_database_select_impl(CWEB *cweb, const char *fmt, CWEB_VArgs args) CWEB_QueryResult cweb_database_select_impl(CWEB *cweb, char *fmt, CWEB_VArgs args)
{ {
#ifdef CWEB_ENABLE_DATABASE
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
int ret = sqlite3utils_prepare_and_bind_impl(cweb->dbcache, &stmt, fmt, args); int ret = sqlite3utils_prepare_and_bind_impl(cweb->dbcache, &stmt, fmt, args);
if (ret != SQLITE_OK) if (ret != SQLITE_OK)
return (CWEB_QueryResult) { NULL }; return (CWEB_QueryResult) { NULL };
return (CWEB_QueryResult) { stmt }; return (CWEB_QueryResult) { stmt };
#else
return (CWEB_QueryResult) { NULL };
#endif
} }
int cweb_next_query_row_impl(CWEB_QueryResult *res, CWEB_VArgs args) int cweb_next_query_row_impl(CWEB_QueryResult *res, CWEB_VArgs args)
{ {
#ifdef CWEB_ENABLE_DATABASE
if (res->handle == NULL) if (res->handle == NULL)
return -1; return -1;
@@ -674,19 +781,30 @@ int cweb_next_query_row_impl(CWEB_QueryResult *res, CWEB_VArgs args)
} }
return 1; return 1;
#else
(void) res;
(void) args;
return -1;
#endif
} }
void cweb_free_query_result(CWEB_QueryResult *res) void cweb_free_query_result(CWEB_QueryResult *res)
{ {
#ifdef CWEB_ENABLE_DATABASE
if (res->handle) { if (res->handle) {
sqlite3_reset(res->handle); sqlite3_reset(res->handle);
res->handle = NULL; res->handle = NULL;
} }
#else
(void) res;
#endif
} }
int cweb_global_init(void) int cweb_global_init(void)
{ {
http_global_init(); if (http_global_init())
return -1;
return 0;
} }
void cweb_global_free(void) void cweb_global_free(void)
@@ -694,7 +812,7 @@ void cweb_global_free(void)
http_global_free(); http_global_free();
} }
CWEB *web_init(CWEB_String addr, uint16_t port) CWEB *cweb_init(CWEB_String addr, uint16_t port)
{ {
// If set, allows logins and signups over HTTP, which is highly insecure. // If set, allows logins and signups over HTTP, which is highly insecure.
// This allows compiling the application without TLS when developing. // This allows compiling the application without TLS when developing.
@@ -705,56 +823,68 @@ CWEB *web_init(CWEB_String addr, uint16_t port)
CWEB *cweb = malloc(sizeof(CWEB)); CWEB *cweb = malloc(sizeof(CWEB));
if (cweb == NULL) if (cweb == NULL)
return -1; return NULL;
cweb->pool_cap = 1<<20; cweb->pool_cap = 1<<20;
cweb->pool = malloc(cweb->pool_cap); cweb->pool = malloc(cweb->pool_cap);
if (cweb->pool == NULL) { if (cweb->pool == NULL) {
free(cweb); free(cweb);
return -1; return NULL;
} }
#ifdef CWEB_ENABLE_TEMPLATE
cweb->tpcache = template_cache_init(4); cweb->tpcache = template_cache_init(4);
if (cweb->tpcache == NULL) { if (cweb->tpcache == NULL) {
free(cweb->pool); free(cweb->pool);
free(cweb); free(cweb);
return -1; return NULL;
} }
#endif
cweb->session_storage = session_storage_init(1024); cweb->session_storage = session_storage_init(1024);
if (cweb->session_storage == NULL) { if (cweb->session_storage == NULL) {
#ifdef CWEB_ENABLE_TEMPLATE
template_cache_free(cweb->tpcache); template_cache_free(cweb->tpcache);
#endif
free(cweb->pool); free(cweb->pool);
free(cweb); free(cweb);
return -1; return NULL;
} }
cweb->server = http_server_init((HTTP_String) { addr.ptr, addr.len }, port); cweb->server = http_server_init((HTTP_String) { addr.ptr, addr.len }, port);
if (cweb->server == NULL) { if (cweb->server == NULL) {
session_storage_free(cweb->session_storage); session_storage_free(cweb->session_storage);
#ifdef CWEB_ENABLE_TEMPLATE
template_cache_free(cweb->tpcache); template_cache_free(cweb->tpcache);
#endif
free(cweb->pool); free(cweb->pool);
free(cweb); free(cweb);
return -1; return NULL;
} }
#ifdef CWEB_ENABLE_DATABASE
cweb->db = NULL; cweb->db = NULL;
cweb->dbcache = NULL; cweb->dbcache = NULL;
#endif
cweb->allow_insecure_login = false; cweb->allow_insecure_login = false;
return 0; return cweb;
} }
void cweb_free(CWEB *cweb) void cweb_free(CWEB *cweb)
{ {
http_server_free(cweb->server); http_server_free(cweb->server);
session_storage_free(cweb->session_storage); session_storage_free(cweb->session_storage);
#ifdef CWEB_ENABLE_TEMPLATE
template_cache_free(cweb->tpcache); template_cache_free(cweb->tpcache);
#endif
#ifdef CWEB_ENABLE_DATABASE
if (cweb->db) { if (cweb->db) {
sqlite_cache_free(cweb->dbcache); sqlite_cache_free(cweb->dbcache);
sqlite3_close(cweb->db); sqlite3_close(cweb->db);
} }
#endif
free(cweb); free(cweb);
} }
@@ -765,6 +895,7 @@ void cweb_version(void)
int cweb_enable_database(CWEB *cweb, CWEB_String file) int cweb_enable_database(CWEB *cweb, CWEB_String file)
{ {
#ifdef CWEB_ENABLE_DATABASE
if (cweb->db != NULL) if (cweb->db != NULL)
return -1; // Already enabled return -1; // Already enabled
@@ -781,23 +912,21 @@ int cweb_enable_database(CWEB *cweb, CWEB_String file)
return -1; return -1;
} }
char *schema_data; LoadedFile *schema = load_file(file);
long schema_size; if (schema == NULL) {
ret = load_file(file_copy, &schema_data, &schema_size);
if (ret < 0) {
sqlite3_close(cweb->db); sqlite3_close(cweb->db);
cweb->db = NULL; cweb->db = NULL;
return -1; return -1;
} }
ret = sqlite3_exec(cweb->db, schema_data, NULL, NULL, NULL); ret = sqlite3_exec(cweb->db, schema->data, NULL, NULL, NULL);
if (ret != SQLITE_OK) { if (ret != SQLITE_OK) {
sqlite3_close(cweb->db); sqlite3_close(cweb->db);
cweb->db = NULL; cweb->db = NULL;
return -1; return -1;
} }
free(schema_data); free_loaded_files(schema);
cweb->dbcache = sqlite_cache_init(cweb->db, 5); cweb->dbcache = sqlite_cache_init(cweb->db, 5);
if (cweb->dbcache == NULL) { if (cweb->dbcache == NULL) {
@@ -807,6 +936,9 @@ int cweb_enable_database(CWEB *cweb, CWEB_String file)
} }
return 0; return 0;
#else
return -1;
#endif
} }
CWEB_Request *cweb_wait(CWEB *cweb) CWEB_Request *cweb_wait(CWEB *cweb)
@@ -814,12 +946,15 @@ CWEB_Request *cweb_wait(CWEB *cweb)
CWEB_Request *req = &cweb->req; CWEB_Request *req = &cweb->req;
int ret = http_server_wait(cweb->server, &req->req, &req->builder); int ret = http_server_wait(cweb->server, &req->req, &req->builder);
if (ret < 0) return -1; if (ret) return NULL; // Error or signal
HTTP_String session_token = http_get_cookie(req->req, HTTP_STR("sess_token"));
req->cweb = cweb;
req->arena = (WL_Arena) { cweb->pool, cweb->pool_cap, 0 }; req->arena = (WL_Arena) { cweb->pool, cweb->pool_cap, 0 };
req->just_created_session = false; req->just_created_session = false;
req->sess = http_get_cookie(req->req, HTTP_STR("sess_token")); req->sess = (CWEB_String) { session_token.ptr, session_token.len };
if (find_session(cweb->session_storage, req->sess, &req->csrf, &req->user_id) < 0) { if (find_session(cweb->session_storage, req->sess, &req->csrf, &req->user_id) < 0) {
req->user_id = -1; req->user_id = -1;
req->sess = (CWEB_String) { NULL, 0 }; req->sess = (CWEB_String) { NULL, 0 };
@@ -871,9 +1006,9 @@ static int set_auth_cookie_if_necessary(CWEB_Request *req)
return 0; return 0;
} }
void cweb_respond(CWEB_Request *req, int status, CWEB_String content) void cweb_respond_basic(CWEB_Request *req, int status, CWEB_String content)
{ {
http_response_builder_status(req->builder, 200); http_response_builder_status(req->builder, status);
int ret = set_auth_cookie_if_necessary(req); int ret = set_auth_cookie_if_necessary(req);
if (ret < 0) { if (ret < 0) {
http_response_builder_undo(req->builder); http_response_builder_undo(req->builder);
@@ -909,6 +1044,11 @@ static void append_to_output_s64(StaticOutputBuffer *out, int64_t n)
// TODO // TODO
} }
static void append_to_output_f64(StaticOutputBuffer *out, double n)
{
// TODO
}
static void append_to_output_ptr(StaticOutputBuffer *out, void *p) static void append_to_output_ptr(StaticOutputBuffer *out, void *p)
{ {
// TODO // TODO
@@ -986,7 +1126,7 @@ static void evaluate_format(StaticOutputBuffer *out, CWEB_String format, CWEB_VA
cur++; cur++;
if (cur < len) { if (cur < len) {
assert(src[cur] == '}'); ASSERT(src[cur] == '}');
cur++; cur++;
} }
@@ -996,7 +1136,7 @@ static void evaluate_format(StaticOutputBuffer *out, CWEB_String format, CWEB_VA
} }
} else { } else {
assert(src[cur-1] == '\\'); ASSERT(src[cur-1] == '\\');
if (cur < len) { if (cur < len) {
append_to_output(out, &src[cur], 1); append_to_output(out, &src[cur], 1);
cur++; cur++;
@@ -1065,9 +1205,15 @@ int cweb_get_user_id(CWEB_Request *req)
return req->user_id; return req->user_id;
} }
CWEB_String cweb_get_csrf(CWEB_Request *req)
{
return req->csrf;
}
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// TEMPLATE // TEMPLATE
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
#ifdef CWEB_ENABLE_TEMPLATE
static TemplateCache *template_cache_init(int capacity_log2) static TemplateCache *template_cache_init(int capacity_log2)
{ {
@@ -1088,22 +1234,10 @@ static void template_cache_free(TemplateCache *cache)
free(cache); free(cache);
} }
static unsigned long djb2(WL_String str) static int template_cache_lookup(TemplateCache *cache, WL_String path)
{
char *ptr = str.ptr;
char *end = str.ptr + str.len;
unsigned long hash = 5381;
int c;
while (ptr < end && (c = *ptr++))
hash = ((hash << 5) + hash) + c; // hash * 33 + c
return hash;
}
static int lookup(TemplateCache *cache, WL_String path)
{ {
int mask = (1 << cache->capacity_log2) - 1; int mask = (1 << cache->capacity_log2) - 1;
int hash = djb2(path); int hash = djb2(path.ptr, path.len);
int i = hash & mask; int i = hash & mask;
int perturb = hash; int perturb = hash;
for (;;) { for (;;) {
@@ -1121,72 +1255,6 @@ static int lookup(TemplateCache *cache, WL_String path)
return -1; return -1;
} }
typedef struct LoadedFile LoadedFile;
struct LoadedFile {
LoadedFile* next;
int len;
char data[];
};
static LoadedFile *load_file(WL_String path)
{
char buf[1<<10];
if (path.len >= (int) sizeof(buf))
return NULL;
memcpy(buf, path.ptr, path.len);
buf[path.len] = '\0';
FILE *stream = fopen(buf, "rb");
if (stream == NULL)
return NULL;
int ret = fseek(stream, 0, SEEK_END);
if (ret) {
fclose(stream);
return NULL;
}
long tmp = ftell(stream);
if (tmp < 0 || tmp > INT_MAX) {
fclose(stream);
return NULL;
}
int len = (int) tmp;
ret = fseek(stream, 0, SEEK_SET);
if (ret) {
fclose(stream);
return NULL;
}
LoadedFile *result = malloc(sizeof(LoadedFile) + len + 1);
if (result == NULL) {
fclose(stream);
return NULL;
}
result->next = NULL;
result->len = len;
int read_len = fread(result->data, 1, len+1, stream);
if (read_len != len || ferror(stream) || !feof(stream)) {
fclose(stream);
free(result);
return NULL;
}
fclose(stream);
return result;
}
static void free_loaded_files(LoadedFile *loaded_file)
{
while (loaded_file) {
LoadedFile *next = loaded_file->next;
free(loaded_file);
loaded_file = next;
}
}
static int compile(WL_String path, WL_Program *program, WL_Arena *arena) static int compile(WL_String path, WL_Program *program, WL_Arena *arena)
{ {
WL_Compiler *compiler = wl_compiler_init(arena); WL_Compiler *compiler = wl_compiler_init(arena);
@@ -1200,7 +1268,7 @@ static int compile(WL_String path, WL_Program *program, WL_Arena *arena)
for (int i = 0;; i++) { for (int i = 0;; i++) {
LoadedFile *loaded_file = load_file(path); LoadedFile *loaded_file = load_file((CWEB_String) { path.ptr, path.len });
if (loaded_file == NULL) { if (loaded_file == NULL) {
TRACE("Couldn't load file '%.*s'", path.len, path.ptr); TRACE("Couldn't load file '%.*s'", path.len, path.ptr);
free_loaded_files(loaded_file_head); free_loaded_files(loaded_file_head);
@@ -1221,7 +1289,7 @@ static int compile(WL_String path, WL_Program *program, WL_Arena *arena)
if (result.type == WL_ADD_LINK) break; if (result.type == WL_ADD_LINK) break;
assert(result.type == WL_ADD_AGAIN); ASSERT(result.type == WL_ADD_AGAIN);
path = result.path; path = result.path;
} }
@@ -1267,7 +1335,7 @@ static int query_routine(WL_Runtime *rt, SQLiteCache *dbcache)
else if (wl_arg_str(rt, i, &str)) else if (wl_arg_str(rt, i, &str))
ret = sqlite3_bind_text(stmt, i, str.ptr, str.len, NULL); ret = sqlite3_bind_text(stmt, i, str.ptr, str.len, NULL);
else { else {
assert(0); // TODO ASSERT(0); // TODO
} }
if (ret != SQLITE_OK) { if (ret != SQLITE_OK) {
@@ -1382,7 +1450,7 @@ static int get_or_create_program(TemplateCache *cache, WL_String path, WL_Arena
if (cache == NULL) if (cache == NULL)
return -1; return -1;
int i = lookup(cache, path); int i = template_cache_lookup(cache, path);
if (cache->pool[i].pathlen == -1) { if (cache->pool[i].pathlen == -1) {
WL_Program program; WL_Program program;
@@ -1406,9 +1474,11 @@ static int get_or_create_program(TemplateCache *cache, WL_String path, WL_Arena
*program = cache->pool[i].program; *program = cache->pool[i].program;
return 0; return 0;
} }
#endif
void cweb_respond_template(CWEB_Request *req, int status, CWEB_String template_file, int resource_id) void cweb_respond_template(CWEB_Request *req, int status, CWEB_String template_file, int resource_id)
{ {
#ifdef CWEB_ENABLE_TEMPLATE
http_response_builder_status(req->builder, status); http_response_builder_status(req->builder, status);
int ret = set_auth_cookie_if_necessary(req); int ret = set_auth_cookie_if_necessary(req);
if (ret < 0) { if (ret < 0) {
@@ -1419,7 +1489,7 @@ void cweb_respond_template(CWEB_Request *req, int status, CWEB_String template_f
} }
WL_Program program; WL_Program program;
int ret = get_or_create_program(req->cweb->tpcache, template_file, &req->arena, &program); ret = get_or_create_program(req->cweb->tpcache, (WL_String) { template_file.ptr, template_file.len }, &req->arena, &program);
if (ret < 0) { if (ret < 0) {
http_response_builder_undo(req->builder); http_response_builder_undo(req->builder);
http_response_builder_status(req->builder, 500); http_response_builder_status(req->builder, 500);
@@ -1470,4 +1540,8 @@ void cweb_respond_template(CWEB_Request *req, int status, CWEB_String template_f
break; break;
} }
} }
#else
http_response_builder_status(req->builder, 500);
http_response_builder_done(req->builder);
#endif
} }
+18 -15
View File
@@ -1,6 +1,9 @@
#include <stdint.h> #include <stdint.h>
#include <stdbool.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 { typedef struct {
@@ -134,16 +137,16 @@ CWEB_VArg cweb_varg_from_ps (short *ps);
CWEB_VArg cweb_varg_from_pi (int *pi); CWEB_VArg cweb_varg_from_pi (int *pi);
CWEB_VArg cweb_varg_from_pl (long *pl); CWEB_VArg cweb_varg_from_pl (long *pl);
CWEB_VArg cweb_varg_from_pll (long long *pll); CWEB_VArg cweb_varg_from_pll (long long *pll);
CWEB_VArg cweb_varg_from_psc (char *psc); CWEB_VArg cweb_varg_from_psc (signed char *psc);
CWEB_VArg cweb_varg_from_pss (short *pss); CWEB_VArg cweb_varg_from_pss (signed short *pss);
CWEB_VArg cweb_varg_from_psi (int *psi); CWEB_VArg cweb_varg_from_psi (signed int *psi);
CWEB_VArg cweb_varg_from_psl (long *psl); CWEB_VArg cweb_varg_from_psl (signed long *psl);
CWEB_VArg cweb_varg_from_psll (long long *psll); CWEB_VArg cweb_varg_from_psll (signed long long *psll);
CWEB_VArg cweb_varg_from_puc (char *puc); CWEB_VArg cweb_varg_from_puc (unsigned char *puc);
CWEB_VArg cweb_varg_from_pus (short *pus); CWEB_VArg cweb_varg_from_pus (unsigned short *pus);
CWEB_VArg cweb_varg_from_pui (int *pui); CWEB_VArg cweb_varg_from_pui (unsigned int *pui);
CWEB_VArg cweb_varg_from_pul (long *pul); CWEB_VArg cweb_varg_from_pul (unsigned long *pul);
CWEB_VArg cweb_varg_from_pull (long long *pull); CWEB_VArg cweb_varg_from_pull (unsigned long long *pull);
CWEB_VArg cweb_varg_from_pf (float *pf); CWEB_VArg cweb_varg_from_pf (float *pf);
CWEB_VArg cweb_varg_from_pd (double *pd); CWEB_VArg cweb_varg_from_pd (double *pd);
CWEB_VArg cweb_varg_from_pb (bool *pb); CWEB_VArg cweb_varg_from_pb (bool *pb);
@@ -229,14 +232,14 @@ CWEB_Request *cweb_wait(CWEB *cweb);
bool cweb_match_endpoint(CWEB_Request *req, CWEB_String str); bool cweb_match_endpoint(CWEB_Request *req, CWEB_String str);
// Returns the CSRF token associated to the current session // Returns the CSRF token associated to the current session
CWEB_String cweb_get_session_csrf(CWEB_Request *req); CWEB_String cweb_get_csrf(CWEB_Request *req);
// Returns the user ID for the current session, or -1 if there is no session // Returns the user ID for the current session, or -1 if there is no session
int cweb_get_session_user_id(CWEB_Request *req); int cweb_get_user_id(CWEB_Request *req);
// Sets the user ID for the current session (it must be a positive integer). // Sets the user ID for the current session (it must be a positive integer).
// If the ID is -1, the session is deleted. // If the ID is -1, the session is deleted.
int cweb_set_session_user_id(CWEB_Request *req, int user_id); int cweb_set_user_id(CWEB_Request *req, int user_id);
// Returns the request parameter with the specified name // Returns the request parameter with the specified name
// If the request uses POST, the parameter is taken from the body, // If the request uses POST, the parameter is taken from the body,
@@ -265,7 +268,7 @@ void cweb_respond_redirect(CWEB_Request *req, CWEB_String target);
void cweb_respond_template(CWEB_Request *req, int status, CWEB_String template_file, int resource_id); void cweb_respond_template(CWEB_Request *req, int status, CWEB_String template_file, int resource_id);
// Evaluates an SQL INSERT statement and returns the ID of the last inserted row. On error -1 is returned // 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, const char *fmt, CWEB_VArgs args); int64_t cweb_database_insert_impl(CWEB *cweb, char *fmt, CWEB_VArgs args);
// Helper // 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__))
@@ -275,7 +278,7 @@ typedef struct { void *handle; } CWEB_QueryResult;
// Evaluates an SQL SELECT statement, returning a scanner over the returned rows. // Evaluates an SQL SELECT statement, returning a scanner over the returned rows.
// You don't have to check for errors with this function // You don't have to check for errors with this function
CWEB_QueryResult cweb_database_select_impl(CWEB *cweb, const char *fmt, CWEB_VArgs args); CWEB_QueryResult cweb_database_select_impl(CWEB *cweb, char *fmt, CWEB_VArgs args);
// Helper // Helper
#define cweb_database_select(cweb, fmt, ...) cweb_database_select_impl((cweb), (fmt), CWEB_VARGS(__VA_ARGS__)) #define cweb_database_select(cweb, fmt, ...) cweb_database_select_impl((cweb), (fmt), CWEB_VARGS(__VA_ARGS__))