fix: harden UCE runtime and starter

This commit is contained in:
udo
2026-06-11 13:44:24 +00:00
parent 71ddcaf7d4
commit 7f757654b6
128 changed files with 276200 additions and 872 deletions
+257679
View File
File diff suppressed because it is too large Load Diff
+13425
View File
File diff suppressed because it is too large Load Diff
+719
View File
@@ -0,0 +1,719 @@
/*
** 2006 June 7
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This header file defines the SQLite interface for use by
** shared libraries that want to be imported as extensions into
** an SQLite instance. Shared libraries that intend to be loaded
** as extensions by SQLite should #include this file instead of
** sqlite3.h.
*/
#ifndef SQLITE3EXT_H
#define SQLITE3EXT_H
#include "sqlite3.h"
/*
** The following structure holds pointers to all of the SQLite API
** routines.
**
** WARNING: In order to maintain backwards compatibility, add new
** interfaces to the end of this structure only. If you insert new
** interfaces in the middle of this structure, then older different
** versions of SQLite will not be able to load each other's shared
** libraries!
*/
struct sqlite3_api_routines {
void * (*aggregate_context)(sqlite3_context*,int nBytes);
int (*aggregate_count)(sqlite3_context*);
int (*bind_blob)(sqlite3_stmt*,int,const void*,int n,void(*)(void*));
int (*bind_double)(sqlite3_stmt*,int,double);
int (*bind_int)(sqlite3_stmt*,int,int);
int (*bind_int64)(sqlite3_stmt*,int,sqlite_int64);
int (*bind_null)(sqlite3_stmt*,int);
int (*bind_parameter_count)(sqlite3_stmt*);
int (*bind_parameter_index)(sqlite3_stmt*,const char*zName);
const char * (*bind_parameter_name)(sqlite3_stmt*,int);
int (*bind_text)(sqlite3_stmt*,int,const char*,int n,void(*)(void*));
int (*bind_text16)(sqlite3_stmt*,int,const void*,int,void(*)(void*));
int (*bind_value)(sqlite3_stmt*,int,const sqlite3_value*);
int (*busy_handler)(sqlite3*,int(*)(void*,int),void*);
int (*busy_timeout)(sqlite3*,int ms);
int (*changes)(sqlite3*);
int (*close)(sqlite3*);
int (*collation_needed)(sqlite3*,void*,void(*)(void*,sqlite3*,
int eTextRep,const char*));
int (*collation_needed16)(sqlite3*,void*,void(*)(void*,sqlite3*,
int eTextRep,const void*));
const void * (*column_blob)(sqlite3_stmt*,int iCol);
int (*column_bytes)(sqlite3_stmt*,int iCol);
int (*column_bytes16)(sqlite3_stmt*,int iCol);
int (*column_count)(sqlite3_stmt*pStmt);
const char * (*column_database_name)(sqlite3_stmt*,int);
const void * (*column_database_name16)(sqlite3_stmt*,int);
const char * (*column_decltype)(sqlite3_stmt*,int i);
const void * (*column_decltype16)(sqlite3_stmt*,int);
double (*column_double)(sqlite3_stmt*,int iCol);
int (*column_int)(sqlite3_stmt*,int iCol);
sqlite_int64 (*column_int64)(sqlite3_stmt*,int iCol);
const char * (*column_name)(sqlite3_stmt*,int);
const void * (*column_name16)(sqlite3_stmt*,int);
const char * (*column_origin_name)(sqlite3_stmt*,int);
const void * (*column_origin_name16)(sqlite3_stmt*,int);
const char * (*column_table_name)(sqlite3_stmt*,int);
const void * (*column_table_name16)(sqlite3_stmt*,int);
const unsigned char * (*column_text)(sqlite3_stmt*,int iCol);
const void * (*column_text16)(sqlite3_stmt*,int iCol);
int (*column_type)(sqlite3_stmt*,int iCol);
sqlite3_value* (*column_value)(sqlite3_stmt*,int iCol);
void * (*commit_hook)(sqlite3*,int(*)(void*),void*);
int (*complete)(const char*sql);
int (*complete16)(const void*sql);
int (*create_collation)(sqlite3*,const char*,int,void*,
int(*)(void*,int,const void*,int,const void*));
int (*create_collation16)(sqlite3*,const void*,int,void*,
int(*)(void*,int,const void*,int,const void*));
int (*create_function)(sqlite3*,const char*,int,int,void*,
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*));
int (*create_function16)(sqlite3*,const void*,int,int,void*,
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*));
int (*create_module)(sqlite3*,const char*,const sqlite3_module*,void*);
int (*data_count)(sqlite3_stmt*pStmt);
sqlite3 * (*db_handle)(sqlite3_stmt*);
int (*declare_vtab)(sqlite3*,const char*);
int (*enable_shared_cache)(int);
int (*errcode)(sqlite3*db);
const char * (*errmsg)(sqlite3*);
const void * (*errmsg16)(sqlite3*);
int (*exec)(sqlite3*,const char*,sqlite3_callback,void*,char**);
int (*expired)(sqlite3_stmt*);
int (*finalize)(sqlite3_stmt*pStmt);
void (*free)(void*);
void (*free_table)(char**result);
int (*get_autocommit)(sqlite3*);
void * (*get_auxdata)(sqlite3_context*,int);
int (*get_table)(sqlite3*,const char*,char***,int*,int*,char**);
int (*global_recover)(void);
void (*interruptx)(sqlite3*);
sqlite_int64 (*last_insert_rowid)(sqlite3*);
const char * (*libversion)(void);
int (*libversion_number)(void);
void *(*malloc)(int);
char * (*mprintf)(const char*,...);
int (*open)(const char*,sqlite3**);
int (*open16)(const void*,sqlite3**);
int (*prepare)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
int (*prepare16)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
void * (*profile)(sqlite3*,void(*)(void*,const char*,sqlite_uint64),void*);
void (*progress_handler)(sqlite3*,int,int(*)(void*),void*);
void *(*realloc)(void*,int);
int (*reset)(sqlite3_stmt*pStmt);
void (*result_blob)(sqlite3_context*,const void*,int,void(*)(void*));
void (*result_double)(sqlite3_context*,double);
void (*result_error)(sqlite3_context*,const char*,int);
void (*result_error16)(sqlite3_context*,const void*,int);
void (*result_int)(sqlite3_context*,int);
void (*result_int64)(sqlite3_context*,sqlite_int64);
void (*result_null)(sqlite3_context*);
void (*result_text)(sqlite3_context*,const char*,int,void(*)(void*));
void (*result_text16)(sqlite3_context*,const void*,int,void(*)(void*));
void (*result_text16be)(sqlite3_context*,const void*,int,void(*)(void*));
void (*result_text16le)(sqlite3_context*,const void*,int,void(*)(void*));
void (*result_value)(sqlite3_context*,sqlite3_value*);
void * (*rollback_hook)(sqlite3*,void(*)(void*),void*);
int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*,
const char*,const char*),void*);
void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*));
char * (*xsnprintf)(int,char*,const char*,...);
int (*step)(sqlite3_stmt*);
int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,
char const**,char const**,int*,int*,int*);
void (*thread_cleanup)(void);
int (*total_changes)(sqlite3*);
void * (*trace)(sqlite3*,void(*xTrace)(void*,const char*),void*);
int (*transfer_bindings)(sqlite3_stmt*,sqlite3_stmt*);
void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*,
sqlite_int64),void*);
void * (*user_data)(sqlite3_context*);
const void * (*value_blob)(sqlite3_value*);
int (*value_bytes)(sqlite3_value*);
int (*value_bytes16)(sqlite3_value*);
double (*value_double)(sqlite3_value*);
int (*value_int)(sqlite3_value*);
sqlite_int64 (*value_int64)(sqlite3_value*);
int (*value_numeric_type)(sqlite3_value*);
const unsigned char * (*value_text)(sqlite3_value*);
const void * (*value_text16)(sqlite3_value*);
const void * (*value_text16be)(sqlite3_value*);
const void * (*value_text16le)(sqlite3_value*);
int (*value_type)(sqlite3_value*);
char *(*vmprintf)(const char*,va_list);
/* Added ??? */
int (*overload_function)(sqlite3*, const char *zFuncName, int nArg);
/* Added by 3.3.13 */
int (*prepare_v2)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
int (*prepare16_v2)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
int (*clear_bindings)(sqlite3_stmt*);
/* Added by 3.4.1 */
int (*create_module_v2)(sqlite3*,const char*,const sqlite3_module*,void*,
void (*xDestroy)(void *));
/* Added by 3.5.0 */
int (*bind_zeroblob)(sqlite3_stmt*,int,int);
int (*blob_bytes)(sqlite3_blob*);
int (*blob_close)(sqlite3_blob*);
int (*blob_open)(sqlite3*,const char*,const char*,const char*,sqlite3_int64,
int,sqlite3_blob**);
int (*blob_read)(sqlite3_blob*,void*,int,int);
int (*blob_write)(sqlite3_blob*,const void*,int,int);
int (*create_collation_v2)(sqlite3*,const char*,int,void*,
int(*)(void*,int,const void*,int,const void*),
void(*)(void*));
int (*file_control)(sqlite3*,const char*,int,void*);
sqlite3_int64 (*memory_highwater)(int);
sqlite3_int64 (*memory_used)(void);
sqlite3_mutex *(*mutex_alloc)(int);
void (*mutex_enter)(sqlite3_mutex*);
void (*mutex_free)(sqlite3_mutex*);
void (*mutex_leave)(sqlite3_mutex*);
int (*mutex_try)(sqlite3_mutex*);
int (*open_v2)(const char*,sqlite3**,int,const char*);
int (*release_memory)(int);
void (*result_error_nomem)(sqlite3_context*);
void (*result_error_toobig)(sqlite3_context*);
int (*sleep)(int);
void (*soft_heap_limit)(int);
sqlite3_vfs *(*vfs_find)(const char*);
int (*vfs_register)(sqlite3_vfs*,int);
int (*vfs_unregister)(sqlite3_vfs*);
int (*xthreadsafe)(void);
void (*result_zeroblob)(sqlite3_context*,int);
void (*result_error_code)(sqlite3_context*,int);
int (*test_control)(int, ...);
void (*randomness)(int,void*);
sqlite3 *(*context_db_handle)(sqlite3_context*);
int (*extended_result_codes)(sqlite3*,int);
int (*limit)(sqlite3*,int,int);
sqlite3_stmt *(*next_stmt)(sqlite3*,sqlite3_stmt*);
const char *(*sql)(sqlite3_stmt*);
int (*status)(int,int*,int*,int);
int (*backup_finish)(sqlite3_backup*);
sqlite3_backup *(*backup_init)(sqlite3*,const char*,sqlite3*,const char*);
int (*backup_pagecount)(sqlite3_backup*);
int (*backup_remaining)(sqlite3_backup*);
int (*backup_step)(sqlite3_backup*,int);
const char *(*compileoption_get)(int);
int (*compileoption_used)(const char*);
int (*create_function_v2)(sqlite3*,const char*,int,int,void*,
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*),
void(*xDestroy)(void*));
int (*db_config)(sqlite3*,int,...);
sqlite3_mutex *(*db_mutex)(sqlite3*);
int (*db_status)(sqlite3*,int,int*,int*,int);
int (*extended_errcode)(sqlite3*);
void (*log)(int,const char*,...);
sqlite3_int64 (*soft_heap_limit64)(sqlite3_int64);
const char *(*sourceid)(void);
int (*stmt_status)(sqlite3_stmt*,int,int);
int (*strnicmp)(const char*,const char*,int);
int (*unlock_notify)(sqlite3*,void(*)(void**,int),void*);
int (*wal_autocheckpoint)(sqlite3*,int);
int (*wal_checkpoint)(sqlite3*,const char*);
void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*);
int (*blob_reopen)(sqlite3_blob*,sqlite3_int64);
int (*vtab_config)(sqlite3*,int op,...);
int (*vtab_on_conflict)(sqlite3*);
/* Version 3.7.16 and later */
int (*close_v2)(sqlite3*);
const char *(*db_filename)(sqlite3*,const char*);
int (*db_readonly)(sqlite3*,const char*);
int (*db_release_memory)(sqlite3*);
const char *(*errstr)(int);
int (*stmt_busy)(sqlite3_stmt*);
int (*stmt_readonly)(sqlite3_stmt*);
int (*stricmp)(const char*,const char*);
int (*uri_boolean)(const char*,const char*,int);
sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64);
const char *(*uri_parameter)(const char*,const char*);
char *(*xvsnprintf)(int,char*,const char*,va_list);
int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*);
/* Version 3.8.7 and later */
int (*auto_extension)(void(*)(void));
int (*bind_blob64)(sqlite3_stmt*,int,const void*,sqlite3_uint64,
void(*)(void*));
int (*bind_text64)(sqlite3_stmt*,int,const char*,sqlite3_uint64,
void(*)(void*),unsigned char);
int (*cancel_auto_extension)(void(*)(void));
int (*load_extension)(sqlite3*,const char*,const char*,char**);
void *(*malloc64)(sqlite3_uint64);
sqlite3_uint64 (*msize)(void*);
void *(*realloc64)(void*,sqlite3_uint64);
void (*reset_auto_extension)(void);
void (*result_blob64)(sqlite3_context*,const void*,sqlite3_uint64,
void(*)(void*));
void (*result_text64)(sqlite3_context*,const char*,sqlite3_uint64,
void(*)(void*), unsigned char);
int (*strglob)(const char*,const char*);
/* Version 3.8.11 and later */
sqlite3_value *(*value_dup)(const sqlite3_value*);
void (*value_free)(sqlite3_value*);
int (*result_zeroblob64)(sqlite3_context*,sqlite3_uint64);
int (*bind_zeroblob64)(sqlite3_stmt*, int, sqlite3_uint64);
/* Version 3.9.0 and later */
unsigned int (*value_subtype)(sqlite3_value*);
void (*result_subtype)(sqlite3_context*,unsigned int);
/* Version 3.10.0 and later */
int (*status64)(int,sqlite3_int64*,sqlite3_int64*,int);
int (*strlike)(const char*,const char*,unsigned int);
int (*db_cacheflush)(sqlite3*);
/* Version 3.12.0 and later */
int (*system_errno)(sqlite3*);
/* Version 3.14.0 and later */
int (*trace_v2)(sqlite3*,unsigned,int(*)(unsigned,void*,void*,void*),void*);
char *(*expanded_sql)(sqlite3_stmt*);
/* Version 3.18.0 and later */
void (*set_last_insert_rowid)(sqlite3*,sqlite3_int64);
/* Version 3.20.0 and later */
int (*prepare_v3)(sqlite3*,const char*,int,unsigned int,
sqlite3_stmt**,const char**);
int (*prepare16_v3)(sqlite3*,const void*,int,unsigned int,
sqlite3_stmt**,const void**);
int (*bind_pointer)(sqlite3_stmt*,int,void*,const char*,void(*)(void*));
void (*result_pointer)(sqlite3_context*,void*,const char*,void(*)(void*));
void *(*value_pointer)(sqlite3_value*,const char*);
int (*vtab_nochange)(sqlite3_context*);
int (*value_nochange)(sqlite3_value*);
const char *(*vtab_collation)(sqlite3_index_info*,int);
/* Version 3.24.0 and later */
int (*keyword_count)(void);
int (*keyword_name)(int,const char**,int*);
int (*keyword_check)(const char*,int);
sqlite3_str *(*str_new)(sqlite3*);
char *(*str_finish)(sqlite3_str*);
void (*str_appendf)(sqlite3_str*, const char *zFormat, ...);
void (*str_vappendf)(sqlite3_str*, const char *zFormat, va_list);
void (*str_append)(sqlite3_str*, const char *zIn, int N);
void (*str_appendall)(sqlite3_str*, const char *zIn);
void (*str_appendchar)(sqlite3_str*, int N, char C);
void (*str_reset)(sqlite3_str*);
int (*str_errcode)(sqlite3_str*);
int (*str_length)(sqlite3_str*);
char *(*str_value)(sqlite3_str*);
/* Version 3.25.0 and later */
int (*create_window_function)(sqlite3*,const char*,int,int,void*,
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*),
void (*xValue)(sqlite3_context*),
void (*xInv)(sqlite3_context*,int,sqlite3_value**),
void(*xDestroy)(void*));
/* Version 3.26.0 and later */
const char *(*normalized_sql)(sqlite3_stmt*);
/* Version 3.28.0 and later */
int (*stmt_isexplain)(sqlite3_stmt*);
int (*value_frombind)(sqlite3_value*);
/* Version 3.30.0 and later */
int (*drop_modules)(sqlite3*,const char**);
/* Version 3.31.0 and later */
sqlite3_int64 (*hard_heap_limit64)(sqlite3_int64);
const char *(*uri_key)(const char*,int);
const char *(*filename_database)(const char*);
const char *(*filename_journal)(const char*);
const char *(*filename_wal)(const char*);
/* Version 3.32.0 and later */
const char *(*create_filename)(const char*,const char*,const char*,
int,const char**);
void (*free_filename)(const char*);
sqlite3_file *(*database_file_object)(const char*);
/* Version 3.34.0 and later */
int (*txn_state)(sqlite3*,const char*);
/* Version 3.36.1 and later */
sqlite3_int64 (*changes64)(sqlite3*);
sqlite3_int64 (*total_changes64)(sqlite3*);
/* Version 3.37.0 and later */
int (*autovacuum_pages)(sqlite3*,
unsigned int(*)(void*,const char*,unsigned int,unsigned int,unsigned int),
void*, void(*)(void*));
/* Version 3.38.0 and later */
int (*error_offset)(sqlite3*);
int (*vtab_rhs_value)(sqlite3_index_info*,int,sqlite3_value**);
int (*vtab_distinct)(sqlite3_index_info*);
int (*vtab_in)(sqlite3_index_info*,int,int);
int (*vtab_in_first)(sqlite3_value*,sqlite3_value**);
int (*vtab_in_next)(sqlite3_value*,sqlite3_value**);
/* Version 3.39.0 and later */
int (*deserialize)(sqlite3*,const char*,unsigned char*,
sqlite3_int64,sqlite3_int64,unsigned);
unsigned char *(*serialize)(sqlite3*,const char *,sqlite3_int64*,
unsigned int);
const char *(*db_name)(sqlite3*,int);
/* Version 3.40.0 and later */
int (*value_encoding)(sqlite3_value*);
/* Version 3.41.0 and later */
int (*is_interrupted)(sqlite3*);
/* Version 3.43.0 and later */
int (*stmt_explain)(sqlite3_stmt*,int);
/* Version 3.44.0 and later */
void *(*get_clientdata)(sqlite3*,const char*);
int (*set_clientdata)(sqlite3*, const char*, void*, void(*)(void*));
};
/*
** This is the function signature used for all extension entry points. It
** is also defined in the file "loadext.c".
*/
typedef int (*sqlite3_loadext_entry)(
sqlite3 *db, /* Handle to the database. */
char **pzErrMsg, /* Used to set error string on failure. */
const sqlite3_api_routines *pThunk /* Extension API function pointers. */
);
/*
** The following macros redefine the API routines so that they are
** redirected through the global sqlite3_api structure.
**
** This header file is also used by the loadext.c source file
** (part of the main SQLite library - not an extension) so that
** it can get access to the sqlite3_api_routines structure
** definition. But the main library does not want to redefine
** the API. So the redefinition macros are only valid if the
** SQLITE_CORE macros is undefined.
*/
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
#define sqlite3_aggregate_context sqlite3_api->aggregate_context
#ifndef SQLITE_OMIT_DEPRECATED
#define sqlite3_aggregate_count sqlite3_api->aggregate_count
#endif
#define sqlite3_bind_blob sqlite3_api->bind_blob
#define sqlite3_bind_double sqlite3_api->bind_double
#define sqlite3_bind_int sqlite3_api->bind_int
#define sqlite3_bind_int64 sqlite3_api->bind_int64
#define sqlite3_bind_null sqlite3_api->bind_null
#define sqlite3_bind_parameter_count sqlite3_api->bind_parameter_count
#define sqlite3_bind_parameter_index sqlite3_api->bind_parameter_index
#define sqlite3_bind_parameter_name sqlite3_api->bind_parameter_name
#define sqlite3_bind_text sqlite3_api->bind_text
#define sqlite3_bind_text16 sqlite3_api->bind_text16
#define sqlite3_bind_value sqlite3_api->bind_value
#define sqlite3_busy_handler sqlite3_api->busy_handler
#define sqlite3_busy_timeout sqlite3_api->busy_timeout
#define sqlite3_changes sqlite3_api->changes
#define sqlite3_close sqlite3_api->close
#define sqlite3_collation_needed sqlite3_api->collation_needed
#define sqlite3_collation_needed16 sqlite3_api->collation_needed16
#define sqlite3_column_blob sqlite3_api->column_blob
#define sqlite3_column_bytes sqlite3_api->column_bytes
#define sqlite3_column_bytes16 sqlite3_api->column_bytes16
#define sqlite3_column_count sqlite3_api->column_count
#define sqlite3_column_database_name sqlite3_api->column_database_name
#define sqlite3_column_database_name16 sqlite3_api->column_database_name16
#define sqlite3_column_decltype sqlite3_api->column_decltype
#define sqlite3_column_decltype16 sqlite3_api->column_decltype16
#define sqlite3_column_double sqlite3_api->column_double
#define sqlite3_column_int sqlite3_api->column_int
#define sqlite3_column_int64 sqlite3_api->column_int64
#define sqlite3_column_name sqlite3_api->column_name
#define sqlite3_column_name16 sqlite3_api->column_name16
#define sqlite3_column_origin_name sqlite3_api->column_origin_name
#define sqlite3_column_origin_name16 sqlite3_api->column_origin_name16
#define sqlite3_column_table_name sqlite3_api->column_table_name
#define sqlite3_column_table_name16 sqlite3_api->column_table_name16
#define sqlite3_column_text sqlite3_api->column_text
#define sqlite3_column_text16 sqlite3_api->column_text16
#define sqlite3_column_type sqlite3_api->column_type
#define sqlite3_column_value sqlite3_api->column_value
#define sqlite3_commit_hook sqlite3_api->commit_hook
#define sqlite3_complete sqlite3_api->complete
#define sqlite3_complete16 sqlite3_api->complete16
#define sqlite3_create_collation sqlite3_api->create_collation
#define sqlite3_create_collation16 sqlite3_api->create_collation16
#define sqlite3_create_function sqlite3_api->create_function
#define sqlite3_create_function16 sqlite3_api->create_function16
#define sqlite3_create_module sqlite3_api->create_module
#define sqlite3_create_module_v2 sqlite3_api->create_module_v2
#define sqlite3_data_count sqlite3_api->data_count
#define sqlite3_db_handle sqlite3_api->db_handle
#define sqlite3_declare_vtab sqlite3_api->declare_vtab
#define sqlite3_enable_shared_cache sqlite3_api->enable_shared_cache
#define sqlite3_errcode sqlite3_api->errcode
#define sqlite3_errmsg sqlite3_api->errmsg
#define sqlite3_errmsg16 sqlite3_api->errmsg16
#define sqlite3_exec sqlite3_api->exec
#ifndef SQLITE_OMIT_DEPRECATED
#define sqlite3_expired sqlite3_api->expired
#endif
#define sqlite3_finalize sqlite3_api->finalize
#define sqlite3_free sqlite3_api->free
#define sqlite3_free_table sqlite3_api->free_table
#define sqlite3_get_autocommit sqlite3_api->get_autocommit
#define sqlite3_get_auxdata sqlite3_api->get_auxdata
#define sqlite3_get_table sqlite3_api->get_table
#ifndef SQLITE_OMIT_DEPRECATED
#define sqlite3_global_recover sqlite3_api->global_recover
#endif
#define sqlite3_interrupt sqlite3_api->interruptx
#define sqlite3_last_insert_rowid sqlite3_api->last_insert_rowid
#define sqlite3_libversion sqlite3_api->libversion
#define sqlite3_libversion_number sqlite3_api->libversion_number
#define sqlite3_malloc sqlite3_api->malloc
#define sqlite3_mprintf sqlite3_api->mprintf
#define sqlite3_open sqlite3_api->open
#define sqlite3_open16 sqlite3_api->open16
#define sqlite3_prepare sqlite3_api->prepare
#define sqlite3_prepare16 sqlite3_api->prepare16
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
#define sqlite3_profile sqlite3_api->profile
#define sqlite3_progress_handler sqlite3_api->progress_handler
#define sqlite3_realloc sqlite3_api->realloc
#define sqlite3_reset sqlite3_api->reset
#define sqlite3_result_blob sqlite3_api->result_blob
#define sqlite3_result_double sqlite3_api->result_double
#define sqlite3_result_error sqlite3_api->result_error
#define sqlite3_result_error16 sqlite3_api->result_error16
#define sqlite3_result_int sqlite3_api->result_int
#define sqlite3_result_int64 sqlite3_api->result_int64
#define sqlite3_result_null sqlite3_api->result_null
#define sqlite3_result_text sqlite3_api->result_text
#define sqlite3_result_text16 sqlite3_api->result_text16
#define sqlite3_result_text16be sqlite3_api->result_text16be
#define sqlite3_result_text16le sqlite3_api->result_text16le
#define sqlite3_result_value sqlite3_api->result_value
#define sqlite3_rollback_hook sqlite3_api->rollback_hook
#define sqlite3_set_authorizer sqlite3_api->set_authorizer
#define sqlite3_set_auxdata sqlite3_api->set_auxdata
#define sqlite3_snprintf sqlite3_api->xsnprintf
#define sqlite3_step sqlite3_api->step
#define sqlite3_table_column_metadata sqlite3_api->table_column_metadata
#define sqlite3_thread_cleanup sqlite3_api->thread_cleanup
#define sqlite3_total_changes sqlite3_api->total_changes
#define sqlite3_trace sqlite3_api->trace
#ifndef SQLITE_OMIT_DEPRECATED
#define sqlite3_transfer_bindings sqlite3_api->transfer_bindings
#endif
#define sqlite3_update_hook sqlite3_api->update_hook
#define sqlite3_user_data sqlite3_api->user_data
#define sqlite3_value_blob sqlite3_api->value_blob
#define sqlite3_value_bytes sqlite3_api->value_bytes
#define sqlite3_value_bytes16 sqlite3_api->value_bytes16
#define sqlite3_value_double sqlite3_api->value_double
#define sqlite3_value_int sqlite3_api->value_int
#define sqlite3_value_int64 sqlite3_api->value_int64
#define sqlite3_value_numeric_type sqlite3_api->value_numeric_type
#define sqlite3_value_text sqlite3_api->value_text
#define sqlite3_value_text16 sqlite3_api->value_text16
#define sqlite3_value_text16be sqlite3_api->value_text16be
#define sqlite3_value_text16le sqlite3_api->value_text16le
#define sqlite3_value_type sqlite3_api->value_type
#define sqlite3_vmprintf sqlite3_api->vmprintf
#define sqlite3_vsnprintf sqlite3_api->xvsnprintf
#define sqlite3_overload_function sqlite3_api->overload_function
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
#define sqlite3_clear_bindings sqlite3_api->clear_bindings
#define sqlite3_bind_zeroblob sqlite3_api->bind_zeroblob
#define sqlite3_blob_bytes sqlite3_api->blob_bytes
#define sqlite3_blob_close sqlite3_api->blob_close
#define sqlite3_blob_open sqlite3_api->blob_open
#define sqlite3_blob_read sqlite3_api->blob_read
#define sqlite3_blob_write sqlite3_api->blob_write
#define sqlite3_create_collation_v2 sqlite3_api->create_collation_v2
#define sqlite3_file_control sqlite3_api->file_control
#define sqlite3_memory_highwater sqlite3_api->memory_highwater
#define sqlite3_memory_used sqlite3_api->memory_used
#define sqlite3_mutex_alloc sqlite3_api->mutex_alloc
#define sqlite3_mutex_enter sqlite3_api->mutex_enter
#define sqlite3_mutex_free sqlite3_api->mutex_free
#define sqlite3_mutex_leave sqlite3_api->mutex_leave
#define sqlite3_mutex_try sqlite3_api->mutex_try
#define sqlite3_open_v2 sqlite3_api->open_v2
#define sqlite3_release_memory sqlite3_api->release_memory
#define sqlite3_result_error_nomem sqlite3_api->result_error_nomem
#define sqlite3_result_error_toobig sqlite3_api->result_error_toobig
#define sqlite3_sleep sqlite3_api->sleep
#define sqlite3_soft_heap_limit sqlite3_api->soft_heap_limit
#define sqlite3_vfs_find sqlite3_api->vfs_find
#define sqlite3_vfs_register sqlite3_api->vfs_register
#define sqlite3_vfs_unregister sqlite3_api->vfs_unregister
#define sqlite3_threadsafe sqlite3_api->xthreadsafe
#define sqlite3_result_zeroblob sqlite3_api->result_zeroblob
#define sqlite3_result_error_code sqlite3_api->result_error_code
#define sqlite3_test_control sqlite3_api->test_control
#define sqlite3_randomness sqlite3_api->randomness
#define sqlite3_context_db_handle sqlite3_api->context_db_handle
#define sqlite3_extended_result_codes sqlite3_api->extended_result_codes
#define sqlite3_limit sqlite3_api->limit
#define sqlite3_next_stmt sqlite3_api->next_stmt
#define sqlite3_sql sqlite3_api->sql
#define sqlite3_status sqlite3_api->status
#define sqlite3_backup_finish sqlite3_api->backup_finish
#define sqlite3_backup_init sqlite3_api->backup_init
#define sqlite3_backup_pagecount sqlite3_api->backup_pagecount
#define sqlite3_backup_remaining sqlite3_api->backup_remaining
#define sqlite3_backup_step sqlite3_api->backup_step
#define sqlite3_compileoption_get sqlite3_api->compileoption_get
#define sqlite3_compileoption_used sqlite3_api->compileoption_used
#define sqlite3_create_function_v2 sqlite3_api->create_function_v2
#define sqlite3_db_config sqlite3_api->db_config
#define sqlite3_db_mutex sqlite3_api->db_mutex
#define sqlite3_db_status sqlite3_api->db_status
#define sqlite3_extended_errcode sqlite3_api->extended_errcode
#define sqlite3_log sqlite3_api->log
#define sqlite3_soft_heap_limit64 sqlite3_api->soft_heap_limit64
#define sqlite3_sourceid sqlite3_api->sourceid
#define sqlite3_stmt_status sqlite3_api->stmt_status
#define sqlite3_strnicmp sqlite3_api->strnicmp
#define sqlite3_unlock_notify sqlite3_api->unlock_notify
#define sqlite3_wal_autocheckpoint sqlite3_api->wal_autocheckpoint
#define sqlite3_wal_checkpoint sqlite3_api->wal_checkpoint
#define sqlite3_wal_hook sqlite3_api->wal_hook
#define sqlite3_blob_reopen sqlite3_api->blob_reopen
#define sqlite3_vtab_config sqlite3_api->vtab_config
#define sqlite3_vtab_on_conflict sqlite3_api->vtab_on_conflict
/* Version 3.7.16 and later */
#define sqlite3_close_v2 sqlite3_api->close_v2
#define sqlite3_db_filename sqlite3_api->db_filename
#define sqlite3_db_readonly sqlite3_api->db_readonly
#define sqlite3_db_release_memory sqlite3_api->db_release_memory
#define sqlite3_errstr sqlite3_api->errstr
#define sqlite3_stmt_busy sqlite3_api->stmt_busy
#define sqlite3_stmt_readonly sqlite3_api->stmt_readonly
#define sqlite3_stricmp sqlite3_api->stricmp
#define sqlite3_uri_boolean sqlite3_api->uri_boolean
#define sqlite3_uri_int64 sqlite3_api->uri_int64
#define sqlite3_uri_parameter sqlite3_api->uri_parameter
#define sqlite3_uri_vsnprintf sqlite3_api->xvsnprintf
#define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2
/* Version 3.8.7 and later */
#define sqlite3_auto_extension sqlite3_api->auto_extension
#define sqlite3_bind_blob64 sqlite3_api->bind_blob64
#define sqlite3_bind_text64 sqlite3_api->bind_text64
#define sqlite3_cancel_auto_extension sqlite3_api->cancel_auto_extension
#define sqlite3_load_extension sqlite3_api->load_extension
#define sqlite3_malloc64 sqlite3_api->malloc64
#define sqlite3_msize sqlite3_api->msize
#define sqlite3_realloc64 sqlite3_api->realloc64
#define sqlite3_reset_auto_extension sqlite3_api->reset_auto_extension
#define sqlite3_result_blob64 sqlite3_api->result_blob64
#define sqlite3_result_text64 sqlite3_api->result_text64
#define sqlite3_strglob sqlite3_api->strglob
/* Version 3.8.11 and later */
#define sqlite3_value_dup sqlite3_api->value_dup
#define sqlite3_value_free sqlite3_api->value_free
#define sqlite3_result_zeroblob64 sqlite3_api->result_zeroblob64
#define sqlite3_bind_zeroblob64 sqlite3_api->bind_zeroblob64
/* Version 3.9.0 and later */
#define sqlite3_value_subtype sqlite3_api->value_subtype
#define sqlite3_result_subtype sqlite3_api->result_subtype
/* Version 3.10.0 and later */
#define sqlite3_status64 sqlite3_api->status64
#define sqlite3_strlike sqlite3_api->strlike
#define sqlite3_db_cacheflush sqlite3_api->db_cacheflush
/* Version 3.12.0 and later */
#define sqlite3_system_errno sqlite3_api->system_errno
/* Version 3.14.0 and later */
#define sqlite3_trace_v2 sqlite3_api->trace_v2
#define sqlite3_expanded_sql sqlite3_api->expanded_sql
/* Version 3.18.0 and later */
#define sqlite3_set_last_insert_rowid sqlite3_api->set_last_insert_rowid
/* Version 3.20.0 and later */
#define sqlite3_prepare_v3 sqlite3_api->prepare_v3
#define sqlite3_prepare16_v3 sqlite3_api->prepare16_v3
#define sqlite3_bind_pointer sqlite3_api->bind_pointer
#define sqlite3_result_pointer sqlite3_api->result_pointer
#define sqlite3_value_pointer sqlite3_api->value_pointer
/* Version 3.22.0 and later */
#define sqlite3_vtab_nochange sqlite3_api->vtab_nochange
#define sqlite3_value_nochange sqlite3_api->value_nochange
#define sqlite3_vtab_collation sqlite3_api->vtab_collation
/* Version 3.24.0 and later */
#define sqlite3_keyword_count sqlite3_api->keyword_count
#define sqlite3_keyword_name sqlite3_api->keyword_name
#define sqlite3_keyword_check sqlite3_api->keyword_check
#define sqlite3_str_new sqlite3_api->str_new
#define sqlite3_str_finish sqlite3_api->str_finish
#define sqlite3_str_appendf sqlite3_api->str_appendf
#define sqlite3_str_vappendf sqlite3_api->str_vappendf
#define sqlite3_str_append sqlite3_api->str_append
#define sqlite3_str_appendall sqlite3_api->str_appendall
#define sqlite3_str_appendchar sqlite3_api->str_appendchar
#define sqlite3_str_reset sqlite3_api->str_reset
#define sqlite3_str_errcode sqlite3_api->str_errcode
#define sqlite3_str_length sqlite3_api->str_length
#define sqlite3_str_value sqlite3_api->str_value
/* Version 3.25.0 and later */
#define sqlite3_create_window_function sqlite3_api->create_window_function
/* Version 3.26.0 and later */
#define sqlite3_normalized_sql sqlite3_api->normalized_sql
/* Version 3.28.0 and later */
#define sqlite3_stmt_isexplain sqlite3_api->stmt_isexplain
#define sqlite3_value_frombind sqlite3_api->value_frombind
/* Version 3.30.0 and later */
#define sqlite3_drop_modules sqlite3_api->drop_modules
/* Version 3.31.0 and later */
#define sqlite3_hard_heap_limit64 sqlite3_api->hard_heap_limit64
#define sqlite3_uri_key sqlite3_api->uri_key
#define sqlite3_filename_database sqlite3_api->filename_database
#define sqlite3_filename_journal sqlite3_api->filename_journal
#define sqlite3_filename_wal sqlite3_api->filename_wal
/* Version 3.32.0 and later */
#define sqlite3_create_filename sqlite3_api->create_filename
#define sqlite3_free_filename sqlite3_api->free_filename
#define sqlite3_database_file_object sqlite3_api->database_file_object
/* Version 3.34.0 and later */
#define sqlite3_txn_state sqlite3_api->txn_state
/* Version 3.36.1 and later */
#define sqlite3_changes64 sqlite3_api->changes64
#define sqlite3_total_changes64 sqlite3_api->total_changes64
/* Version 3.37.0 and later */
#define sqlite3_autovacuum_pages sqlite3_api->autovacuum_pages
/* Version 3.38.0 and later */
#define sqlite3_error_offset sqlite3_api->error_offset
#define sqlite3_vtab_rhs_value sqlite3_api->vtab_rhs_value
#define sqlite3_vtab_distinct sqlite3_api->vtab_distinct
#define sqlite3_vtab_in sqlite3_api->vtab_in
#define sqlite3_vtab_in_first sqlite3_api->vtab_in_first
#define sqlite3_vtab_in_next sqlite3_api->vtab_in_next
/* Version 3.39.0 and later */
#ifndef SQLITE_OMIT_DESERIALIZE
#define sqlite3_deserialize sqlite3_api->deserialize
#define sqlite3_serialize sqlite3_api->serialize
#endif
#define sqlite3_db_name sqlite3_api->db_name
/* Version 3.40.0 and later */
#define sqlite3_value_encoding sqlite3_api->value_encoding
/* Version 3.41.0 and later */
#define sqlite3_is_interrupted sqlite3_api->is_interrupted
/* Version 3.43.0 and later */
#define sqlite3_stmt_explain sqlite3_api->stmt_explain
/* Version 3.44.0 and later */
#define sqlite3_get_clientdata sqlite3_api->get_clientdata
#define sqlite3_set_clientdata sqlite3_api->set_clientdata
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
/* This case when the file really is being compiled as a loadable
** extension */
# define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0;
# define SQLITE_EXTENSION_INIT2(v) sqlite3_api=v;
# define SQLITE_EXTENSION_INIT3 \
extern const sqlite3_api_routines *sqlite3_api;
#else
/* This case when the file is being statically linked into the
** application */
# define SQLITE_EXTENSION_INIT1 /*no-op*/
# define SQLITE_EXTENSION_INIT2(v) (void)v; /* unused parameter */
# define SQLITE_EXTENSION_INIT3 /*no-op*/
#endif
#endif /* SQLITE3EXT_H */
+113
View File
@@ -316,6 +316,118 @@ String compiler_process_text_literal(Request* context, SharedUnit* su, String co
return(parsed_content);
}
bool compiler_line_starts_entrypoint(String trimmed, String macro_name)
{
if(trimmed.rfind(macro_name + "(", 0) == 0)
return(true);
return(trimmed.rfind(macro_name + ":", 0) == 0 && trimmed.find("(") != String::npos);
}
bool compiler_line_starts_fragmentable_entrypoint(String trimmed, String& kind)
{
if(compiler_line_starts_entrypoint(trimmed, "ONCE"))
{
kind = "ONCE";
return(true);
}
if(compiler_line_starts_entrypoint(trimmed, "RENDER"))
{
kind = "RENDER";
return(true);
}
if(compiler_line_starts_entrypoint(trimmed, "COMPONENT"))
{
kind = "COMPONENT";
return(true);
}
return(false);
}
String compiler_fragment_capture_prelude(String slot)
{
return("\nstruct __UceFragmentCapture { Request& context; String slot; __UceFragmentCapture(Request& c, String s) : context(c), slot(s) { ob_start(); } ~__UceFragmentCapture() { String html = ob_get_close(); if(html != \"\") context.call[\"fragments\"][slot] = context.call[\"fragments\"][slot].to_string() + html; } }; __UceFragmentCapture __uce_fragment_capture(context, " + compiler_cpp_string_literal(slot) + ");\n");
}
String compiler_rewrite_fragment_attributes(String content)
{
StringList lines = split(content, "\n");
String result;
for(u32 i = 0; i < lines.size(); i++)
{
String line = lines[i];
String kind;
if(!compiler_line_starts_fragmentable_entrypoint(trim(line), kind))
{
result += line;
if(i + 1 < lines.size())
result += "\n";
continue;
}
String slot = (kind == "ONCE" ? "once" : "");
StringList pending;
bool has_fragment_attr = false;
u32 j = i + 1;
while(j < lines.size())
{
String attr_line = lines[j];
String attr_trimmed = trim(attr_line);
if(attr_trimmed.rfind("@fragment", 0) == 0 && (attr_trimmed.length() == 9 || isspace((unsigned char)attr_trimmed[9])))
{
slot = trim(attr_trimmed.substr(9));
has_fragment_attr = true;
j++;
continue;
}
break;
}
bool should_capture = (slot != "") && (kind == "ONCE" || has_fragment_attr);
if(!should_capture)
{
result += line;
if(j < lines.size())
result += "\n";
i = j - 1;
continue;
}
auto declaration_brace_pos = line.find("{");
if(declaration_brace_pos != String::npos)
{
result += line.substr(0, declaration_brace_pos + 1) + compiler_fragment_capture_prelude(slot) + line.substr(declaration_brace_pos + 1);
if(j < lines.size())
result += "\n";
i = j - 1;
continue;
}
result += line;
if(j < lines.size())
result += "\n";
while(j < lines.size())
{
String body_line = lines[j];
auto brace_pos = body_line.find("{");
if(brace_pos == String::npos)
{
result += body_line;
if(j + 1 < lines.size())
result += "\n";
j++;
continue;
}
result += body_line.substr(0, brace_pos + 1) + compiler_fragment_capture_prelude(slot) + body_line.substr(brace_pos + 1);
if(j + 1 < lines.size())
result += "\n";
i = j;
break;
}
}
return(result);
}
bool compiler_rewrite_named_entrypoint_line(String& line, String macro_prefix, String symbol_prefix)
{
u32 indent_length = 0;
@@ -484,6 +596,7 @@ String compiler_preprocess_shared_unit_char_wise(Request* context, SharedUnit* s
String compiler_preprocess_source(Request* context, SharedUnit* su, String content)
{
content = compiler_rewrite_fragment_attributes(content);
content = compiler_rewrite_named_render_syntax(content);
return(compiler_preprocess_shared_unit_char_wise(context, su, content));
}
+109 -12
View File
@@ -3,6 +3,7 @@
#include "hash.h"
#include <algorithm>
#include <cstdlib>
#include <cctype>
#include <filesystem>
#include <sys/file.h>
#include <unistd.h>
@@ -17,7 +18,7 @@ const char* UCE_CLI_SYMBOL = "__uce_cli";
const char* UCE_SERVE_HTTP_SYMBOL = "__uce_serve_http";
const char* UCE_ONCE_SYMBOL = "__uce_once";
const char* UCE_INIT_SYMBOL = "__uce_init";
const u64 UCE_UNIT_ABI_VERSION = 1;
const u64 UCE_UNIT_ABI_VERSION = 2;
struct SharedUnitFilesystemState
{
@@ -282,9 +283,19 @@ auto compiler_with_registry_lock(Request* context, TCallback callback) -> declty
{
auto lock_file_name = compiler_registry_lock_file_name(context);
int fdlock = compiler_open_lock_file(lock_file_name, "compiler-registry");
auto result = callback();
compiler_close_lock_file(fdlock);
return(result);
if(fdlock == -1)
throw std::runtime_error("could not open compiler registry lock: " + lock_file_name);
try
{
auto result = callback();
compiler_close_lock_file(fdlock);
return(result);
}
catch(...)
{
compiler_close_lock_file(fdlock);
throw;
}
}
bool compiler_has_known_unit_cached(Request* context, String file_name)
@@ -609,6 +620,20 @@ String preprocess_shared_unit(Request* context, SharedUnit* su)
return(compiler_preprocess_source(context, su, content));
}
String compiler_generated_cpp_path(Request* context, String source_file)
{
if(!context || !context->server || source_file == "")
return("");
return(context->server->config["BIN_DIRECTORY"] + dirname(source_file) + "/" + basename(source_file) + ".cpp");
}
String compiler_generated_cpp_path(SharedUnit* su)
{
if(!su)
return("");
return(su->pre_path + "/" + su->pre_file_name);
}
void setup_unit_paths(Request* context, SharedUnit* su, String file_name)
{
su->file_name = file_name;
@@ -722,6 +747,72 @@ void load_shared_unit(Request* context, SharedUnit* su)
return(result);
}*/
s64 compiler_first_error_line_for_path(String messages, String path)
{
if(path == "")
return(-1);
String needle = path + ":";
auto pos = messages.find(needle);
if(pos == String::npos)
return(-1);
pos += needle.length();
String digits;
while(pos < messages.length() && isdigit((unsigned char)messages[pos]))
{
digits.append(1, messages[pos]);
pos += 1;
}
if(digits == "")
return(-1);
return(int_val(digits));
}
String compiler_source_excerpt(String file_name, s64 line_number, u64 radius = 3)
{
if(file_name == "" || line_number <= 0 || !file_exists(file_name))
return("");
auto lines = split(file_get_contents(file_name), "\n");
if(lines.size() == 0)
return("");
s64 start = line_number - (s64)radius;
if(start < 1)
start = 1;
s64 end = line_number + (s64)radius;
if(end > (s64)lines.size())
end = lines.size();
String result;
for(s64 i = start; i <= end; i++)
{
String marker = (i == line_number ? "> " : " ");
result += marker + std::to_string((u64)i) + " | " + lines[i - 1] + "\n";
}
return(result);
}
String compiler_format_compile_failure(SharedUnit* su, String raw_messages)
{
String generated_file = compiler_generated_cpp_path(su);
String result = "UCE compile error\n";
result += "Source: " + su->file_name + "\n";
result += "Generated C++: " + generated_file + "\n";
result += "Compile output: " + su->compile_output_file_name + "\n";
s64 source_line = compiler_first_error_line_for_path(raw_messages, su->file_name);
String excerpt = compiler_source_excerpt(su->file_name, source_line);
if(excerpt != "")
result += "\nSource excerpt:\n" + excerpt;
else
{
s64 generated_line = compiler_first_error_line_for_path(raw_messages, generated_file);
String generated_excerpt = compiler_source_excerpt(generated_file, generated_line);
if(generated_excerpt != "")
result += "\nGenerated C++ excerpt:\n" + generated_excerpt;
}
result += "\nCompiler output:\n" + trim(raw_messages) + "\n";
return(result);
}
void compile_shared_unit(Request* context, SharedUnit* su)
{
f64 comp_start = time_precise();
@@ -737,11 +828,10 @@ void compile_shared_unit(Request* context, SharedUnit* su)
shell_exec("mkdir -p " + shell_escape(su->pre_path));
file_put_contents(su->pre_path + "/" + su->pre_file_name, preprocess_shared_unit(context, su));
//file_put_contents(su->setup_file_name, compile_setup_file(context, su));
file_put_contents(su->api_file_name, join(su->api_declarations, "\n"));
if(!su->opt_so_optional)
su->compiler_messages = trim(shell_exec(context->server->config["COMPILE_SCRIPT"]+" "+
su->compiler_messages = trim(shell_exec(shell_escape(context->server->config["COMPILE_SCRIPT"])+" "+
shell_escape(su->src_path)+" "+
shell_escape(su->bin_path)+" "+
shell_escape(su->file_name)+" "+
@@ -751,9 +841,10 @@ void compile_shared_unit(Request* context, SharedUnit* su)
if(su->compiler_messages.length() > 0)
{
file_put_contents(su->compile_output_file_name, su->compiler_messages + "\n");
compiler_record_compile_result(su, time_precise() - comp_start, false, "compile_error", su->compiler_messages);
printf("%s \n", su->compiler_messages.c_str());
String raw_messages = su->compiler_messages;
file_put_contents(su->compile_output_file_name, raw_messages + "\n");
compiler_record_compile_result(su, time_precise() - comp_start, false, "compile_error", raw_messages);
printf("%s \n", compiler_format_compile_failure(su, raw_messages).c_str());
}
else
{
@@ -898,11 +989,17 @@ SharedUnit* compiler_load_shared_unit(Request* context, String file_name, String
}
else if(su->compiler_messages.length() > 0)
{
printf("%s\n", su->compiler_messages.c_str());
String display_messages = su->compiler_messages;
if(su->compile_status == "compile_error")
display_messages = compiler_format_compile_failure(su, su->compiler_messages);
printf("%s\n", display_messages.c_str());
if(compiler_can_write_response(context) && context->stats.invoke_count == 1)
context->header["Content-Type"] = "text/plain";
{
context->set_status(500, "UCE Unit Compile Error");
context->header["Content-Type"] = "text/plain; charset=utf-8";
}
if(compiler_can_write_response(context))
print(su->compiler_messages);
print(display_messages);
return(0);
}
else
+2
View File
@@ -10,6 +10,8 @@
#define EXPORT extern "C"
String preprocess_shared_unit(Request* context, SharedUnit* su);
String compiler_generated_cpp_path(Request* context, String source_file);
String compiler_generated_cpp_path(SharedUnit* su);
void setup_unit_paths(Request* context, SharedUnit* su, String file_name);
void load_shared_unit(Request* context, SharedUnit* su);
void compile_shared_unit(Request* context, SharedUnit* su);
+7 -2
View File
@@ -140,7 +140,7 @@ u64 dtree_clamp_to_u64_range(long double value)
}
void DTree::each(std::function <void (DTree t, String key)> f)
void DTree::each(std::function <void (const DTree& t, String key)> f)
{
const DTree& target = deref();
switch(target.type)
@@ -695,7 +695,7 @@ void DTree::operator = (void* v) { set(v); }
void DTree::operator = (DTree v) { set(v); }
void DTree::operator = (StringMap v) { set(v); }
void DTree::push(DTree& child)
void DTree::push(const DTree& child)
{
DTree* target = reference_target();
if(target)
@@ -733,6 +733,11 @@ DTree DTree::pop()
if(target)
return(target->pop());
set_type('M');
if(_map.empty())
{
_array_index = 0;
return(DTree());
}
auto last = _map.rbegin();
DTree result = last->second;
_map.erase(last->first);
+2 -2
View File
@@ -19,7 +19,7 @@ struct DTree {
void* _ptr;
std::map<String, DTree> _map;
void each(std::function <void (DTree t, String key)> f);
void each(std::function <void (const DTree& t, String key)> f);
bool is_array();
bool is_list() const;
String to_string();
@@ -56,7 +56,7 @@ struct DTree {
void operator = (DTree v);
void operator = (StringMap v);
void push(DTree& child);
void push(const DTree& child);
DTree pop();
void remove(String s);
void clear();
+192 -61
View File
@@ -4,6 +4,7 @@
#include <pcre2.h>
#include <cctype>
#include <stdexcept>
#include <algorithm>
String var_dump(StringMap map, String prefix, String postfix)
{
@@ -59,6 +60,145 @@ String to_upper(String s)
return(result);
}
StringList list_unique(StringList items)
{
StringList result;
std::set<String> seen;
for(auto item : items)
{
if(seen.find(item) != seen.end())
continue;
seen.insert(item);
result.push_back(item);
}
return(result);
}
StringList list_sort(StringList items)
{
std::sort(items.begin(), items.end());
return(items);
}
bool list_some(StringList items, std::function<bool (String)> f)
{
for(auto item : items)
{
if(f(item))
return(true);
}
return(false);
}
bool list_every(StringList items, std::function<bool (String)> f)
{
for(auto item : items)
{
if(!f(item))
return(false);
}
return(true);
}
String list_find(StringList items, std::function<bool (String)> f, String fallback)
{
for(auto item : items)
{
if(f(item))
return(item);
}
return(fallback);
}
StringList dtree_keys(DTree tree)
{
StringList result;
tree.each([&](const DTree& item, String key) {
if(key != "")
result.push_back(key);
});
return(result);
}
DTree dtree_values(DTree tree)
{
DTree result;
result.set_array();
tree.each([&](const DTree& item, String key) {
result.push(item);
});
return(result);
}
DTree dtree_pick(DTree tree, StringList keys)
{
DTree result;
for(auto key : keys)
{
DTree* item = tree.key(key);
if(item)
result[key] = *item;
}
return(result);
}
DTree dtree_omit(DTree tree, StringList keys)
{
DTree result;
std::set<String> omitted(keys.begin(), keys.end());
tree.each([&](const DTree& item, String key) {
if(key != "" && omitted.find(key) == omitted.end())
result[key] = item;
});
return(result);
}
DTree dtree_map(DTree tree, std::function<DTree (const DTree&, String)> f)
{
DTree result;
bool input_is_list = tree.is_list();
if(input_is_list)
result.set_array();
tree.each([&](const DTree& item, String key) {
DTree mapped = f(item, key);
if(key != "" && !input_is_list)
result[key] = mapped;
else
result.push(mapped);
});
return(result);
}
DTree dtree_filter(DTree tree, std::function<bool (const DTree&, String)> f)
{
DTree result;
bool input_is_list = tree.is_list();
if(input_is_list)
result.set_array();
tree.each([&](const DTree& item, String key) {
if(!f(item, key))
return;
if(key != "" && !input_is_list)
result[key] = item;
else
result.push(item);
});
return(result);
}
DTree dtree_group_by(DTree tree, std::function<String (const DTree&, String)> f)
{
DTree result;
tree.each([&](const DTree& item, String key) {
String group = f(item, key);
DTree* group_items = result.get_or_create(group);
if(!group_items->is_array())
group_items->set_array();
group_items->push(item);
});
return(result);
}
String substr(String s, s64 start_pos)
{
s64 len = s.length();
@@ -502,11 +642,11 @@ String trim(String raw)
s64 len = raw.length();
s64 start_pos = 0;
s64 end_pos = len - 1;
if(len == 0 || (len == 1 && isspace(raw[0])))
if(len == 0 || (len == 1 && isspace((unsigned char)raw[0])))
return("");
while(start_pos < len && isspace(raw[start_pos]))
while(start_pos < len && isspace((unsigned char)raw[start_pos]))
start_pos++;
while(end_pos >= 0 && isspace(raw[end_pos]))
while(end_pos >= 0 && isspace((unsigned char)raw[end_pos]))
end_pos--;
if(end_pos < start_pos)
return("");
@@ -519,7 +659,7 @@ StringList split_space(String str)
String current_token = "";
for(auto c : str)
{
if(isspace(c))
if(isspace((unsigned char)c))
{
if(current_token != "")
{
@@ -540,6 +680,11 @@ StringList split_space(String str)
StringList split(String str, String delim)
{
StringList result;
if(delim == "")
{
result.push_back(str);
return(result);
}
int start = 0;
int end = str.find(delim);
while (end != String::npos)
@@ -562,14 +707,16 @@ StringMap split_kv(String s, char separator, bool trim_whitespace, bool uppercas
u8 mode = 0;
k = "";
v = "";
if(s[0] != '#') for(auto c : s)
if(s == "" || s[0] == '#')
continue;
for(auto c : s)
{
if(mode == 0)
{
if(c == separator)
mode = 1;
else
k.append(1, uppercase_keys ? toupper(c) : c);
k.append(1, uppercase_keys ? toupper((unsigned char)c) : c);
}
else
{
@@ -590,62 +737,43 @@ StringMap split_kv(String s, char separator, bool trim_whitespace, bool uppercas
StringMap split_http_headers(String s)
{
StringMap result;
String k;
String v;
String query_string;
String base_uri;
for(auto s : split(s, "\n"))
StringList lines = split(s, "\n");
if(lines.size() == 0)
return(result);
u64 header_start = 0;
while(header_start < lines.size() && trim(lines[header_start]) == "")
header_start++;
if(header_start < lines.size() && lines[header_start].find(':') == String::npos)
{
u8 mode = 0;
k = "";
v = "";
for(auto c : s)
{
if(mode == 0)
{
if(c == ':')
mode = 1;
else
k.append(1, c);
}
else
{
v.append(1, c);
}
}
if(k != "")
{
k = trim(k);
v = trim(v);
if(v == "")
{
if(result["REQUEST_METHOD"] == "")
{
result["REQUEST_METHOD"] = nibble(k, " ");
result["REQUEST_URI"] = nibble(k, " ");
String query_string = result["REQUEST_URI"];
String base_uri = nibble(query_string, "?");
result["SERVER_PROTOCOL"] = k;
result["SCRIPT_NAME"] = base_uri;
result["DOCUMENT_URI"] = base_uri;
result["QUERY_STRING"] = query_string;
}
else
{
if(k != "")
result["_"] = k;
}
}
else
{
String header_key = to_upper(k);
std::replace(header_key.begin(), header_key.end(), '-', '_');
result["HTTP_"+header_key] = v;
if(header_key == "CONTENT_TYPE" || header_key == "CONTENT_LENGTH")
result[header_key] = v;
}
}
}
String request_line = trim(lines[header_start]);
result["REQUEST_METHOD"] = nibble(request_line, " ");
result["REQUEST_URI"] = nibble(request_line, " ");
String query_string = result["REQUEST_URI"];
String base_uri = nibble(query_string, "?");
result["SERVER_PROTOCOL"] = trim(request_line);
result["SCRIPT_NAME"] = base_uri;
result["DOCUMENT_URI"] = base_uri;
result["QUERY_STRING"] = query_string;
header_start++;
}
for(u64 i = header_start; i < lines.size(); i++)
{
String line = lines[i];
size_t colon = line.find(':');
if(colon == String::npos)
continue;
String header_key = to_upper(trim(line.substr(0, colon)));
String value = trim(line.substr(colon + 1));
if(header_key == "")
continue;
std::replace(header_key.begin(), header_key.end(), '-', '_');
result["HTTP_" + header_key] = value;
if(header_key == "CONTENT_TYPE" || header_key == "CONTENT_LENGTH")
result[header_key] = value;
}
return(result);
}
@@ -814,6 +942,9 @@ String html_escape(String s)
case('"'):
result.append("&quot;");
break;
case('\''):
result.append("&#39;");
break;
default:
result.append(1, c);
break;
+25 -2
View File
@@ -65,8 +65,8 @@ String to_hex(ITYPE w, size_t hex_len = sizeof(ITYPE)<<1)
return(rc);
}
template<typename T>
std::vector<T> filter(std::vector<T> items, std::function<bool (T)> f)
template<typename T, typename F>
std::vector<T> filter(std::vector<T> items, F f)
{
std::vector<T> new_items;
for(auto item : items)
@@ -77,6 +77,29 @@ std::vector<T> filter(std::vector<T> items, std::function<bool (T)> f)
return(new_items);
}
template<typename T, typename F>
auto map(std::vector<T> items, F f)
{
using ResultType = decltype(f(items[0]));
std::vector<ResultType> new_items;
for(auto item : items)
new_items.push_back(f(item));
return(new_items);
}
StringList list_unique(StringList items);
StringList list_sort(StringList items);
bool list_some(StringList items, std::function<bool (String)> f);
bool list_every(StringList items, std::function<bool (String)> f);
String list_find(StringList items, std::function<bool (String)> f, String fallback = "");
StringList dtree_keys(DTree tree);
DTree dtree_values(DTree tree);
DTree dtree_pick(DTree tree, StringList keys);
DTree dtree_omit(DTree tree, StringList keys);
DTree dtree_map(DTree tree, std::function<DTree (const DTree&, String)> f);
DTree dtree_filter(DTree tree, std::function<bool (const DTree&, String)> f);
DTree dtree_group_by(DTree tree, std::function<String (const DTree&, String)> f);
template <class ...Args>
String first(Args... args)
{
+75 -4
View File
@@ -37,7 +37,8 @@ bool MySQL::connect(String host, String username, String password)
*/
//switch_to_arena(context->mem);
statement_info = String("connected");
context->resources.mysql_connections.push_back(connection);
if(context)
context->resources.mysql_connections.push_back(this);
return(true);
}
@@ -181,8 +182,16 @@ DTree MySQL::get_pending_result()
return(result_data);
}
static bool mysql_has_unquoted_positional_placeholder(String query);
DTree MySQL::query(String q)
{
if(mysql_has_unquoted_positional_placeholder(q))
{
_preload_next_error_code = CR_UNKNOWN_ERROR;
statement_info = "mysql positional ? placeholders are not supported; use named :name placeholders";
return(DTree());
}
_preload_next_error_code = mysql_query((MYSQL*)connection, q.c_str());
DTree result;
if(_preload_next_error_code == 0)
@@ -190,8 +199,50 @@ DTree MySQL::query(String q)
return(result);
}
static bool mysql_has_unquoted_positional_placeholder(String query)
{
bool quoted = false;
char quote = 0;
bool escaped = false;
for(u32 i = 0; i < query.length(); i++)
{
char c = query[i];
if(quoted)
{
if(escaped)
{
escaped = false;
continue;
}
if(c == '\\')
{
escaped = true;
continue;
}
if(c == quote)
quoted = false;
continue;
}
if(c == '\'' || c == '"')
{
quoted = true;
quote = c;
continue;
}
if(c == '?')
return(true);
}
return(false);
}
DTree MySQL::query(String q, StringMap params)
{
if(mysql_has_unquoted_positional_placeholder(q))
{
_preload_next_error_code = CR_UNKNOWN_ERROR;
statement_info = "mysql positional ? placeholders are not supported; use named :name placeholders";
return(DTree());
}
return(query(
parse_query_parameters(q, params).c_str()
));
@@ -255,12 +306,24 @@ void MySQL::disconnect()
if(connection)
mysql_close((MYSQL*)connection);
connection = NULL;
if(context)
{
auto& connections = context->resources.mysql_connections;
connections.erase(std::remove(connections.begin(), connections.end(), this), connections.end());
}
}
String MySQL::error()
{
if(_preload_next_error_code)
{
if(statement_info != "")
{
String result = statement_info;
statement_info = "";
_preload_next_error_code = 0;
return(result);
}
String p = "Unknown error";
switch(_preload_next_error_code)
{
@@ -298,8 +361,16 @@ String MySQL::error()
void cleanup_mysql_connections()
{
//switch_to_system_alloc();
for(auto& con : context->resources.mysql_connections)
mysql_close((MYSQL*)con);
context->resources.mysql_connections.clear();
if(!context)
return;
while(!context->resources.mysql_connections.empty())
{
MySQL* db = (MySQL*)context->resources.mysql_connections.back();
context->resources.mysql_connections.pop_back();
bool should_delete = db->request_cleanup_delete;
db->disconnect();
if(should_delete)
delete db;
}
//switch_to_arena(context->mem);
}
+2
View File
@@ -20,6 +20,7 @@ struct MySQL {
u32 row_count = 0;
u64 insert_id = 0;
String statement_info = ""; //
bool request_cleanup_delete = false;
std::vector<MySQLFieldInfo> field_info;
@@ -37,6 +38,7 @@ struct MySQL {
MySQL* mysql_connect(String host = "localhost", String username = "root", String password = "")
{
MySQL* m = new MySQL();
m->request_cleanup_delete = true;
m->connect(host, username, password);
return(m);
}
+353
View File
@@ -0,0 +1,353 @@
#include "../3rdparty/sqlite/sqlite3.h"
#include "sqlite-connector.h"
namespace {
std::map<String, SQLite*> sqlite_worker_connection_cache;
void sqlite_register_request_connection(SQLite* db)
{
if(!context || !db)
return;
auto& connections = context->resources.sqlite_connections;
if(std::find(connections.begin(), connections.end(), db) == connections.end())
connections.push_back(db);
}
void sqlite_unregister_request_connection(SQLite* db)
{
if(!context || !db)
return;
auto& connections = context->resources.sqlite_connections;
connections.erase(std::remove(connections.begin(), connections.end(), db), connections.end());
}
void sqlite_forget_worker_cached_connection(SQLite* db)
{
if(!db || db->path == "")
return;
auto found = sqlite_worker_connection_cache.find(db->path);
if(found != sqlite_worker_connection_cache.end() && found->second == db)
sqlite_worker_connection_cache.erase(found);
}
}
void SQLite::set_error(s32 code, String info)
{
error_code = code;
if(connection)
statement_info = sqlite3_errmsg((sqlite3*)connection);
else
statement_info = info;
if(info != "")
statement_info = info + (statement_info != "" ? ": " + statement_info : "");
}
bool SQLite::apply_default_pragmas()
{
char* err = 0;
const char* pragmas =
"PRAGMA foreign_keys = ON;"
"PRAGMA journal_mode = WAL;"
"PRAGMA synchronous = NORMAL;";
s32 rc = sqlite3_exec((sqlite3*)connection, pragmas, 0, 0, &err);
if(rc != SQLITE_OK)
{
String message;
if(err)
{
message = err;
sqlite3_free(err);
}
set_error(rc, "sqlite default pragmas failed" + (message != "" ? ": " + message : ""));
return(false);
}
return(true);
}
bool SQLite::connect(String path)
{
disconnect();
this->path = path;
s32 rc = sqlite3_open_v2(path.c_str(), (sqlite3**)&connection, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, 0);
if(rc != SQLITE_OK)
{
set_error(rc, "sqlite open failed for " + path);
disconnect();
return(false);
}
sqlite3_busy_timeout((sqlite3*)connection, 5000);
sqlite_register_request_connection(this);
if(!apply_default_pragmas())
return(false);
statement_info = "connected";
return(true);
}
void SQLite::disconnect()
{
sqlite_forget_worker_cached_connection(this);
if(!connection)
{
sqlite_unregister_request_connection(this);
return;
}
sqlite3_close((sqlite3*)connection);
connection = 0;
sqlite_unregister_request_connection(this);
}
String SQLite::error()
{
if(statement_info != "")
return(statement_info);
if(connection)
return(sqlite3_errmsg((sqlite3*)connection));
return("");
}
bool SQLite::bind_params(void* statement, const StringMap& params)
{
sqlite3_stmt* stmt = (sqlite3_stmt*)statement;
s32 count = sqlite3_bind_parameter_count(stmt);
for(s32 i = 1; i <= count; i++)
{
const char* raw_name = sqlite3_bind_parameter_name(stmt, i);
if(!raw_name || raw_name[0] == '\0')
{
set_error(SQLITE_MISUSE, "sqlite positional ? placeholders are not supported; use named :name placeholders");
return(false);
}
String name = raw_name;
if(name[0] != ':')
{
set_error(SQLITE_MISUSE, "sqlite only supports :name placeholders; found " + name);
return(false);
}
String key = name.substr(1);
auto found = params.find(key);
s32 rc;
if(found == params.end())
rc = sqlite3_bind_null(stmt, i);
else
rc = sqlite3_bind_text(stmt, i, found->second.c_str(), found->second.length(), SQLITE_STATIC);
if(rc != SQLITE_OK)
{
set_error(rc, "sqlite bind failed for " + name);
return(false);
}
}
return(true);
}
DTree SQLite::collect_rows(void* statement)
{
sqlite3_stmt* stmt = (sqlite3_stmt*)statement;
DTree result;
s32 column_count = sqlite3_column_count(stmt);
std::vector<String> column_names;
column_names.reserve(column_count);
for(s32 i = 0; i < column_count; i++)
column_names.push_back(sqlite3_column_name(stmt, i));
while(true)
{
s32 rc = sqlite3_step(stmt);
if(rc == SQLITE_ROW)
{
DTree row;
for(s32 i = 0; i < column_count; i++)
{
const String& name = column_names[i];
switch(sqlite3_column_type(stmt, i))
{
case SQLITE_INTEGER:
row[name].set((s64)sqlite3_column_int64(stmt, i));
break;
case SQLITE_FLOAT:
row[name].set((f64)sqlite3_column_double(stmt, i));
break;
case SQLITE_TEXT:
{
const unsigned char* text = sqlite3_column_text(stmt, i);
row[name].set(text ? String((const char*)text) : "");
break;
}
case SQLITE_BLOB:
{
const char* data = (const char*)sqlite3_column_blob(stmt, i);
s32 bytes = sqlite3_column_bytes(stmt, i);
row[name].set(data && bytes > 0 ? String(data, bytes) : "");
break;
}
case SQLITE_NULL:
default:
break;
}
}
result.push(row);
continue;
}
if(rc == SQLITE_DONE)
{
affected_rows = sqlite3_changes((sqlite3*)connection);
insert_id = sqlite3_last_insert_rowid((sqlite3*)connection);
return(result);
}
set_error(rc, "sqlite step failed");
return(DTree());
}
}
DTree SQLite::query(String q)
{
StringMap params;
return(query(q, params));
}
DTree SQLite::query(String q, const StringMap& params)
{
DTree result;
affected_rows = 0;
insert_id = 0;
error_code = SQLITE_OK;
statement_info = "";
if(!connection)
{
set_error(SQLITE_MISUSE, "sqlite query called without an open connection");
return(result);
}
sqlite3_stmt* stmt = 0;
const char* tail = 0;
s32 rc = sqlite3_prepare_v2((sqlite3*)connection, q.c_str(), q.length(), &stmt, &tail);
if(rc != SQLITE_OK)
{
set_error(rc, "sqlite prepare failed");
return(result);
}
if(!stmt)
{
statement_info = "ok";
return(result);
}
if(tail && trim(String(tail)) != "")
{
sqlite3_stmt* trailing_stmt = 0;
const char* trailing_tail = 0;
rc = sqlite3_prepare_v2((sqlite3*)connection, tail, -1, &trailing_stmt, &trailing_tail);
if(rc != SQLITE_OK)
{
sqlite3_finalize(stmt);
set_error(rc, "sqlite_query accepts exactly one SQL statement per call; trailing SQL after the first statement was rejected");
return(result);
}
if(trailing_stmt)
{
sqlite3_finalize(trailing_stmt);
sqlite3_finalize(stmt);
set_error(SQLITE_MISUSE, "sqlite_query accepts exactly one SQL statement per call; trailing SQL after the first statement was rejected");
return(result);
}
}
if(!bind_params(stmt, params))
{
sqlite3_finalize(stmt);
return(result);
}
result = collect_rows(stmt);
rc = sqlite3_finalize(stmt);
if(rc != SQLITE_OK && error_code == SQLITE_OK)
set_error(rc, "sqlite finalize failed");
if(statement_info == "")
statement_info = "ok";
return(result);
}
SQLite* sqlite_connect(String path)
{
auto found = sqlite_worker_connection_cache.find(path);
if(found != sqlite_worker_connection_cache.end() && found->second && found->second->connection)
{
SQLite* cached = found->second;
cached->error_code = SQLITE_OK;
cached->affected_rows = 0;
cached->insert_id = 0;
cached->statement_info = "connected";
sqlite_register_request_connection(cached);
return(cached);
}
SQLite* db = new SQLite();
db->worker_cache = true;
if(db->connect(path) && db->connection)
sqlite_worker_connection_cache[path] = db;
else
db->request_cleanup_delete = true;
return(db);
}
void sqlite_disconnect(SQLite* db)
{
if(!db)
return;
db->disconnect();
delete db;
}
String sqlite_error(SQLite* db)
{
if(!db)
return("sqlite connection is null");
return(db->error());
}
DTree sqlite_query(SQLite* db, String q)
{
if(!db)
return(DTree());
return(db->query(q));
}
DTree sqlite_query(SQLite* db, String q, const StringMap& params)
{
if(!db)
return(DTree());
return(db->query(q, params));
}
u64 sqlite_insert_id(SQLite* db)
{
if(!db)
return(0);
return(db->insert_id);
}
u32 sqlite_affected_rows(SQLite* db)
{
if(!db)
return(0);
return(db->affected_rows);
}
void cleanup_sqlite_connections()
{
if(!context)
return;
while(!context->resources.sqlite_connections.empty())
{
SQLite* db = (SQLite*)context->resources.sqlite_connections.back();
context->resources.sqlite_connections.pop_back();
if(db->worker_cache)
{
db->affected_rows = 0;
db->insert_id = 0;
db->error_code = SQLITE_OK;
db->statement_info = "";
continue;
}
bool should_delete = db->request_cleanup_delete;
db->disconnect();
if(should_delete)
delete db;
}
}
+34
View File
@@ -0,0 +1,34 @@
#pragma once
struct SQLite {
void* connection = 0;
s32 error_code = 0;
u32 affected_rows = 0;
u64 insert_id = 0;
String statement_info = "";
String path = "";
bool request_cleanup_delete = false;
bool worker_cache = false;
bool connect(String path);
void disconnect();
String error();
DTree query(String q);
DTree query(String q, const StringMap& params);
private:
void set_error(s32 code, String info = "");
bool apply_default_pragmas();
bool bind_params(void* statement, const StringMap& params);
DTree collect_rows(void* statement);
};
SQLite* sqlite_connect(String path);
void sqlite_disconnect(SQLite* db);
String sqlite_error(SQLite* db);
DTree sqlite_query(SQLite* db, String q);
DTree sqlite_query(SQLite* db, String q, const StringMap& params);
u64 sqlite_insert_id(SQLite* db);
u32 sqlite_affected_rows(SQLite* db);
void cleanup_sqlite_connections();
+1
View File
@@ -208,6 +208,7 @@ struct Request {
struct Resources {
std::vector<u64> sockets;
std::vector<void*> mysql_connections;
std::vector<void*> sqlite_connections;
u64 client_socket = 0;
u64 server_socket = 0;
bool is_websocket = false;
+6 -1
View File
@@ -1,4 +1,8 @@
// UCE runtime amalgamation include.
//
// The worker and generated units include this file to build the runtime in a
// single translation unit. Do not compile the listed .cpp files separately
// unless the build/compiler model is deliberately changed.
#include "types.cpp"
#include "dtree.cpp"
@@ -12,3 +16,4 @@
#include "markdown.cpp"
#include "zip.cpp"
#include "mysql-connector.cpp"
#include "sqlite-connector.cpp"
+1
View File
@@ -11,3 +11,4 @@
#include "markdown.h"
#include "zip.h"
#include "mysql-connector.h"
#include "sqlite-connector.h"
+143 -24
View File
@@ -220,38 +220,31 @@ String uri_encode(String q)
StringMap parse_query(String q)
{
StringMap result;
if(q.length() == 0)
return(result);
return(parse_query(q, 0));
}
bool is_key = true;
String key = "";
String value = "";
for (char &c: q)
StringMap parse_query(String q, String* first_keyless_path)
{
StringMap result;
if(first_keyless_path)
*first_keyless_path = "";
for(String part : split(q, "&"))
{
if(c == '=')
if(part == "")
continue;
size_t equals = part.find('=');
if(equals == String::npos)
{
is_key = !is_key;
}
else if(c == '&')
{
result[uri_decode(key)] = uri_decode(value);
key = "";
value = "";
is_key = true;
}
else if(is_key)
{
key.append(1, c);
String key = uri_decode(part);
if(first_keyless_path && *first_keyless_path == "")
*first_keyless_path = key;
result[key] = "";
}
else
{
value.append(1, c);
result[uri_decode(part.substr(0, equals))] = uri_decode(part.substr(equals + 1));
}
}
result[uri_decode(key)] = uri_decode(value);
return(result);
}
@@ -269,6 +262,132 @@ String encode_query(StringMap map)
return(result);
}
String route_path_normalize(String path)
{
path = trim(path);
size_t start = path.find_first_not_of('/');
if(start == String::npos)
return("");
size_t end = path.find_last_not_of('/');
return(path.substr(start, end - start + 1));
}
bool route_path_normalized_is_safe(String path)
{
if(path == "")
return(true);
for(String part : split(path, "/"))
{
if(part == "" || part == "." || part == "..")
return(false);
for(unsigned char c : part)
{
if(!(std::isalnum(c) || c == '-' || c == '_'))
return(false);
}
}
return(true);
}
bool route_path_is_safe(String path)
{
return(route_path_normalized_is_safe(route_path_normalize(path)));
}
String route_path_sanitize(String path, String default_path)
{
path = route_path_normalize(path);
if(path == "")
path = route_path_normalize(default_path);
if(!route_path_normalized_is_safe(path))
return("");
return(path);
}
String route_path_sanitize_normalized(String path, String default_path)
{
if(path == "")
path = route_path_normalize(default_path);
if(!route_path_normalized_is_safe(path))
return("");
return(path);
}
String request_script_url(Request& context)
{
String url = first(context.params["DOCUMENT_URI"], context.params["SCRIPT_NAME"]);
if(str_ends_with(url, "/index.uce"))
url = url.substr(0, url.length() - String("index.uce").length());
return(url);
}
String request_base_url_from_script_url(String script_url)
{
String base = dirname(script_url);
if(base == "")
base = "/";
if(base[base.length() - 1] != '/')
base.append(1, '/');
return(base);
}
String request_base_url(Request& context)
{
return(request_base_url_from_script_url(request_script_url(context)));
}
String request_query_path(Request& context, String default_path)
{
return(request_query_route(context, default_path)["l_path"].to_string());
}
DTree request_query_route(Request& context, String default_path)
{
String raw_path = "";
parse_query(context.params["QUERY_STRING"], &raw_path);
return(request_route_from_raw_path(raw_path, default_path));
}
DTree request_route_from_raw_path(String raw_path, String default_path)
{
DTree route;
String normalized_path = route_path_normalize(raw_path);
String route_path = route_path_sanitize_normalized(normalized_path, default_path);
bool valid = route_path != "";
route["raw_path"] = normalized_path;
route["l_path"] = route_path;
String page = route_path;
route["page"] = valid ? nibble(page, "/") : "";
if(valid && route["page"].to_string() == "")
route["page"] = default_path;
route["valid"].set_bool(valid);
return(route);
}
void request_populate_context_params(Request& context, String default_path)
{
DTree route = request_query_route(context, default_path);
String script_url = request_script_url(context);
context.params["SCRIPT_URL"] = script_url;
context.params["BASE_URL"] = request_base_url_from_script_url(script_url);
context.params["ROUTE_PATH"] = route["l_path"].to_string();
context.params["ROUTE_PAGE"] = route["page"].to_string();
context.params["ROUTE_PATH_RAW"] = route["raw_path"].to_string();
context.params["ROUTE_VALID"] = route["valid"].to_bool() ? "1" : "0";
}
void request_populate_context_params_from_route(Request& context, String raw_path, String default_path)
{
DTree route = request_route_from_raw_path(raw_path, default_path);
String script_url = request_script_url(context);
context.params["SCRIPT_URL"] = script_url;
context.params["BASE_URL"] = request_base_url_from_script_url(script_url);
context.params["ROUTE_PATH"] = route["l_path"].to_string();
context.params["ROUTE_PAGE"] = route["page"].to_string();
context.params["ROUTE_PATH_RAW"] = route["raw_path"].to_string();
context.params["ROUTE_VALID"] = route["valid"].to_bool() ? "1" : "0";
}
bool http_header_name_valid(String name)
{
if(name == "")
+11
View File
@@ -8,7 +8,18 @@ String base64_decode(String raw, bool& ok);
String uri_decode(String q);
String uri_encode(String q);
StringMap parse_query(String q);
StringMap parse_query(String q, String* first_keyless_path);
String encode_query(StringMap map);
String route_path_normalize(String path);
bool route_path_is_safe(String path);
String route_path_sanitize(String path, String default_path = "index");
String request_script_url(Request& context);
String request_base_url(Request& context);
String request_query_path(Request& context, String default_path = "index");
DTree request_query_route(Request& context, String default_path = "index");
DTree request_route_from_raw_path(String raw_path, String default_path = "index");
void request_populate_context_params(Request& context, String default_path = "index");
void request_populate_context_params_from_route(Request& context, String raw_path, String default_path = "index");
void redirect(String url, s32 code = 302);
StringMap parse_multipart(String q, String boundary, std::vector<UploadedFile>& uploaded_files);
URI parse_uri(String uri_String);
+62 -38
View File
@@ -27,6 +27,7 @@ static String websocket_exec_write_buffer = "";
void close_inherited_server_sockets();
u64 request_seed_from_time(f64 time_value);
void prepare_request_body_maps(Request& request);
Request* set_active_request(Request& request)
{
@@ -67,40 +68,34 @@ void render_request_failure(Request& request, String title, String details, Stri
Request* previous_context = set_active_request(request);
clear_request_output(request);
print("UCE runtime error\n");
print("Request: ", first(request.params["REQUEST_URI"], request.params["SCRIPT_FILENAME"]), "\n");
print("Script: ", request.params["SCRIPT_FILENAME"], "\n");
print("Error: ", title, "\n");
String body;
body += "UCE runtime error\n";
body += "Request: " + first(request.params["REQUEST_URI"], request.params["SCRIPT_FILENAME"]) + "\n";
body += "Script: " + request.params["SCRIPT_FILENAME"] + "\n";
body += "Error: " + title + "\n";
if(details != "")
print("Details: ", details, "\n");
body += "Details: " + details + "\n";
if(request.server && request.params["SCRIPT_FILENAME"] != "")
{
String generated = compiler_generated_cpp_path(&request, request.params["SCRIPT_FILENAME"]);
body += "Generated C++: " + generated + "\n";
body += "Hint: if this came from template code, inspect the generated C++ and the nearest .uce literal/code delimiter before changing runtime code.\n";
}
else
body += "Hint: inspect the requested .uce file, its generated C++, and any component/unit called immediately before this failure.\n";
if(request_fault_signal != 0)
{
String sig_label = signal_name((int)request_fault_signal);
print("Signal: ", (s64)request_fault_signal);
body += "Signal: " + std::to_string((int)request_fault_signal);
if(sig_label != "")
print(" (", sig_label, ")");
print("\n");
body += " (" + sig_label + ")";
body += "\n";
}
if(trace != "")
print("\nTrace:\n", trace);
request.err += "UCE runtime error\n";
request.err += "Request: " + first(request.params["REQUEST_URI"], request.params["SCRIPT_FILENAME"]) + "\n";
request.err += "Script: " + request.params["SCRIPT_FILENAME"] + "\n";
request.err += "Error: " + title + "\n";
if(details != "")
request.err += "Details: " + details + "\n";
if(request_fault_signal != 0)
{
String sig_label = signal_name((int)request_fault_signal);
request.err += "Signal: " + std::to_string((int)request_fault_signal);
if(sig_label != "")
request.err += " (" + sig_label + ")";
request.err += "\n";
}
if(trace != "")
request.err += "\nTrace:\n" + trace;
body += "\nTrace:\n" + trace;
print(body);
request.err = body;
request.flags.status = status_code;
restore_active_request(previous_context);
}
@@ -108,9 +103,11 @@ void render_request_failure(Request& request, String title, String details, Stri
void on_request_fault_signal(int sig)
{
request_fault_signal = sig;
request_fault_trace = capture_backtrace_string(32, 1);
if(request_fault_active && request_fault_request)
{
request_fault_trace = capture_backtrace_string(32, 1);
siglongjmp(request_fault_jmp, 1);
}
on_segfault(sig);
}
@@ -393,7 +390,7 @@ Request websocket_exec_build_event_request(DTree job, String message)
event_request.server = &server_state;
event_request.params = job["params"].to_stringmap();
event_request.params["REQUEST_METHOD"] = "WEBSOCKET";
event_request.get = parse_query(event_request.params["QUERY_STRING"]);
prepare_request_body_maps(event_request);
event_request.resources.is_websocket = true;
event_request.resources.websocket_connection_id = job["connection_id"].to_string();
event_request.resources.websocket_scope = job["scope"].to_string();
@@ -413,9 +410,6 @@ Request websocket_exec_build_event_request(DTree job, String message)
event_request.header["Content-Type"] = server_state.config["CONTENT_TYPE"];
event_request.in = message;
if(event_request.params["HTTP_COOKIE"].length() > 0)
event_request.cookies = parse_cookies(event_request.params["HTTP_COOKIE"]);
event_request.params["WS_MESSAGE"] = message;
event_request.params["WS_CONNECTION_ID"] = event_request.resources.websocket_connection_id;
event_request.params["WS_SCOPE"] = event_request.resources.websocket_scope;
@@ -475,6 +469,7 @@ void websocket_exec_process_job_line(int fd, String line)
if(event_request.session_id.length() > 0)
save_session_data(event_request.session_id, event_request.session);
cleanup_mysql_connections();
cleanup_sqlite_connections();
DTree response;
response["type"] = "result";
@@ -750,7 +745,9 @@ u64 request_seed_from_time(f64 time_value)
void prepare_request_body_maps(Request& request)
{
request.get = parse_query(request.params["QUERY_STRING"]);
String route_path;
request.get = parse_query(request.params["QUERY_STRING"], &route_path);
request_populate_context_params_from_route(request, route_path);
if(request.params["HTTP_COOKIE"].length() > 0)
request.cookies = parse_cookies(request.params["HTTP_COOKIE"]);
@@ -782,7 +779,6 @@ int handle_cli_complete(FastCGIRequest& request)
request.random_index = 0;
request.random_seed = request_seed_from_time(request.stats.time_start);
request.ob_start();
prepare_request_body_maps(request);
String method = trim(request.params["REQUEST_METHOD"]);
String command = trim(first(request.params["DOCUMENT_URI"], request.params["REQUEST_URI"]));
@@ -827,6 +823,7 @@ int handle_cli_complete(FastCGIRequest& request)
{
request.params["DOCUMENT_ROOT"] = document_root;
request.params["SCRIPT_FILENAME"] = script_filename;
prepare_request_body_maps(request);
request.props = DTree();
compiler_invoke_cli(&request, script_filename);
}
@@ -850,6 +847,7 @@ int handle_cli_complete(FastCGIRequest& request)
for(auto &f : request.uploaded_files)
file_unlink(f.tmp_name);
cleanup_mysql_connections();
cleanup_sqlite_connections();
restore_active_request(previous_context);
return(request.flags.status);
}
@@ -883,7 +881,6 @@ int handle_complete(FastCGIRequest& request) {
//request.stats.mem_alloc = 0;
//request.stats.mem_high = 0;
request.header["Content-Type"] = (request.resources.is_cli ? "text/plain; charset=utf-8" : context->server->config["CONTENT_TYPE"]);
request.get = parse_query(request.params["QUERY_STRING"]);
request.random_index = 0;
request.random_seed = request_seed_from_time(request.stats.time_start);
request.ob_start();
@@ -945,6 +942,7 @@ int handle_complete(FastCGIRequest& request) {
save_session_data(request.session_id, request.session);
cleanup_mysql_connections();
cleanup_sqlite_connections();
restore_active_request(previous_context);
return request.flags.status;
@@ -1305,14 +1303,27 @@ void run_proactive_compiler()
signal(SIGPIPE, SIG_IGN);
setpriority(PRIO_PROCESS, 0, 10);
auto known_units = compiler_list_known_units(&background_context);
auto site_units = compiler_scan_site_units(&background_context);
known_units.insert(known_units.end(), site_units.begin(), site_units.end());
compiler_set_known_units(&background_context, known_units);
try
{
auto known_units = compiler_list_known_units(&background_context);
auto site_units = compiler_scan_site_units(&background_context);
known_units.insert(known_units.end(), site_units.begin(), site_units.end());
compiler_set_known_units(&background_context, known_units);
}
catch(const std::exception& e)
{
printf("(!) proactive compiler initial scan failed: %s\n", e.what());
}
catch(...)
{
printf("(!) proactive compiler initial scan failed: unknown exception\n");
}
next_scan_at = time_precise();
for(;;)
{
try
{
if(compile_queue.size() == 0 && time_precise() >= next_scan_at)
{
auto tracked_units = compiler_list_known_units(&background_context);
@@ -1375,6 +1386,19 @@ void run_proactive_compiler()
}
usleep(250000);
}
catch(const std::exception& e)
{
printf("(!) proactive compiler scan failed: %s\n", e.what());
next_scan_at = time_precise() + check_interval;
usleep(250000);
}
catch(...)
{
printf("(!) proactive compiler scan failed: unknown exception\n");
next_scan_at = time_precise() + check_interval;
usleep(250000);
}
}
}