Reorganize files and fix compiler errors
This commit is contained in:
@@ -16,7 +16,7 @@ sqlite3.o: demo/sqlite3.c
|
||||
gcc -o $@ -c $<
|
||||
|
||||
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:
|
||||
rm *.o *.out *.exe
|
||||
|
||||
@@ -35,14 +35,8 @@ header.save("cweb.h")
|
||||
|
||||
source = Amalgamator()
|
||||
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_file("3p/chttp.h")
|
||||
source.append_file("3p/chttp.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/crypt_blowfish.h")
|
||||
source.append_file("src/crypt_blowfish.c")
|
||||
source.append_file("src/main.c")
|
||||
source.save("cweb.c")
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
#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 }
|
||||
|
||||
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_pl (long *pl);
|
||||
CWEB_VArg cweb_varg_from_pll (long long *pll);
|
||||
CWEB_VArg cweb_varg_from_psc (char *psc);
|
||||
CWEB_VArg cweb_varg_from_pss (short *pss);
|
||||
CWEB_VArg cweb_varg_from_psi (int *psi);
|
||||
CWEB_VArg cweb_varg_from_psl (long *psl);
|
||||
CWEB_VArg cweb_varg_from_psll (long long *psll);
|
||||
CWEB_VArg cweb_varg_from_puc (char *puc);
|
||||
CWEB_VArg cweb_varg_from_pus (short *pus);
|
||||
CWEB_VArg cweb_varg_from_pui (int *pui);
|
||||
CWEB_VArg cweb_varg_from_pul (long *pul);
|
||||
CWEB_VArg cweb_varg_from_pull (long long *pull);
|
||||
CWEB_VArg cweb_varg_from_psc (signed char *psc);
|
||||
CWEB_VArg cweb_varg_from_pss (signed short *pss);
|
||||
CWEB_VArg cweb_varg_from_psi (signed int *psi);
|
||||
CWEB_VArg cweb_varg_from_psl (signed long *psl);
|
||||
CWEB_VArg cweb_varg_from_psll (signed long long *psll);
|
||||
CWEB_VArg cweb_varg_from_puc (unsigned char *puc);
|
||||
CWEB_VArg cweb_varg_from_pus (unsigned short *pus);
|
||||
CWEB_VArg cweb_varg_from_pui (unsigned int *pui);
|
||||
CWEB_VArg cweb_varg_from_pul (unsigned long *pul);
|
||||
CWEB_VArg cweb_varg_from_pull (unsigned long long *pull);
|
||||
CWEB_VArg cweb_varg_from_pf (float *pf);
|
||||
CWEB_VArg cweb_varg_from_pd (double *pd);
|
||||
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);
|
||||
|
||||
// Pause execution until a request is available.
|
||||
// TODO: When does this function return NULL?
|
||||
CWEB_Request *cweb_wait(CWEB *cweb);
|
||||
|
||||
//////////////////////////////////////
|
||||
// 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
|
||||
|
||||
// Returns true iff the request matches the specified endpoint
|
||||
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);
|
||||
|
||||
// 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);
|
||||
|
||||
//////////////////////////////////////
|
||||
// Response
|
||||
|
||||
// Create a string by evaluating a format. Memory is allocated from the arena of the request.
|
||||
// If the arena is full, an empty string is returned.
|
||||
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__))
|
||||
|
||||
// Responds to the specified request with the given status code and 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);
|
||||
|
||||
// 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);
|
||||
|
||||
//////////////////////////////////////
|
||||
// Database
|
||||
|
||||
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);
|
||||
// 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__))
|
||||
|
||||
// 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__))
|
||||
|
||||
// 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__))
|
||||
|
||||
//////////////////////////////////////
|
||||
// Password
|
||||
// Frees the result of a database query
|
||||
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);
|
||||
|
||||
// Checks whether the password matches the given hash
|
||||
int cweb_check_password(char *pass, int passlen, CWEB_PasswordHash hash);
|
||||
#endif // CWEB_AMALGAMATION
|
||||
|
||||
@@ -1648,15 +1648,10 @@ HTTP_String http_get_param(HTTP_String body, HTTP_String str, char *mem, int cap
|
||||
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)
|
||||
{
|
||||
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]))
|
||||
return -1;
|
||||
|
||||
+25
-14
@@ -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)
|
||||
{
|
||||
if (cweb_get_session_user_id(req) != -1) {
|
||||
if (cweb_get_user_id(req) != -1) {
|
||||
cweb_respond_redirect(req, CWEB_STR("/index"));
|
||||
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>"));
|
||||
return;
|
||||
}
|
||||
if (cweb_set_session_user_id(req, ret) < 0) {
|
||||
if (cweb_set_user_id(req, ret) < 0) {
|
||||
// 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)
|
||||
{
|
||||
if (cweb_get_session_user_id(req) != -1) {
|
||||
if (cweb_get_user_id(req) != -1) {
|
||||
cweb_respond_redirect(req, CWEB_STR("/index"));
|
||||
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>"));
|
||||
return;
|
||||
}
|
||||
cweb_set_session_user_id(req, insert_id);
|
||||
cweb_set_user_id(req, insert_id);
|
||||
|
||||
cweb_respond_redirect(req, CWEB_STR("/index"));
|
||||
}
|
||||
|
||||
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"));
|
||||
}
|
||||
|
||||
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) {
|
||||
cweb_respond_redirect(req, CWEB_STR("/index"));
|
||||
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 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"));
|
||||
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)
|
||||
{
|
||||
int user_id = cweb_get_session_user_id(req);
|
||||
int user_id = cweb_get_user_id(req);
|
||||
if (user_id == -1) {
|
||||
cweb_respond_basic(req, 200, CWEB_STR("<div class=\"error\">You are not logged in</div>"));
|
||||
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 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>"));
|
||||
return;
|
||||
}
|
||||
@@ -299,12 +301,16 @@ static void endpoint_api_comment(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);
|
||||
}
|
||||
|
||||
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"));
|
||||
return;
|
||||
}
|
||||
@@ -314,7 +320,9 @@ static void endpoint_write(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"));
|
||||
return;
|
||||
}
|
||||
@@ -324,7 +332,9 @@ static void endpoint_login(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"));
|
||||
return;
|
||||
}
|
||||
@@ -340,8 +350,7 @@ static void endpoint_post(CWEB *cweb, CWEB_Request *req)
|
||||
return;
|
||||
}
|
||||
|
||||
CWEB_QueryResult res = cweb_database_select(cweb,
|
||||
"SELECT COUNT(*) FROM Posts WHERE id=?", post_id);
|
||||
CWEB_QueryResult res = cweb_database_select(cweb, "SELECT COUNT(*) FROM Posts WHERE id=?", post_id);
|
||||
|
||||
int num;
|
||||
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)
|
||||
{
|
||||
(void) cweb;
|
||||
|
||||
cweb_respond_template(req, 404, CWEB_STR("pages/notfound.wl"), -1);
|
||||
}
|
||||
|
||||
|
||||
+228
-154
@@ -1,7 +1,4 @@
|
||||
#include "sqlite3.h"
|
||||
#include "wl.h"
|
||||
#include "chttp.h"
|
||||
#include "cweb.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef __linux__
|
||||
#include <errno.h>
|
||||
@@ -12,6 +9,25 @@
|
||||
#include <windows.h>
|
||||
#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 {
|
||||
char path[1<<8];
|
||||
int pathlen;
|
||||
@@ -27,12 +43,16 @@ typedef struct {
|
||||
static TemplateCache *template_cache_init(int capacity_log2);
|
||||
static void template_cache_free(TemplateCache *cache);
|
||||
|
||||
#endif
|
||||
|
||||
typedef struct SessionStorage SessionStorage;
|
||||
|
||||
#ifdef CWEB_ENABLE_DATABASE
|
||||
|
||||
typedef struct SQLiteCache SQLiteCache;
|
||||
|
||||
static SQLiteCache* sqlite_cache_init(sqlite3 *db, int capacity_log2);
|
||||
static void sqlite_cache_free(SQLiteCache *cache);
|
||||
static sqlite3* sqlite_cache_getdb(SQLiteCache *cache);
|
||||
|
||||
static int sqlite3utils_prepare(SQLiteCache *cache,
|
||||
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, ...) \
|
||||
sqlite3utils_prepare_and_bind_impl((cache), (pstmt), (fmt), VARGS(__VA_ARGS__))
|
||||
|
||||
struct CWEB {
|
||||
|
||||
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;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct CWEB_Request {
|
||||
|
||||
@@ -80,6 +81,29 @@ struct CWEB_Request {
|
||||
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)
|
||||
@@ -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_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_psc (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_psi (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_psll (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_pus (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_pul (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_psc (signed char *psc) { return (CWEB_VArg) { CWEB_VARG_TYPE_PSC, .psc=psc }; }
|
||||
CWEB_VArg cweb_varg_from_pss (signed short *pss) { return (CWEB_VArg) { CWEB_VARG_TYPE_PSS, .pss=pss }; }
|
||||
CWEB_VArg cweb_varg_from_psi (signed int *psi) { return (CWEB_VArg) { CWEB_VARG_TYPE_PSI, .psi=psi }; }
|
||||
CWEB_VArg cweb_varg_from_psl (signed long *psl) { return (CWEB_VArg) { CWEB_VARG_TYPE_PSL, .psl=psl }; }
|
||||
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 (unsigned char *puc) { return (CWEB_VArg) { CWEB_VARG_TYPE_PUC, .puc=puc }; }
|
||||
CWEB_VArg cweb_varg_from_pus (unsigned short *pus) { return (CWEB_VArg) { CWEB_VARG_TYPE_PUS, .pus=pus }; }
|
||||
CWEB_VArg cweb_varg_from_pui (unsigned int *pui) { return (CWEB_VArg) { CWEB_VARG_TYPE_PUI, .pui=pui }; }
|
||||
CWEB_VArg cweb_varg_from_pul (unsigned long *pul) { return (CWEB_VArg) { CWEB_VARG_TYPE_PUL, .pul=pul }; }
|
||||
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_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_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 }; }
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// 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
|
||||
////////////////////////////////////////////////////////////////
|
||||
@@ -242,7 +338,7 @@ static int hex_digit_to_int(char c)
|
||||
|
||||
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++) {
|
||||
static const char table[] = "0123456789abcdef";
|
||||
@@ -258,7 +354,7 @@ static int pack_token(char *src, int srclen, char *dst, int dstlen)
|
||||
if (srclen & 1)
|
||||
return -1;
|
||||
|
||||
assert(srclen == 2 * dstlen);
|
||||
ASSERT(srclen == 2 * dstlen);
|
||||
|
||||
for (int i = 0; i < srclen; i += 2) {
|
||||
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);
|
||||
if (found == NULL)
|
||||
return false;
|
||||
assert(found->user >= 0);
|
||||
ASSERT(found->user >= 0);
|
||||
found->user = -2;
|
||||
storage->count--;
|
||||
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);
|
||||
if (found == NULL)
|
||||
return -1;
|
||||
assert(found->user >= 0);
|
||||
ASSERT(found->user >= 0);
|
||||
*pcsrf = (CWEB_String) { found->csrf, CSRF_TOKEN_SIZE };
|
||||
*puser = found->user;
|
||||
return 0;
|
||||
@@ -402,6 +498,8 @@ static int find_session(SessionStorage *storage, CWEB_String sess, CWEB_String *
|
||||
// DATABASE
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef CWEB_ENABLE_DATABASE
|
||||
|
||||
typedef struct {
|
||||
char *str;
|
||||
int len;
|
||||
@@ -443,11 +541,6 @@ static void sqlite_cache_free(SQLiteCache *cache)
|
||||
free(cache);
|
||||
}
|
||||
|
||||
static sqlite3 *sqlite_cache_getdb(SQLiteCache *cache)
|
||||
{
|
||||
return cache->db;
|
||||
}
|
||||
|
||||
static unsigned long djb2(char *src, int len)
|
||||
{
|
||||
char *ptr = src;
|
||||
@@ -460,7 +553,7 @@ static unsigned long djb2(char *src, int len)
|
||||
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 hash = djb2(fmt, fmtlen);
|
||||
@@ -486,7 +579,7 @@ static int sqlite3utils_prepare(SQLiteCache *cache, sqlite3_stmt **pstmt, char *
|
||||
if (fmtlen < 0)
|
||||
fmtlen = strlen(fmt);
|
||||
|
||||
int i = lookup(cache, fmt, fmtlen);
|
||||
int i = sqlite_cache_lookup(cache, fmt, fmtlen);
|
||||
if (cache->items[i].stmt == NULL) {
|
||||
|
||||
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_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;
|
||||
default:
|
||||
// TODO
|
||||
break;
|
||||
}
|
||||
if (ret != SQLITE_OK) {
|
||||
sqlite3_reset(stmt);
|
||||
@@ -554,8 +650,11 @@ static int sqlite3utils_prepare_and_bind_impl(SQLiteCache *cache,
|
||||
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;
|
||||
int ret = sqlite3utils_prepare_and_bind_impl(cweb->dbcache, &stmt, fmt, args);
|
||||
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);
|
||||
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;
|
||||
int ret = sqlite3utils_prepare_and_bind_impl(cweb->dbcache, &stmt, fmt, args);
|
||||
if (ret != SQLITE_OK)
|
||||
return (CWEB_QueryResult) { NULL };
|
||||
|
||||
return (CWEB_QueryResult) { stmt };
|
||||
#else
|
||||
return (CWEB_QueryResult) { NULL };
|
||||
#endif
|
||||
}
|
||||
|
||||
int cweb_next_query_row_impl(CWEB_QueryResult *res, CWEB_VArgs args)
|
||||
{
|
||||
#ifdef CWEB_ENABLE_DATABASE
|
||||
if (res->handle == NULL)
|
||||
return -1;
|
||||
|
||||
@@ -674,19 +781,30 @@ int cweb_next_query_row_impl(CWEB_QueryResult *res, CWEB_VArgs args)
|
||||
}
|
||||
|
||||
return 1;
|
||||
#else
|
||||
(void) res;
|
||||
(void) args;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void cweb_free_query_result(CWEB_QueryResult *res)
|
||||
{
|
||||
#ifdef CWEB_ENABLE_DATABASE
|
||||
if (res->handle) {
|
||||
sqlite3_reset(res->handle);
|
||||
res->handle = NULL;
|
||||
}
|
||||
#else
|
||||
(void) res;
|
||||
#endif
|
||||
}
|
||||
|
||||
int cweb_global_init(void)
|
||||
{
|
||||
http_global_init();
|
||||
if (http_global_init())
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cweb_global_free(void)
|
||||
@@ -694,7 +812,7 @@ void cweb_global_free(void)
|
||||
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.
|
||||
// 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));
|
||||
if (cweb == NULL)
|
||||
return -1;
|
||||
return NULL;
|
||||
|
||||
cweb->pool_cap = 1<<20;
|
||||
cweb->pool = malloc(cweb->pool_cap);
|
||||
if (cweb->pool == NULL) {
|
||||
free(cweb);
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef CWEB_ENABLE_TEMPLATE
|
||||
cweb->tpcache = template_cache_init(4);
|
||||
if (cweb->tpcache == NULL) {
|
||||
free(cweb->pool);
|
||||
free(cweb);
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
cweb->session_storage = session_storage_init(1024);
|
||||
if (cweb->session_storage == NULL) {
|
||||
#ifdef CWEB_ENABLE_TEMPLATE
|
||||
template_cache_free(cweb->tpcache);
|
||||
#endif
|
||||
free(cweb->pool);
|
||||
free(cweb);
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cweb->server = http_server_init((HTTP_String) { addr.ptr, addr.len }, port);
|
||||
if (cweb->server == NULL) {
|
||||
session_storage_free(cweb->session_storage);
|
||||
#ifdef CWEB_ENABLE_TEMPLATE
|
||||
template_cache_free(cweb->tpcache);
|
||||
#endif
|
||||
free(cweb->pool);
|
||||
free(cweb);
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef CWEB_ENABLE_DATABASE
|
||||
cweb->db = NULL;
|
||||
cweb->dbcache = NULL;
|
||||
#endif
|
||||
|
||||
cweb->allow_insecure_login = false;
|
||||
|
||||
return 0;
|
||||
return cweb;
|
||||
}
|
||||
|
||||
void cweb_free(CWEB *cweb)
|
||||
{
|
||||
http_server_free(cweb->server);
|
||||
session_storage_free(cweb->session_storage);
|
||||
#ifdef CWEB_ENABLE_TEMPLATE
|
||||
template_cache_free(cweb->tpcache);
|
||||
#endif
|
||||
#ifdef CWEB_ENABLE_DATABASE
|
||||
if (cweb->db) {
|
||||
sqlite_cache_free(cweb->dbcache);
|
||||
sqlite3_close(cweb->db);
|
||||
}
|
||||
#endif
|
||||
free(cweb);
|
||||
}
|
||||
|
||||
@@ -765,6 +895,7 @@ void cweb_version(void)
|
||||
|
||||
int cweb_enable_database(CWEB *cweb, CWEB_String file)
|
||||
{
|
||||
#ifdef CWEB_ENABLE_DATABASE
|
||||
if (cweb->db != NULL)
|
||||
return -1; // Already enabled
|
||||
|
||||
@@ -781,23 +912,21 @@ int cweb_enable_database(CWEB *cweb, CWEB_String file)
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *schema_data;
|
||||
long schema_size;
|
||||
ret = load_file(file_copy, &schema_data, &schema_size);
|
||||
if (ret < 0) {
|
||||
LoadedFile *schema = load_file(file);
|
||||
if (schema == NULL) {
|
||||
sqlite3_close(cweb->db);
|
||||
cweb->db = NULL;
|
||||
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) {
|
||||
sqlite3_close(cweb->db);
|
||||
cweb->db = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(schema_data);
|
||||
free_loaded_files(schema);
|
||||
|
||||
cweb->dbcache = sqlite_cache_init(cweb->db, 5);
|
||||
if (cweb->dbcache == NULL) {
|
||||
@@ -807,6 +936,9 @@ int cweb_enable_database(CWEB *cweb, CWEB_String file)
|
||||
}
|
||||
|
||||
return 0;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
CWEB_Request *cweb_wait(CWEB *cweb)
|
||||
@@ -814,12 +946,15 @@ CWEB_Request *cweb_wait(CWEB *cweb)
|
||||
CWEB_Request *req = &cweb->req;
|
||||
|
||||
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->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) {
|
||||
req->user_id = -1;
|
||||
req->sess = (CWEB_String) { NULL, 0 };
|
||||
@@ -871,9 +1006,9 @@ static int set_auth_cookie_if_necessary(CWEB_Request *req)
|
||||
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);
|
||||
if (ret < 0) {
|
||||
http_response_builder_undo(req->builder);
|
||||
@@ -909,6 +1044,11 @@ static void append_to_output_s64(StaticOutputBuffer *out, int64_t n)
|
||||
// TODO
|
||||
}
|
||||
|
||||
static void append_to_output_f64(StaticOutputBuffer *out, double n)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
static void append_to_output_ptr(StaticOutputBuffer *out, void *p)
|
||||
{
|
||||
// TODO
|
||||
@@ -986,7 +1126,7 @@ static void evaluate_format(StaticOutputBuffer *out, CWEB_String format, CWEB_VA
|
||||
cur++;
|
||||
|
||||
if (cur < len) {
|
||||
assert(src[cur] == '}');
|
||||
ASSERT(src[cur] == '}');
|
||||
cur++;
|
||||
}
|
||||
|
||||
@@ -996,7 +1136,7 @@ static void evaluate_format(StaticOutputBuffer *out, CWEB_String format, CWEB_VA
|
||||
}
|
||||
|
||||
} else {
|
||||
assert(src[cur-1] == '\\');
|
||||
ASSERT(src[cur-1] == '\\');
|
||||
if (cur < len) {
|
||||
append_to_output(out, &src[cur], 1);
|
||||
cur++;
|
||||
@@ -1065,9 +1205,15 @@ int cweb_get_user_id(CWEB_Request *req)
|
||||
return req->user_id;
|
||||
}
|
||||
|
||||
CWEB_String cweb_get_csrf(CWEB_Request *req)
|
||||
{
|
||||
return req->csrf;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// TEMPLATE
|
||||
////////////////////////////////////////////////////////////////
|
||||
#ifdef CWEB_ENABLE_TEMPLATE
|
||||
|
||||
static TemplateCache *template_cache_init(int capacity_log2)
|
||||
{
|
||||
@@ -1088,22 +1234,10 @@ static void template_cache_free(TemplateCache *cache)
|
||||
free(cache);
|
||||
}
|
||||
|
||||
static unsigned long djb2(WL_String str)
|
||||
{
|
||||
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)
|
||||
static int template_cache_lookup(TemplateCache *cache, WL_String path)
|
||||
{
|
||||
int mask = (1 << cache->capacity_log2) - 1;
|
||||
int hash = djb2(path);
|
||||
int hash = djb2(path.ptr, path.len);
|
||||
int i = hash & mask;
|
||||
int perturb = hash;
|
||||
for (;;) {
|
||||
@@ -1121,72 +1255,6 @@ static int lookup(TemplateCache *cache, WL_String path)
|
||||
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)
|
||||
{
|
||||
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++) {
|
||||
|
||||
LoadedFile *loaded_file = load_file(path);
|
||||
LoadedFile *loaded_file = load_file((CWEB_String) { path.ptr, path.len });
|
||||
if (loaded_file == NULL) {
|
||||
TRACE("Couldn't load file '%.*s'", path.len, path.ptr);
|
||||
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;
|
||||
|
||||
assert(result.type == WL_ADD_AGAIN);
|
||||
ASSERT(result.type == WL_ADD_AGAIN);
|
||||
path = result.path;
|
||||
}
|
||||
|
||||
@@ -1267,7 +1335,7 @@ static int query_routine(WL_Runtime *rt, SQLiteCache *dbcache)
|
||||
else if (wl_arg_str(rt, i, &str))
|
||||
ret = sqlite3_bind_text(stmt, i, str.ptr, str.len, NULL);
|
||||
else {
|
||||
assert(0); // TODO
|
||||
ASSERT(0); // TODO
|
||||
}
|
||||
|
||||
if (ret != SQLITE_OK) {
|
||||
@@ -1382,7 +1450,7 @@ static int get_or_create_program(TemplateCache *cache, WL_String path, WL_Arena
|
||||
if (cache == NULL)
|
||||
return -1;
|
||||
|
||||
int i = lookup(cache, path);
|
||||
int i = template_cache_lookup(cache, path);
|
||||
if (cache->pool[i].pathlen == -1) {
|
||||
|
||||
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;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
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);
|
||||
int ret = set_auth_cookie_if_necessary(req);
|
||||
if (ret < 0) {
|
||||
@@ -1419,7 +1489,7 @@ void cweb_respond_template(CWEB_Request *req, int status, CWEB_String template_f
|
||||
}
|
||||
|
||||
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) {
|
||||
http_response_builder_undo(req->builder);
|
||||
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;
|
||||
}
|
||||
}
|
||||
#else
|
||||
http_response_builder_status(req->builder, 500);
|
||||
http_response_builder_done(req->builder);
|
||||
#endif
|
||||
}
|
||||
|
||||
+18
-15
@@ -1,6 +1,9 @@
|
||||
#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 }
|
||||
|
||||
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_pl (long *pl);
|
||||
CWEB_VArg cweb_varg_from_pll (long long *pll);
|
||||
CWEB_VArg cweb_varg_from_psc (char *psc);
|
||||
CWEB_VArg cweb_varg_from_pss (short *pss);
|
||||
CWEB_VArg cweb_varg_from_psi (int *psi);
|
||||
CWEB_VArg cweb_varg_from_psl (long *psl);
|
||||
CWEB_VArg cweb_varg_from_psll (long long *psll);
|
||||
CWEB_VArg cweb_varg_from_puc (char *puc);
|
||||
CWEB_VArg cweb_varg_from_pus (short *pus);
|
||||
CWEB_VArg cweb_varg_from_pui (int *pui);
|
||||
CWEB_VArg cweb_varg_from_pul (long *pul);
|
||||
CWEB_VArg cweb_varg_from_pull (long long *pull);
|
||||
CWEB_VArg cweb_varg_from_psc (signed char *psc);
|
||||
CWEB_VArg cweb_varg_from_pss (signed short *pss);
|
||||
CWEB_VArg cweb_varg_from_psi (signed int *psi);
|
||||
CWEB_VArg cweb_varg_from_psl (signed long *psl);
|
||||
CWEB_VArg cweb_varg_from_psll (signed long long *psll);
|
||||
CWEB_VArg cweb_varg_from_puc (unsigned char *puc);
|
||||
CWEB_VArg cweb_varg_from_pus (unsigned short *pus);
|
||||
CWEB_VArg cweb_varg_from_pui (unsigned int *pui);
|
||||
CWEB_VArg cweb_varg_from_pul (unsigned long *pul);
|
||||
CWEB_VArg cweb_varg_from_pull (unsigned long long *pull);
|
||||
CWEB_VArg cweb_varg_from_pf (float *pf);
|
||||
CWEB_VArg cweb_varg_from_pd (double *pd);
|
||||
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);
|
||||
|
||||
// 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
|
||||
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).
|
||||
// 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
|
||||
// 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);
|
||||
|
||||
// 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
|
||||
#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.
|
||||
// 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
|
||||
#define cweb_database_select(cweb, fmt, ...) cweb_database_select_impl((cweb), (fmt), CWEB_VARGS(__VA_ARGS__))
|
||||
|
||||
Reference in New Issue
Block a user