Make a big amalgamation of HTTP, WL, sqlite alongside cweb
This commit is contained in:
+34
-2
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
#ifndef WL_NOINCLUDE
|
#ifndef WL_NOINCLUDE
|
||||||
#include "wl.h"
|
#include "wl.h"
|
||||||
#endif // WL_NOINCLUDE
|
#endif
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////
|
||||||
// BASIC
|
// BASIC
|
||||||
@@ -3588,7 +3588,7 @@ WL_Compiler *wl_compiler_init(WL_Arena *arena)
|
|||||||
return compiler;
|
return compiler;
|
||||||
}
|
}
|
||||||
|
|
||||||
WL_AddResult wl_compiler_add(WL_Compiler *compiler, WL_String content)
|
WL_AddResult wl_compiler_add(WL_Compiler *compiler, WL_String path, WL_String content)
|
||||||
{
|
{
|
||||||
if (compiler->err)
|
if (compiler->err)
|
||||||
return (WL_AddResult) { .type=WL_ADD_ERROR };
|
return (WL_AddResult) { .type=WL_ADD_ERROR };
|
||||||
@@ -3599,6 +3599,38 @@ WL_AddResult wl_compiler_add(WL_Compiler *compiler, WL_String content)
|
|||||||
return (WL_AddResult) { .type=WL_ADD_ERROR };
|
return (WL_AddResult) { .type=WL_ADD_ERROR };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make include paths relative to the parent file
|
||||||
|
if (path.len > 0) {
|
||||||
|
|
||||||
|
String parent = { path.ptr, path.len };
|
||||||
|
|
||||||
|
char sep = '/';
|
||||||
|
while (parent.len > 0 && parent.ptr[parent.len-1] != sep)
|
||||||
|
parent.len--;
|
||||||
|
|
||||||
|
if (parent.len > 0) {
|
||||||
|
Node *include = pres.includes;
|
||||||
|
while (include) {
|
||||||
|
|
||||||
|
char *dst = alloc(compiler->arena, parent.len + include->include_path.len + 1, 1);
|
||||||
|
if (dst == NULL) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(dst,
|
||||||
|
parent.ptr,
|
||||||
|
parent.len);
|
||||||
|
memcpy(dst + parent.len,
|
||||||
|
include->include_path.ptr,
|
||||||
|
include->include_path.len);
|
||||||
|
|
||||||
|
include->include_path = (String) { dst, parent.len + include->include_path.len };
|
||||||
|
|
||||||
|
include = include->include_next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CompiledFile compiled_file = {
|
CompiledFile compiled_file = {
|
||||||
.file = compiler->waiting_file,
|
.file = compiler->waiting_file,
|
||||||
.root = pres.node,
|
.root = pres.node,
|
||||||
+1
-1
@@ -46,7 +46,7 @@ typedef struct {
|
|||||||
} WL_EvalResult;
|
} WL_EvalResult;
|
||||||
|
|
||||||
WL_Compiler* wl_compiler_init (WL_Arena *arena);
|
WL_Compiler* wl_compiler_init (WL_Arena *arena);
|
||||||
WL_AddResult wl_compiler_add (WL_Compiler *compiler, WL_String content);
|
WL_AddResult wl_compiler_add (WL_Compiler *compiler, WL_String path, WL_String content);
|
||||||
int wl_compiler_link (WL_Compiler *compiler, WL_Program *program);
|
int wl_compiler_link (WL_Compiler *compiler, WL_Program *program);
|
||||||
WL_String wl_compiler_error (WL_Compiler *compiler);
|
WL_String wl_compiler_error (WL_Compiler *compiler);
|
||||||
int wl_dump_ast (WL_Compiler *compiler, char *dst, int cap);
|
int wl_dump_ast (WL_Compiler *compiler, char *dst, int cap);
|
||||||
@@ -12,11 +12,8 @@ all: cweb.c cweb.h cozisnews$(EXT)
|
|||||||
cweb.c cweb.h: src/main.c src/main.h
|
cweb.c cweb.h: src/main.c src/main.h
|
||||||
python amalg.py
|
python amalg.py
|
||||||
|
|
||||||
sqlite3.o: demo/sqlite3.c
|
cozisnews$(EXT): demo/main.c cweb.c cweb.h
|
||||||
gcc -o $@ -c $<
|
gcc -o $@ demo/main.c cweb.c $(FLAGS)
|
||||||
|
|
||||||
cozisnews$(EXT): demo/main.c cweb.c cweb.h sqlite3.o
|
|
||||||
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
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ class Amalgamator:
|
|||||||
self.out += "// " + file + "\n"
|
self.out += "// " + file + "\n"
|
||||||
self.out += "////////////////////////////////////////////////////////////////////////////////////////\n"
|
self.out += "////////////////////////////////////////////////////////////////////////////////////////\n"
|
||||||
self.out += "\n"
|
self.out += "\n"
|
||||||
#self.out += "#line 1 \"" + file + "\"\n"
|
self.out += "#line 1 \"" + file + "\"\n"
|
||||||
self.out += open(file).read()
|
self.out += open(file).read()
|
||||||
|
|
||||||
if len(self.out) > 0 and self.out[len(self.out)-1] != '\n':
|
if len(self.out) > 0 and self.out[len(self.out)-1] != '\n':
|
||||||
@@ -35,8 +35,55 @@ 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 CRYPT_BLOWFISH_NOINCLUDE")
|
source.append_text("#define WL_NOINCLUDE\n")
|
||||||
source.append_file("src/crypt_blowfish.h")
|
source.append_text("#define HTTP_NOINCLUDE\n")
|
||||||
source.append_file("src/crypt_blowfish.c")
|
source.append_text("#define CRYPT_BLOWFISH_NOINCLUDE\n")
|
||||||
|
|
||||||
|
source.append_file("3p/chttp.h")
|
||||||
|
source.append_file("3p/chttp.c")
|
||||||
|
|
||||||
|
source.append_text("#undef MIN\n")
|
||||||
|
source.append_text("#undef MAX\n")
|
||||||
|
source.append_text("#undef ASSERT\n")
|
||||||
|
source.append_text("#undef SIZEOF\n")
|
||||||
|
source.append_text("#undef TRACE\n")
|
||||||
|
|
||||||
|
source.append_file("3p/sqlite3.c")
|
||||||
|
|
||||||
|
source.append_text("#undef MIN\n")
|
||||||
|
source.append_text("#undef MAX\n")
|
||||||
|
source.append_text("#undef ASSERT\n")
|
||||||
|
source.append_text("#undef SIZEOF\n")
|
||||||
|
source.append_text("#undef TRACE\n")
|
||||||
|
|
||||||
|
source.append_text("#define Scanner WL_Scanner\n")
|
||||||
|
source.append_text("#define Token WL_Token\n")
|
||||||
|
source.append_text("#define is_space is_space__wl\n")
|
||||||
|
source.append_text("#define is_digit is_digit__wl\n")
|
||||||
|
source.append_text("#define is_alpha is_alpha__wl\n")
|
||||||
|
source.append_text("#define is_printable is_printable__wl\n")
|
||||||
|
source.append_text("#define is_hex_digit is_hex_digit__wl\n")
|
||||||
|
source.append_text("#define hex_digit_to_int hex_digit_to_int__wl\n")
|
||||||
|
source.append_text("#define consume_str consume_str__wl\n")
|
||||||
|
|
||||||
|
source.append_file("3p/wl.h")
|
||||||
|
source.append_file("3p/wl.c")
|
||||||
|
|
||||||
|
source.append_text("#undef Scanner\n")
|
||||||
|
source.append_text("#undef Token\n")
|
||||||
|
source.append_text("#undef is_space\n")
|
||||||
|
source.append_text("#undef is_digit\n")
|
||||||
|
source.append_text("#undef is_alpha\n")
|
||||||
|
source.append_text("#undef is_printable\n")
|
||||||
|
source.append_text("#undef is_hex_digit\n")
|
||||||
|
source.append_text("#undef hex_digit_to_int\n")
|
||||||
|
|
||||||
|
source.append_text("#undef MIN\n")
|
||||||
|
source.append_text("#undef MAX\n")
|
||||||
|
source.append_text("#undef ASSERT\n")
|
||||||
|
source.append_text("#undef SIZEOF\n")
|
||||||
|
|
||||||
|
source.append_file("3p/crypt_blowfish.h")
|
||||||
|
source.append_file("3p/crypt_blowfish.c")
|
||||||
source.append_file("src/main.c")
|
source.append_file("src/main.c")
|
||||||
source.save("cweb.c")
|
source.save("cweb.c")
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
// src/main.h
|
// src/main.h
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#line 1 "src/main.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
@@ -231,7 +232,12 @@ void cweb_global_free(void);
|
|||||||
CWEB *cweb_init(CWEB_String addr, uint16_t port);
|
CWEB *cweb_init(CWEB_String addr, uint16_t port);
|
||||||
void cweb_free(CWEB *cweb);
|
void cweb_free(CWEB *cweb);
|
||||||
|
|
||||||
int cweb_enable_database(CWEB *cweb, CWEB_String file);
|
// Open an SQLite instance in file "database_file" and run the DDL script at "schema_file".
|
||||||
|
// Note that "database_file" may be ":memory:".
|
||||||
|
int cweb_enable_database(CWEB *cweb, CWEB_String database_file, CWEB_String schema_file);
|
||||||
|
|
||||||
|
// Log all evaluated SQL statements to stdout
|
||||||
|
void cweb_trace_sql(CWEB *cweb, bool enable);
|
||||||
|
|
||||||
// Pause execution until a request is available.
|
// Pause execution until a request is available.
|
||||||
// TODO: When does this function return NULL?
|
// TODO: When does this function return NULL?
|
||||||
@@ -302,8 +308,8 @@ int cweb_next_query_row_impl(CWEB_QueryResult *res, CWEB_VArgs args);
|
|||||||
void cweb_free_query_result(CWEB_QueryResult *res);
|
void cweb_free_query_result(CWEB_QueryResult *res);
|
||||||
|
|
||||||
// Calculates the bcrypt hash of the specified password
|
// 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(CWEB_String pass, int cost, CWEB_PasswordHash *hash);
|
||||||
|
|
||||||
// Checks whether the password matches the given hash
|
// Checks whether the password matches the given hash
|
||||||
int cweb_check_password(char *pass, int passlen, CWEB_PasswordHash hash);
|
int cweb_check_password(CWEB_String pass, CWEB_PasswordHash hash);
|
||||||
#endif // CWEB_AMALGAMATION
|
#endif // CWEB_AMALGAMATION
|
||||||
|
|||||||
+50
-96
@@ -1,68 +1,7 @@
|
|||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
#include "cweb.h"
|
#include "cweb.h"
|
||||||
|
|
||||||
#if 0
|
|
||||||
#define WL_STR(X) ((WL_String) { (X), (int) sizeof(X)-1})
|
|
||||||
|
|
||||||
#define HTML_STR(X) html_str(HTTP_STR(#X))
|
|
||||||
|
|
||||||
static CWEB_String html_str(CWEB_String str)
|
|
||||||
{
|
|
||||||
str = cweb_trim(str);
|
|
||||||
if (str.len > 0 && str.ptr[0] == '(') {
|
|
||||||
str.ptr++;
|
|
||||||
str.len--;
|
|
||||||
}
|
|
||||||
if (str.len > 0 && str.ptr[str.len-1] == ')')
|
|
||||||
str.len--;
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
int load_file(char *file, char **data, long *size)
|
|
||||||
{
|
|
||||||
FILE *f = fopen(file, "rb");
|
|
||||||
if (f == NULL) return -1;
|
|
||||||
|
|
||||||
fseek(f, 0, SEEK_END);
|
|
||||||
*size = ftell(f);
|
|
||||||
fseek(f, 0, SEEK_SET);
|
|
||||||
|
|
||||||
*data = malloc(*size + 1);
|
|
||||||
|
|
||||||
fread(*data, 1, *size, f);
|
|
||||||
(*data)[*size] = '\0';
|
|
||||||
|
|
||||||
fclose(f);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *alloc(WL_Arena *arena, int num, int align)
|
|
||||||
{
|
|
||||||
int pad = -(uintptr_t) (arena->ptr + arena->cur) & (align-1);
|
|
||||||
if (arena->len - arena->cur < num + pad)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
void *ptr = arena->ptr + arena->cur + pad;
|
|
||||||
arena->cur += num + pad;
|
|
||||||
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool is_hex_digit(char c)
|
|
||||||
{
|
|
||||||
return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f');
|
|
||||||
}
|
|
||||||
|
|
||||||
static int hex_digit_to_int(char c)
|
|
||||||
{
|
|
||||||
if (c >= 'A' && c <= 'F')
|
|
||||||
return c - 'A' + 10;
|
|
||||||
if (c >= 'a' && c <= 'f')
|
|
||||||
return c - 'a' + 10;
|
|
||||||
return c - '0';
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#define USERNAME_LIMIT 64
|
#define USERNAME_LIMIT 64
|
||||||
|
|
||||||
bool valid_name(CWEB_String str)
|
bool valid_name(CWEB_String str)
|
||||||
@@ -125,14 +64,14 @@ static int user_exists(CWEB *cweb, CWEB_String name, CWEB_String pass)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = cweb_check_password(pass.ptr, pass.len, hash);
|
ret = cweb_check_password(pass, hash);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
cweb_free_query_result(&res);
|
cweb_free_query_result(&res);
|
||||||
return -500;
|
return -1;
|
||||||
}
|
}
|
||||||
if (ret > 0) {
|
if (ret > 0) {
|
||||||
cweb_free_query_result(&res);
|
cweb_free_query_result(&res);
|
||||||
return -400;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return user_id;
|
return user_id;
|
||||||
@@ -148,17 +87,22 @@ static void endpoint_api_login(CWEB *cweb, CWEB_Request *req)
|
|||||||
CWEB_String name = cweb_get_param_s(req, CWEB_STR("username"));
|
CWEB_String name = cweb_get_param_s(req, CWEB_STR("username"));
|
||||||
CWEB_String pass = cweb_get_param_s(req, CWEB_STR("password"));
|
CWEB_String pass = cweb_get_param_s(req, CWEB_STR("password"));
|
||||||
if (!valid_name(name) || !valid_pass(pass)) {
|
if (!valid_name(name) || !valid_pass(pass)) {
|
||||||
cweb_respond_basic(req, 200, CWEB_STR("<div class=\"error\">Invalid credentials</div>"));
|
cweb_respond_basic(req, 400, CWEB_STR("Invalid credentials"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ret = user_exists(cweb, name, pass);
|
int ret = user_exists(cweb, name, pass);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
cweb_respond_basic(req, 200, CWEB_STR("<div class=\"error\">Invalid credentials</div>"));
|
cweb_respond_basic(req, 500, CWEB_STR("Internal error"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ret == 0) {
|
||||||
|
cweb_respond_basic(req, 400, CWEB_STR("Invalid credentials"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (cweb_set_user_id(req, ret) < 0) {
|
if (cweb_set_user_id(req, ret) < 0) {
|
||||||
// TODO
|
cweb_respond_basic(req, 500, CWEB_STR("Internal error"));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cweb_respond_redirect(req, CWEB_STR("/index"));
|
cweb_respond_redirect(req, CWEB_STR("/index"));
|
||||||
@@ -177,29 +121,32 @@ static void endpoint_api_signup(CWEB *cweb, CWEB_Request *req)
|
|||||||
CWEB_String pass2 = cweb_get_param_s(req, CWEB_STR("password2"));
|
CWEB_String pass2 = cweb_get_param_s(req, CWEB_STR("password2"));
|
||||||
|
|
||||||
if (!valid_name(name) || !valid_email(email) || !valid_pass(pass1)) {
|
if (!valid_name(name) || !valid_email(email) || !valid_pass(pass1)) {
|
||||||
cweb_respond_basic(req, 200, CWEB_STR("<div class=\"error\">Invalid credentials</div>"));
|
cweb_respond_basic(req, 400, CWEB_STR("Invalid credentials"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cweb_streq(pass1, pass2)) {
|
if (!cweb_streq(pass1, pass2)) {
|
||||||
cweb_respond_basic(req, 200, CWEB_STR("<div class=\"error\">The password was repeated incorrectly</div>"));
|
cweb_respond_basic(req, 400, CWEB_STR("The password was repeated incorrectly"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CWEB_PasswordHash hash;
|
CWEB_PasswordHash hash;
|
||||||
int ret = cweb_hash_password(pass1.ptr, pass1.len, 12, &hash);
|
int ret = cweb_hash_password(pass1, 12, &hash);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
cweb_respond_basic(req, 400, CWEB_STR("<div class=\"error\">Internal error</div>"));
|
cweb_respond_basic(req, 500, CWEB_STR("Internal error"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t insert_id = cweb_database_insert(cweb, "INSERT INTO Users(username, email, hash) VALUES (?, ?, ?)", name, email, hash);
|
int64_t insert_id = cweb_database_insert(cweb, "INSERT INTO Users(username, email, hash) VALUES (?, ?, ?)", name, email, hash);
|
||||||
if (insert_id < 0) {
|
if (insert_id < 0) {
|
||||||
// TODO: What if the user exists?
|
// TODO: What if the user exists?
|
||||||
cweb_respond_basic(req, 400, CWEB_STR("<div class=\"error\">Internal error</div>"));
|
cweb_respond_basic(req, 500, CWEB_STR("Internal error"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (cweb_set_user_id(req, insert_id) < 0) {
|
||||||
|
cweb_respond_basic(req, 500, CWEB_STR("Internal error"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
cweb_set_user_id(req, insert_id);
|
|
||||||
|
|
||||||
cweb_respond_redirect(req, CWEB_STR("/index"));
|
cweb_respond_redirect(req, CWEB_STR("/index"));
|
||||||
}
|
}
|
||||||
@@ -229,19 +176,16 @@ static void endpoint_api_post(CWEB *cweb, CWEB_Request *req)
|
|||||||
cweb_respond_basic(req, 400, CWEB_STR("Invalid request"));
|
cweb_respond_basic(req, 400, CWEB_STR("Invalid request"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!valid_post_title(title)) {
|
if (!valid_post_title(title)) {
|
||||||
cweb_respond_basic(req, 200, CWEB_STR("<div class=\"error\">Invalid title</div>"));
|
cweb_respond_basic(req, 400, CWEB_STR("Invalid title"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!valid_link(link)) {
|
if (!valid_link(link)) {
|
||||||
cweb_respond_basic(req, 200, CWEB_STR("<div class=\"error\">Invalid link</div>"));
|
cweb_respond_basic(req, 400, CWEB_STR("Invalid link"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!valid_post_content(content)) {
|
if (!valid_post_content(content)) {
|
||||||
cweb_respond_basic(req, 200, CWEB_STR("<div class=\"error\">Invalid content</div>"));
|
cweb_respond_basic(req, 400, CWEB_STR("Invalid content"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -256,19 +200,20 @@ static void endpoint_api_post(CWEB *cweb, CWEB_Request *req)
|
|||||||
user_id, title, is_link, content);
|
user_id, title, is_link, content);
|
||||||
|
|
||||||
if (insert_id < 0) {
|
if (insert_id < 0) {
|
||||||
cweb_respond_basic(req, 500, CWEB_STR("<div class=\"error\">Internal error</div>"));
|
cweb_respond_basic(req, 500, CWEB_STR("Internal error"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int post_id = (int) insert_id;
|
int post_id = (int) insert_id;
|
||||||
|
|
||||||
cweb_respond_redirect(req, cweb_format(req, "/post?id={}", post_id));
|
CWEB_String target = cweb_format(req, "/post?id={}", post_id);
|
||||||
|
cweb_respond_redirect(req, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
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_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, 400, CWEB_STR("You are not logged in"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -278,13 +223,13 @@ static void endpoint_api_comment(CWEB *cweb, CWEB_Request *req)
|
|||||||
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_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, 400, CWEB_STR("Invalid request"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
content = cweb_trim(content);
|
content = cweb_trim(content);
|
||||||
if (!valid_comment_content(content)) {
|
if (!valid_comment_content(content)) {
|
||||||
cweb_respond_basic(req, 200, CWEB_STR("<div class=\"error\">Invalid content</div>"));
|
cweb_respond_basic(req, 400, CWEB_STR("Invalid content"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -292,18 +237,19 @@ static void endpoint_api_comment(CWEB *cweb, CWEB_Request *req)
|
|||||||
if (parent_comment == -1) insert_id = cweb_database_insert(cweb, "INSERT INTO Comments(author, content, parent_post) VALUES (?, ?, ?)", user_id, content, parent_post);
|
if (parent_comment == -1) insert_id = cweb_database_insert(cweb, "INSERT INTO Comments(author, content, parent_post) VALUES (?, ?, ?)", user_id, content, parent_post);
|
||||||
else insert_id = cweb_database_insert(cweb, "INSERT INTO Comments(author, content, parent_post, parent_comment) VALUES (?, ?, ?, ?)", user_id, content, parent_post, parent_comment);
|
else insert_id = cweb_database_insert(cweb, "INSERT INTO Comments(author, content, parent_post, parent_comment) VALUES (?, ?, ?, ?)", user_id, content, parent_post, parent_comment);
|
||||||
if (insert_id < 0) {
|
if (insert_id < 0) {
|
||||||
cweb_respond_basic(req, 200, CWEB_STR("<div class=\"error\">Internal error</div>"));
|
cweb_respond_basic(req, 500, CWEB_STR("Internal error"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cweb_respond_redirect(req, cweb_format(req, "/post?id={}", parent_post));
|
CWEB_String target = cweb_format(req, "/post?id={}", parent_post);
|
||||||
|
cweb_respond_redirect(req, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void endpoint_index(CWEB *cweb, CWEB_Request *req)
|
static void endpoint_index(CWEB *cweb, CWEB_Request *req)
|
||||||
{
|
{
|
||||||
(void) cweb;
|
(void) cweb;
|
||||||
|
|
||||||
cweb_respond_template(req, 200, CWEB_STR("pages/index.wl"), -1);
|
cweb_respond_template(req, 200, CWEB_STR("demo/pages/index.wl"), -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void endpoint_write(CWEB *cweb, CWEB_Request *req)
|
static void endpoint_write(CWEB *cweb, CWEB_Request *req)
|
||||||
@@ -315,7 +261,7 @@ static void endpoint_write(CWEB *cweb, CWEB_Request *req)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cweb_respond_template(req, 200, CWEB_STR("pages/write.wl"), -1);
|
cweb_respond_template(req, 200, CWEB_STR("demo/pages/write.wl"), -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void endpoint_login(CWEB *cweb, CWEB_Request *req)
|
static void endpoint_login(CWEB *cweb, CWEB_Request *req)
|
||||||
@@ -327,7 +273,7 @@ static void endpoint_login(CWEB *cweb, CWEB_Request *req)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cweb_respond_template(req, 200, CWEB_STR("pages/login.wl"), -1);
|
cweb_respond_template(req, 200, CWEB_STR("demo/pages/login.wl"), -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void endpoint_signup(CWEB *cweb, CWEB_Request *req)
|
static void endpoint_signup(CWEB *cweb, CWEB_Request *req)
|
||||||
@@ -339,14 +285,14 @@ static void endpoint_signup(CWEB *cweb, CWEB_Request *req)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cweb_respond_template(req, 200, CWEB_STR("pages/signup.wl"), -1);
|
cweb_respond_template(req, 200, CWEB_STR("demo/pages/signup.wl"), -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void endpoint_post(CWEB *cweb, CWEB_Request *req)
|
static void endpoint_post(CWEB *cweb, CWEB_Request *req)
|
||||||
{
|
{
|
||||||
int post_id = cweb_get_param_i(req, CWEB_STR("id"));
|
int post_id = cweb_get_param_i(req, CWEB_STR("id"));
|
||||||
if (post_id < 0) {
|
if (post_id < 0) {
|
||||||
cweb_respond_template(req, 404, CWEB_STR("pages/notfound.wl"), -1);
|
cweb_respond_template(req, 404, CWEB_STR("demo/pages/notfound.wl"), -1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -366,18 +312,18 @@ static void endpoint_post(CWEB *cweb, CWEB_Request *req)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (num == 0) {
|
if (num == 0) {
|
||||||
cweb_respond_template(req, 404, CWEB_STR("pages/notfound.wl"), -1);
|
cweb_respond_template(req, 404, CWEB_STR("demo/pages/notfound.wl"), -1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cweb_respond_template(req, 200, CWEB_STR("pages/post.wl"), post_id);
|
cweb_respond_template(req, 200, CWEB_STR("demo/pages/post.wl"), post_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void endpoint_fallback(CWEB *cweb, CWEB_Request *req)
|
static void endpoint_fallback(CWEB *cweb, CWEB_Request *req)
|
||||||
{
|
{
|
||||||
(void) cweb;
|
(void) cweb;
|
||||||
|
|
||||||
cweb_respond_template(req, 404, CWEB_STR("pages/notfound.wl"), -1);
|
cweb_respond_template(req, 404, CWEB_STR("demo/pages/notfound.wl"), -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
@@ -394,6 +340,14 @@ int main(void)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cweb_enable_database(cweb, CWEB_STR(":memory:"), CWEB_STR("demo/schema.sql")) < 0) {
|
||||||
|
cweb_free(cweb);
|
||||||
|
cweb_global_free();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cweb_trace_sql(cweb, true);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
CWEB_Request *req = cweb_wait(cweb);
|
CWEB_Request *req = cweb_wait(cweb);
|
||||||
if (0) {}
|
if (0) {}
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
include "pages/page.wl"
|
include "page.wl"
|
||||||
|
|
||||||
let posts = $query("SELECT P.id, P.title, P.is_link, P.content, (SELECT COUNT(*) FROM Comments as C WHERE c.parent_post=P.id) as num_comments, CURRENT_TIMESTAMP as date FROM Posts as P")
|
let posts = $query("SELECT P.id, P.title, P.is_link, P.content, (SELECT COUNT(*) FROM Comments as C WHERE c.parent_post=P.id) as num_comments, CURRENT_TIMESTAMP as date FROM Posts as P")
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -1,5 +1,5 @@
|
|||||||
include "pages/page.wl"
|
include "page.wl"
|
||||||
include "pages/login_and_signup_style.wl"
|
include "login_and_signup_style.wl"
|
||||||
|
|
||||||
let main =
|
let main =
|
||||||
<main>
|
<main>
|
||||||
@@ -7,7 +7,7 @@ let main =
|
|||||||
|
|
||||||
<div id="response"></div>
|
<div id="response"></div>
|
||||||
|
|
||||||
<form hx-post="/api/login" hx-target="#response">
|
<form action="/api/login" method="POST">
|
||||||
<input type="text" name="username" placeholder="username" />
|
<input type="text" name="username" placeholder="username" />
|
||||||
<input type="password" name="password" placeholder="password" />
|
<input type="password" name="password" placeholder="password" />
|
||||||
<input type="submit" value="Log-In" />
|
<input type="submit" value="Log-In" />
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
include "pages/page.wl"
|
include "page.wl"
|
||||||
|
|
||||||
let style =
|
let style =
|
||||||
<style>
|
<style>
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
include "pages/page.wl"
|
include "page.wl"
|
||||||
|
|
||||||
let posts = $query("SELECT U.username, P.title, P.content FROM Posts as P, Users as U WHERE P.id=? AND U.id=P.author", $post_id)
|
let posts = $query("SELECT U.username, P.title, P.content FROM Posts as P, Users as U WHERE P.id=? AND U.id=P.author", $post_id)
|
||||||
let comments = $query("SELECT C.id, U.username, C.content, C.parent_post, C.parent_comment FROM Comments as C, Users as U WHERE C.parent_post=? AND U.id=C.author", $post_id)
|
let comments = $query("SELECT C.id, U.username, C.content, C.parent_post, C.parent_comment FROM Comments as C, Users as U WHERE C.parent_post=? AND U.id=C.author", $post_id)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
include "pages/page.wl"
|
include "page.wl"
|
||||||
|
|
||||||
let posts = $query("SELECT title, content FROM Posts WHERE id=?", $post_id)
|
let posts = $query("SELECT title, content FROM Posts WHERE id=?", $post_id)
|
||||||
let comments = $query("SELECT C.id, U.username, C.content, C.parent_post, C.parent_comment FROM Comments as C, Users as U WHERE C.parent_post=? AND U.id == C.author", $post_id)
|
let comments = $query("SELECT C.id, U.username, C.content, C.parent_post, C.parent_comment FROM Comments as C, Users as U WHERE C.parent_post=? AND U.id == C.author", $post_id)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
include "pages/page.wl"
|
include "page.wl"
|
||||||
include "pages/login_and_signup_style.wl"
|
include "login_and_signup_style.wl"
|
||||||
|
|
||||||
let main =
|
let main =
|
||||||
<main>
|
<main>
|
||||||
@@ -7,7 +7,7 @@ let main =
|
|||||||
|
|
||||||
<div id="response"></div>
|
<div id="response"></div>
|
||||||
|
|
||||||
<form hx-post="/api/signup" hx-target="#response">
|
<form action="/api/signup" method="POST">
|
||||||
<input type="text" name="username" placeholder="username" />
|
<input type="text" name="username" placeholder="username" />
|
||||||
<input type="email" name="email" placeholder="email" />
|
<input type="email" name="email" placeholder="email" />
|
||||||
<input type="password" name="password1" placeholder="password" />
|
<input type="password" name="password1" placeholder="password" />
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
include "pages/page.wl"
|
include "page.wl"
|
||||||
|
|
||||||
let style =
|
let style =
|
||||||
<style>
|
<style>
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS Users (
|
||||||
|
id INTEGER PRIMARY KEY,
|
||||||
|
username TEXT NOT NULL UNIQUE,
|
||||||
|
hash TEXT NOT NULL,
|
||||||
|
email TEXT NOT NULL UNIQUE,
|
||||||
|
signup_time DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS Posts (
|
||||||
|
id INTEGER PRIMARY KEY,
|
||||||
|
author INTEGER NOT NULL,
|
||||||
|
title TEXT NOT NULL,
|
||||||
|
is_link BOOLEAN NOT NULL,
|
||||||
|
content TEXT NOT NULL,
|
||||||
|
submit_time DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
FOREIGN KEY (author) REFERENCES Users(id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS Comments (
|
||||||
|
id INTEGER PRIMARY KEY,
|
||||||
|
parent_post INTEGER NOT NULL,
|
||||||
|
parent_comment INTEGER,
|
||||||
|
author INTEGER NOT NULL,
|
||||||
|
content TEXT NOT NULL,
|
||||||
|
submit_time DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
FOREIGN KEY (author) REFERENCES Users(id),
|
||||||
|
FOREIGN KEY (parent_post) REFERENCES Posts(id),
|
||||||
|
FOREIGN KEY (parent_comment) REFERENCES Comments(id)
|
||||||
|
);
|
||||||
+166
-117
@@ -1,4 +1,6 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@@ -9,6 +11,7 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef CWEB_AMALGAMATION
|
||||||
#ifdef CWEB_ENABLE_DATABASE
|
#ifdef CWEB_ENABLE_DATABASE
|
||||||
#include "sqlite3.h"
|
#include "sqlite3.h"
|
||||||
#endif
|
#endif
|
||||||
@@ -18,7 +21,8 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "chttp.h"
|
#include "chttp.h"
|
||||||
#include "cweb.h"
|
#include "main.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
|
#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
|
||||||
#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
|
#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
|
||||||
@@ -93,6 +97,7 @@ struct CWEB {
|
|||||||
#ifdef CWEB_ENABLE_DATABASE
|
#ifdef CWEB_ENABLE_DATABASE
|
||||||
sqlite3 *db;
|
sqlite3 *db;
|
||||||
SQLiteCache *dbcache;
|
SQLiteCache *dbcache;
|
||||||
|
bool trace_sql;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CWEB_ENABLE_TEMPLATE
|
#ifdef CWEB_ENABLE_TEMPLATE
|
||||||
@@ -158,6 +163,87 @@ CWEB_VArg cweb_varg_from_pb (bool *pb) { return (CWEB_VArg) { CWEB_VA
|
|||||||
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 }; }
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *dst;
|
||||||
|
int cap;
|
||||||
|
int len;
|
||||||
|
} StaticOutputBuffer;
|
||||||
|
|
||||||
|
static void append_to_output(StaticOutputBuffer *out, char *src, int len)
|
||||||
|
{
|
||||||
|
int unused = out->cap - out->len;
|
||||||
|
if (unused > 0)
|
||||||
|
memcpy(out->dst + out->len, src, MIN(len, unused));
|
||||||
|
out->len += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void append_to_output_u64(StaticOutputBuffer *out, uint64_t n)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
static void value_to_output(StaticOutputBuffer *out, CWEB_VArg arg)
|
||||||
|
{
|
||||||
|
switch (arg.type) {
|
||||||
|
case CWEB_VARG_TYPE_C : append_to_output(out, &arg.c, 1); break;
|
||||||
|
case CWEB_VARG_TYPE_S : append_to_output_s64(out, arg.s); break;
|
||||||
|
case CWEB_VARG_TYPE_I : append_to_output_s64(out, arg.i); break;
|
||||||
|
case CWEB_VARG_TYPE_L : append_to_output_s64(out, arg.l); break;
|
||||||
|
case CWEB_VARG_TYPE_LL : append_to_output_s64(out, arg.ll); break;
|
||||||
|
case CWEB_VARG_TYPE_SC : append_to_output_s64(out, arg.sc); break;
|
||||||
|
case CWEB_VARG_TYPE_SS : append_to_output_s64(out, arg.ss); break;
|
||||||
|
case CWEB_VARG_TYPE_SI : append_to_output_s64(out, arg.si); break;
|
||||||
|
case CWEB_VARG_TYPE_SL : append_to_output_s64(out, arg.sl); break;
|
||||||
|
case CWEB_VARG_TYPE_SLL : append_to_output_s64(out, arg.sll); break;
|
||||||
|
case CWEB_VARG_TYPE_UC : append_to_output_u64(out, arg.uc); break;
|
||||||
|
case CWEB_VARG_TYPE_US : append_to_output_u64(out, arg.us); break;
|
||||||
|
case CWEB_VARG_TYPE_UI : append_to_output_u64(out, arg.ui); break;
|
||||||
|
case CWEB_VARG_TYPE_UL : append_to_output_u64(out, arg.ul); break;
|
||||||
|
case CWEB_VARG_TYPE_ULL : append_to_output_u64(out, arg.ull); break;
|
||||||
|
case CWEB_VARG_TYPE_F : append_to_output_f64(out, arg.f); break;
|
||||||
|
case CWEB_VARG_TYPE_D : append_to_output_u64(out, arg.d); break;
|
||||||
|
case CWEB_VARG_TYPE_B : append_to_output(out, arg.b ? "true" : "false", arg.b ? 4: 5);break;
|
||||||
|
case CWEB_VARG_TYPE_STR : append_to_output(out, arg.str.ptr, arg.str.len); break;
|
||||||
|
case CWEB_VARG_TYPE_HASH : append_to_output(out, arg.hash.data, strlen(arg.hash.data)); break;
|
||||||
|
case CWEB_VARG_TYPE_PC : append_to_output_ptr(out, arg.pc); break;
|
||||||
|
case CWEB_VARG_TYPE_PS : append_to_output_ptr(out, arg.ps); break;
|
||||||
|
case CWEB_VARG_TYPE_PI : append_to_output_ptr(out, arg.pi); break;
|
||||||
|
case CWEB_VARG_TYPE_PL : append_to_output_ptr(out, arg.pl); break;
|
||||||
|
case CWEB_VARG_TYPE_PLL : append_to_output_ptr(out, arg.pll); break;
|
||||||
|
case CWEB_VARG_TYPE_PSC : append_to_output_ptr(out, arg.psc); break;
|
||||||
|
case CWEB_VARG_TYPE_PSS : append_to_output_ptr(out, arg.pss); break;
|
||||||
|
case CWEB_VARG_TYPE_PSI : append_to_output_ptr(out, arg.psi); break;
|
||||||
|
case CWEB_VARG_TYPE_PSL : append_to_output_ptr(out, arg.psl); break;
|
||||||
|
case CWEB_VARG_TYPE_PSLL : append_to_output_ptr(out, arg.psll); break;
|
||||||
|
case CWEB_VARG_TYPE_PUC : append_to_output_ptr(out, arg.puc); break;
|
||||||
|
case CWEB_VARG_TYPE_PUS : append_to_output_ptr(out, arg.pus); break;
|
||||||
|
case CWEB_VARG_TYPE_PUI : append_to_output_ptr(out, arg.pui); break;
|
||||||
|
case CWEB_VARG_TYPE_PUL : append_to_output_ptr(out, arg.pul); break;
|
||||||
|
case CWEB_VARG_TYPE_PULL : append_to_output_ptr(out, arg.pull); break;
|
||||||
|
case CWEB_VARG_TYPE_PF : append_to_output_ptr(out, arg.pf); break;
|
||||||
|
case CWEB_VARG_TYPE_PD : append_to_output_ptr(out, arg.pd); break;
|
||||||
|
case CWEB_VARG_TYPE_PB : append_to_output_ptr(out, arg.pb); break;
|
||||||
|
case CWEB_VARG_TYPE_PSTR : append_to_output_ptr(out, arg.pstr); break;
|
||||||
|
case CWEB_VARG_TYPE_PHASH: append_to_output_ptr(out, arg.phash); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////
|
||||||
// FILE SYSTEM
|
// FILE SYSTEM
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
@@ -260,13 +346,13 @@ static int generate_random_bytes(char *dst, int cap)
|
|||||||
// PASSWORD
|
// PASSWORD
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
int cweb_hash_password(char *pass, int passlen, int cost, CWEB_PasswordHash *hash)
|
int cweb_hash_password(CWEB_String pass, int cost, CWEB_PasswordHash *hash)
|
||||||
{
|
{
|
||||||
char passzt[128];
|
char passzt[128];
|
||||||
if (passlen >= (int) sizeof(passzt))
|
if (pass.len >= (int) sizeof(passzt))
|
||||||
return -1;
|
return -1;
|
||||||
memcpy(passzt, pass, passlen);
|
memcpy(passzt, pass.ptr, pass.len);
|
||||||
passzt[passlen] = '\0';
|
passzt[pass.len] = '\0';
|
||||||
|
|
||||||
char random[16];
|
char random[16];
|
||||||
int ret = generate_random_bytes(random, (int) sizeof(random));
|
int ret = generate_random_bytes(random, (int) sizeof(random));
|
||||||
@@ -282,13 +368,13 @@ int cweb_hash_password(char *pass, int passlen, int cost, CWEB_PasswordHash *has
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cweb_check_password(char *pass, int passlen, CWEB_PasswordHash hash)
|
int cweb_check_password(CWEB_String pass, CWEB_PasswordHash hash)
|
||||||
{
|
{
|
||||||
char passzt[128];
|
char passzt[128];
|
||||||
if (passlen >= (int) sizeof(passzt))
|
if (pass.len >= (int) sizeof(passzt))
|
||||||
return -1;
|
return -1;
|
||||||
memcpy(passzt, pass, passlen);
|
memcpy(passzt, pass.ptr, pass.len);
|
||||||
passzt[passlen] = '\0';
|
passzt[pass.len] = '\0';
|
||||||
|
|
||||||
CWEB_PasswordHash new_hash;
|
CWEB_PasswordHash new_hash;
|
||||||
if (_crypt_blowfish_rn(passzt, hash.data, new_hash.data, sizeof(new_hash.data)) == NULL)
|
if (_crypt_blowfish_rn(passzt, hash.data, new_hash.data, sizeof(new_hash.data)) == NULL)
|
||||||
@@ -322,6 +408,8 @@ struct SessionStorage {
|
|||||||
Session items[];
|
Session items[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifndef CWEB_AMALGAMATION
|
||||||
|
|
||||||
static bool is_hex_digit(char c)
|
static bool is_hex_digit(char c)
|
||||||
{
|
{
|
||||||
return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f');
|
return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f');
|
||||||
@@ -336,6 +424,8 @@ static int hex_digit_to_int(char c)
|
|||||||
return c - '0';
|
return c - '0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
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);
|
||||||
@@ -585,7 +675,7 @@ static int sqlite3utils_prepare(SQLiteCache *cache, sqlite3_stmt **pstmt, char *
|
|||||||
sqlite3_stmt *stmt;
|
sqlite3_stmt *stmt;
|
||||||
int ret = sqlite3_prepare_v2(cache->db, fmt, -1, &stmt, NULL);
|
int ret = sqlite3_prepare_v2(cache->db, fmt, -1, &stmt, NULL);
|
||||||
if (ret != SQLITE_OK) {
|
if (ret != SQLITE_OK) {
|
||||||
//fprintf(stderr, "Failed to prepare statement: %s (%s:%d)\n", sqlite3_errmsg(db), __FILE__, __LINE__);
|
fprintf(stderr, "Failed to prepare statement: %s (%s:%d)\n", sqlite3_errmsg(cache->db), __FILE__, __LINE__); // TODO
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -617,30 +707,32 @@ static int sqlite3utils_prepare_and_bind_impl(SQLiteCache *cache,
|
|||||||
for (int i = 0; i < args.len; i++) {
|
for (int i = 0; i < args.len; i++) {
|
||||||
CWEB_VArg arg = args.ptr[i];
|
CWEB_VArg arg = args.ptr[i];
|
||||||
switch (arg.type) {
|
switch (arg.type) {
|
||||||
case CWEB_VARG_TYPE_C : ret = sqlite3_bind_text (stmt, i+1, &arg.c, 1, NULL); break;
|
case CWEB_VARG_TYPE_C : ret = sqlite3_bind_text (stmt, i+1, &arg.c, 1, NULL); break;
|
||||||
case CWEB_VARG_TYPE_S : ret = sqlite3_bind_int (stmt, i+1, arg.s); break;
|
case CWEB_VARG_TYPE_S : ret = sqlite3_bind_int (stmt, i+1, arg.s); break;
|
||||||
case CWEB_VARG_TYPE_I : ret = sqlite3_bind_int (stmt, i+1, arg.i); break;
|
case CWEB_VARG_TYPE_I : ret = sqlite3_bind_int (stmt, i+1, arg.i); break;
|
||||||
case CWEB_VARG_TYPE_L : ret = sqlite3_bind_int64 (stmt, i+1, arg.l); break;
|
case CWEB_VARG_TYPE_L : ret = sqlite3_bind_int64 (stmt, i+1, arg.l); break;
|
||||||
case CWEB_VARG_TYPE_LL : ret = sqlite3_bind_int64 (stmt, i+1, arg.ll); break;
|
case CWEB_VARG_TYPE_LL : ret = sqlite3_bind_int64 (stmt, i+1, arg.ll); break;
|
||||||
case CWEB_VARG_TYPE_SC : ret = sqlite3_bind_int (stmt, i+1, arg.sc); break;
|
case CWEB_VARG_TYPE_SC : ret = sqlite3_bind_int (stmt, i+1, arg.sc); break;
|
||||||
case CWEB_VARG_TYPE_SS : ret = sqlite3_bind_int (stmt, i+1, arg.ss); break;
|
case CWEB_VARG_TYPE_SS : ret = sqlite3_bind_int (stmt, i+1, arg.ss); break;
|
||||||
case CWEB_VARG_TYPE_SI : ret = sqlite3_bind_int (stmt, i+1, arg.si); break;
|
case CWEB_VARG_TYPE_SI : ret = sqlite3_bind_int (stmt, i+1, arg.si); break;
|
||||||
case CWEB_VARG_TYPE_SL : ret = sqlite3_bind_int64 (stmt, i+1, arg.sl); break;
|
case CWEB_VARG_TYPE_SL : ret = sqlite3_bind_int64 (stmt, i+1, arg.sl); break;
|
||||||
case CWEB_VARG_TYPE_SLL: ret = sqlite3_bind_int (stmt, i+1, arg.sll); break;
|
case CWEB_VARG_TYPE_SLL : ret = sqlite3_bind_int (stmt, i+1, arg.sll); break;
|
||||||
case CWEB_VARG_TYPE_UC : ret = sqlite3_bind_int (stmt, i+1, arg.uc); break;
|
case CWEB_VARG_TYPE_UC : ret = sqlite3_bind_int (stmt, i+1, arg.uc); break;
|
||||||
case CWEB_VARG_TYPE_US : ret = sqlite3_bind_int (stmt, i+1, arg.us); break;
|
case CWEB_VARG_TYPE_US : ret = sqlite3_bind_int (stmt, i+1, arg.us); break;
|
||||||
case CWEB_VARG_TYPE_UI : ret = sqlite3_bind_int64 (stmt, i+1, arg.ui); break;
|
case CWEB_VARG_TYPE_UI : ret = sqlite3_bind_int64 (stmt, i+1, arg.ui); break;
|
||||||
case CWEB_VARG_TYPE_UL : ret = sqlite3_bind_int64 (stmt, i+1, arg.ul); break;
|
case CWEB_VARG_TYPE_UL : ret = sqlite3_bind_int64 (stmt, i+1, arg.ul); break;
|
||||||
case CWEB_VARG_TYPE_ULL: ret = sqlite3_bind_int64 (stmt, i+1, arg.ull); break;
|
case CWEB_VARG_TYPE_ULL : ret = sqlite3_bind_int64 (stmt, i+1, arg.ull); break;
|
||||||
case CWEB_VARG_TYPE_F : ret = sqlite3_bind_double(stmt, i+1, arg.f); break;
|
case CWEB_VARG_TYPE_F : ret = sqlite3_bind_double(stmt, i+1, arg.f); break;
|
||||||
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;
|
||||||
|
case CWEB_VARG_TYPE_HASH: ret = sqlite3_bind_text (stmt, i+1, arg.hash.data, -1, NULL); break;
|
||||||
default:
|
default:
|
||||||
// TODO
|
ASSERT(0); // TODO
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (ret != SQLITE_OK) {
|
if (ret != SQLITE_OK) {
|
||||||
|
fprintf(stderr, "Failed to bind paremeter: %s (%s:%d)\n", sqlite3_errmsg(cache->db), __FILE__, __LINE__); // TODO
|
||||||
sqlite3_reset(stmt);
|
sqlite3_reset(stmt);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -652,9 +744,29 @@ static int sqlite3utils_prepare_and_bind_impl(SQLiteCache *cache,
|
|||||||
|
|
||||||
#endif // CWEB_ENABLE_DATABASE
|
#endif // CWEB_ENABLE_DATABASE
|
||||||
|
|
||||||
|
static void dump_sql(char *fmt, CWEB_VArgs args)
|
||||||
|
{
|
||||||
|
printf("SQL :: %s", fmt);
|
||||||
|
if (args.len > 0) {
|
||||||
|
printf(" (");
|
||||||
|
for (int i = 0; i < args.len; i++) {
|
||||||
|
char mem[128];
|
||||||
|
StaticOutputBuffer buf = { mem, sizeof(mem), 0 };
|
||||||
|
value_to_output(&buf, args.ptr[i]);
|
||||||
|
printf("%.*s", buf.len, buf.dst);
|
||||||
|
if (i+1 < args.len)
|
||||||
|
printf(", ");
|
||||||
|
}
|
||||||
|
printf(")");
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
int64_t cweb_database_insert_impl(CWEB *cweb, char *fmt, CWEB_VArgs args)
|
int64_t cweb_database_insert_impl(CWEB *cweb, char *fmt, CWEB_VArgs args)
|
||||||
{
|
{
|
||||||
#ifdef CWEB_ENABLE_DATABASE
|
#ifdef CWEB_ENABLE_DATABASE
|
||||||
|
if (cweb->trace_sql) dump_sql(fmt, args);
|
||||||
|
|
||||||
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)
|
||||||
@@ -668,6 +780,7 @@ int64_t cweb_database_insert_impl(CWEB *cweb, char *fmt, CWEB_VArgs args)
|
|||||||
|
|
||||||
int64_t insert_id = sqlite3_last_insert_rowid(cweb->db);
|
int64_t insert_id = sqlite3_last_insert_rowid(cweb->db);
|
||||||
if (insert_id < 0) {
|
if (insert_id < 0) {
|
||||||
|
fprintf(stderr, "Insert ID is invalid: %s (%s:%d)\n", sqlite3_errmsg(cweb->db), __FILE__, __LINE__); // TODO
|
||||||
sqlite3_reset(stmt);
|
sqlite3_reset(stmt);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -682,6 +795,8 @@ int64_t cweb_database_insert_impl(CWEB *cweb, char *fmt, CWEB_VArgs args)
|
|||||||
CWEB_QueryResult cweb_database_select_impl(CWEB *cweb, char *fmt, CWEB_VArgs args)
|
CWEB_QueryResult cweb_database_select_impl(CWEB *cweb, char *fmt, CWEB_VArgs args)
|
||||||
{
|
{
|
||||||
#ifdef CWEB_ENABLE_DATABASE
|
#ifdef CWEB_ENABLE_DATABASE
|
||||||
|
if (cweb->trace_sql) dump_sql(fmt, args);
|
||||||
|
|
||||||
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)
|
||||||
@@ -865,6 +980,7 @@ CWEB *cweb_init(CWEB_String addr, uint16_t port)
|
|||||||
#ifdef CWEB_ENABLE_DATABASE
|
#ifdef CWEB_ENABLE_DATABASE
|
||||||
cweb->db = NULL;
|
cweb->db = NULL;
|
||||||
cweb->dbcache = NULL;
|
cweb->dbcache = NULL;
|
||||||
|
cweb->trace_sql = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
cweb->allow_insecure_login = false;
|
cweb->allow_insecure_login = false;
|
||||||
@@ -893,17 +1009,24 @@ void cweb_version(void)
|
|||||||
printf("%s\n", sqlite3_libversion());
|
printf("%s\n", sqlite3_libversion());
|
||||||
}
|
}
|
||||||
|
|
||||||
int cweb_enable_database(CWEB *cweb, CWEB_String file)
|
void cweb_trace_sql(CWEB *cweb, bool enable)
|
||||||
|
{
|
||||||
|
#ifdef CWEB_ENABLE_DATABASE
|
||||||
|
cweb->trace_sql = enable;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int cweb_enable_database(CWEB *cweb, CWEB_String database_file, CWEB_String schema_file)
|
||||||
{
|
{
|
||||||
#ifdef CWEB_ENABLE_DATABASE
|
#ifdef CWEB_ENABLE_DATABASE
|
||||||
if (cweb->db != NULL)
|
if (cweb->db != NULL)
|
||||||
return -1; // Already enabled
|
return -1; // Already enabled
|
||||||
|
|
||||||
char file_copy[1<<12];
|
char file_copy[1<<12];
|
||||||
if (file.len >= SIZEOF(file_copy))
|
if (database_file.len >= SIZEOF(file_copy))
|
||||||
return -1;
|
return -1;
|
||||||
memcpy(file_copy, file.ptr, file.len);
|
memcpy(file_copy, database_file.ptr, database_file.len);
|
||||||
file_copy[file.len] = '\0';
|
file_copy[database_file.len] = '\0';
|
||||||
|
|
||||||
int ret = sqlite3_open(file_copy, &cweb->db);
|
int ret = sqlite3_open(file_copy, &cweb->db);
|
||||||
if (ret != SQLITE_OK) {
|
if (ret != SQLITE_OK) {
|
||||||
@@ -912,7 +1035,7 @@ int cweb_enable_database(CWEB *cweb, CWEB_String file)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
LoadedFile *schema = load_file(file);
|
LoadedFile *schema = load_file(schema_file);
|
||||||
if (schema == NULL) {
|
if (schema == NULL) {
|
||||||
sqlite3_close(cweb->db);
|
sqlite3_close(cweb->db);
|
||||||
cweb->db = NULL;
|
cweb->db = NULL;
|
||||||
@@ -921,6 +1044,7 @@ int cweb_enable_database(CWEB *cweb, CWEB_String file)
|
|||||||
|
|
||||||
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) {
|
||||||
|
free_loaded_files(schema);
|
||||||
sqlite3_close(cweb->db);
|
sqlite3_close(cweb->db);
|
||||||
cweb->db = NULL;
|
cweb->db = NULL;
|
||||||
return -1;
|
return -1;
|
||||||
@@ -998,7 +1122,7 @@ static int set_auth_cookie_if_necessary(CWEB_Request *req)
|
|||||||
{
|
{
|
||||||
if (req->just_created_session) {
|
if (req->just_created_session) {
|
||||||
char cookie[1<<9];
|
char cookie[1<<9];
|
||||||
int cookie_len = snprintf(cookie, sizeof(cookie), "Set-Cookie: sess_token=%.*s; Path=/; HttpOnly; Secure", req->sess.len, req->sess.ptr);
|
int cookie_len = snprintf(cookie, sizeof(cookie), "Set-Cookie: sess_token=%.*s; Path=/; HttpOnly%s", req->sess.len, req->sess.ptr, req->cweb->allow_insecure_login ? "" : "; Secure");
|
||||||
if (cookie_len < 0 || cookie_len >= (int) sizeof(cookie))
|
if (cookie_len < 0 || cookie_len >= (int) sizeof(cookie))
|
||||||
return -500;
|
return -500;
|
||||||
http_response_builder_header(req->builder, (HTTP_String) { cookie, cookie_len });
|
http_response_builder_header(req->builder, (HTTP_String) { cookie, cookie_len });
|
||||||
@@ -1020,86 +1144,6 @@ void cweb_respond_basic(CWEB_Request *req, int status, CWEB_String content)
|
|||||||
http_response_builder_done(req->builder);
|
http_response_builder_done(req->builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char *dst;
|
|
||||||
int cap;
|
|
||||||
int len;
|
|
||||||
} StaticOutputBuffer;
|
|
||||||
|
|
||||||
static void append_to_output(StaticOutputBuffer *out, char *src, int len)
|
|
||||||
{
|
|
||||||
int unused = out->cap - out->len;
|
|
||||||
if (unused > 0)
|
|
||||||
memcpy(out->dst + out->len, src, MIN(len, unused));
|
|
||||||
out->len += len;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void append_to_output_u64(StaticOutputBuffer *out, uint64_t n)
|
|
||||||
{
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
static void value_to_output(StaticOutputBuffer *out, CWEB_VArg arg)
|
|
||||||
{
|
|
||||||
switch (arg.type) {
|
|
||||||
case CWEB_VARG_TYPE_C : append_to_output(out, &arg.c, 1); break;
|
|
||||||
case CWEB_VARG_TYPE_S : append_to_output_s64(out, arg.s); break;
|
|
||||||
case CWEB_VARG_TYPE_I : append_to_output_s64(out, arg.i); break;
|
|
||||||
case CWEB_VARG_TYPE_L : append_to_output_s64(out, arg.l); break;
|
|
||||||
case CWEB_VARG_TYPE_LL : append_to_output_s64(out, arg.ll); break;
|
|
||||||
case CWEB_VARG_TYPE_SC : append_to_output_s64(out, arg.sc); break;
|
|
||||||
case CWEB_VARG_TYPE_SS : append_to_output_s64(out, arg.ss); break;
|
|
||||||
case CWEB_VARG_TYPE_SI : append_to_output_s64(out, arg.si); break;
|
|
||||||
case CWEB_VARG_TYPE_SL : append_to_output_s64(out, arg.sl); break;
|
|
||||||
case CWEB_VARG_TYPE_SLL : append_to_output_s64(out, arg.sll); break;
|
|
||||||
case CWEB_VARG_TYPE_UC : append_to_output_u64(out, arg.uc); break;
|
|
||||||
case CWEB_VARG_TYPE_US : append_to_output_u64(out, arg.us); break;
|
|
||||||
case CWEB_VARG_TYPE_UI : append_to_output_u64(out, arg.ui); break;
|
|
||||||
case CWEB_VARG_TYPE_UL : append_to_output_u64(out, arg.ul); break;
|
|
||||||
case CWEB_VARG_TYPE_ULL : append_to_output_u64(out, arg.ull); break;
|
|
||||||
case CWEB_VARG_TYPE_F : append_to_output_f64(out, arg.f); break;
|
|
||||||
case CWEB_VARG_TYPE_D : append_to_output_u64(out, arg.d); break;
|
|
||||||
case CWEB_VARG_TYPE_B : append_to_output(out, arg.b ? "true" : "false", arg.b ? 4: 5);break;
|
|
||||||
case CWEB_VARG_TYPE_STR : append_to_output(out, arg.str.ptr, arg.str.len); break;
|
|
||||||
case CWEB_VARG_TYPE_HASH : append_to_output(out, arg.hash.data, strlen(arg.hash.data)); break;
|
|
||||||
case CWEB_VARG_TYPE_PC : append_to_output_ptr(out, arg.pc); break;
|
|
||||||
case CWEB_VARG_TYPE_PS : append_to_output_ptr(out, arg.ps); break;
|
|
||||||
case CWEB_VARG_TYPE_PI : append_to_output_ptr(out, arg.pi); break;
|
|
||||||
case CWEB_VARG_TYPE_PL : append_to_output_ptr(out, arg.pl); break;
|
|
||||||
case CWEB_VARG_TYPE_PLL : append_to_output_ptr(out, arg.pll); break;
|
|
||||||
case CWEB_VARG_TYPE_PSC : append_to_output_ptr(out, arg.psc); break;
|
|
||||||
case CWEB_VARG_TYPE_PSS : append_to_output_ptr(out, arg.pss); break;
|
|
||||||
case CWEB_VARG_TYPE_PSI : append_to_output_ptr(out, arg.psi); break;
|
|
||||||
case CWEB_VARG_TYPE_PSL : append_to_output_ptr(out, arg.psl); break;
|
|
||||||
case CWEB_VARG_TYPE_PSLL : append_to_output_ptr(out, arg.psll); break;
|
|
||||||
case CWEB_VARG_TYPE_PUC : append_to_output_ptr(out, arg.puc); break;
|
|
||||||
case CWEB_VARG_TYPE_PUS : append_to_output_ptr(out, arg.pus); break;
|
|
||||||
case CWEB_VARG_TYPE_PUI : append_to_output_ptr(out, arg.pui); break;
|
|
||||||
case CWEB_VARG_TYPE_PUL : append_to_output_ptr(out, arg.pul); break;
|
|
||||||
case CWEB_VARG_TYPE_PULL : append_to_output_ptr(out, arg.pull); break;
|
|
||||||
case CWEB_VARG_TYPE_PF : append_to_output_ptr(out, arg.pf); break;
|
|
||||||
case CWEB_VARG_TYPE_PD : append_to_output_ptr(out, arg.pd); break;
|
|
||||||
case CWEB_VARG_TYPE_PB : append_to_output_ptr(out, arg.pb); break;
|
|
||||||
case CWEB_VARG_TYPE_PSTR : append_to_output_ptr(out, arg.pstr); break;
|
|
||||||
case CWEB_VARG_TYPE_PHASH: append_to_output_ptr(out, arg.phash); break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void evaluate_format(StaticOutputBuffer *out, CWEB_String format, CWEB_VArgs args)
|
static void evaluate_format(StaticOutputBuffer *out, CWEB_String format, CWEB_VArgs args)
|
||||||
{
|
{
|
||||||
char *src = format.ptr;
|
char *src = format.ptr;
|
||||||
@@ -1279,7 +1323,7 @@ static int compile(WL_String path, WL_Program *program, WL_Arena *arena)
|
|||||||
loaded_file_tail = &loaded_file->next;
|
loaded_file_tail = &loaded_file->next;
|
||||||
|
|
||||||
WL_String content = { loaded_file->data, loaded_file->len };
|
WL_String content = { loaded_file->data, loaded_file->len };
|
||||||
WL_AddResult result = wl_compiler_add(compiler, content);
|
WL_AddResult result = wl_compiler_add(compiler, path, content);
|
||||||
|
|
||||||
if (result.type == WL_ADD_ERROR) {
|
if (result.type == WL_ADD_ERROR) {
|
||||||
TRACE("Compilation failed (%s)", wl_compiler_error(compiler).ptr);
|
TRACE("Compilation failed (%s)", wl_compiler_error(compiler).ptr);
|
||||||
@@ -1307,6 +1351,11 @@ static int compile(WL_String path, WL_Program *program, WL_Arena *arena)
|
|||||||
|
|
||||||
static int query_routine(WL_Runtime *rt, SQLiteCache *dbcache)
|
static int query_routine(WL_Runtime *rt, SQLiteCache *dbcache)
|
||||||
{
|
{
|
||||||
|
if (dbcache == NULL) {
|
||||||
|
wl_push_none(rt); // Allow not pushing anything on the WL machine
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
int num_args = wl_arg_count(rt);
|
int num_args = wl_arg_count(rt);
|
||||||
if (num_args == 0)
|
if (num_args == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
+8
-3
@@ -222,7 +222,12 @@ void cweb_global_free(void);
|
|||||||
CWEB *cweb_init(CWEB_String addr, uint16_t port);
|
CWEB *cweb_init(CWEB_String addr, uint16_t port);
|
||||||
void cweb_free(CWEB *cweb);
|
void cweb_free(CWEB *cweb);
|
||||||
|
|
||||||
int cweb_enable_database(CWEB *cweb, CWEB_String file);
|
// Open an SQLite instance in file "database_file" and run the DDL script at "schema_file".
|
||||||
|
// Note that "database_file" may be ":memory:".
|
||||||
|
int cweb_enable_database(CWEB *cweb, CWEB_String database_file, CWEB_String schema_file);
|
||||||
|
|
||||||
|
// Log all evaluated SQL statements to stdout
|
||||||
|
void cweb_trace_sql(CWEB *cweb, bool enable);
|
||||||
|
|
||||||
// Pause execution until a request is available.
|
// Pause execution until a request is available.
|
||||||
// TODO: When does this function return NULL?
|
// TODO: When does this function return NULL?
|
||||||
@@ -293,7 +298,7 @@ int cweb_next_query_row_impl(CWEB_QueryResult *res, CWEB_VArgs args);
|
|||||||
void cweb_free_query_result(CWEB_QueryResult *res);
|
void cweb_free_query_result(CWEB_QueryResult *res);
|
||||||
|
|
||||||
// Calculates the bcrypt hash of the specified password
|
// 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(CWEB_String pass, int cost, CWEB_PasswordHash *hash);
|
||||||
|
|
||||||
// Checks whether the password matches the given hash
|
// Checks whether the password matches the given hash
|
||||||
int cweb_check_password(char *pass, int passlen, CWEB_PasswordHash hash);
|
int cweb_check_password(CWEB_String pass, CWEB_PasswordHash hash);
|
||||||
|
|||||||
Reference in New Issue
Block a user