├── logs └── .logs_here ├── res └── wait.gif ├── src ├── silgy.bat ├── silgy ├── m.bat ├── m_vc.bat ├── m ├── silgy_app.h ├── silgy_svc.cpp └── silgy_app.cpp ├── README.md ├── bin ├── silgystart ├── silgystop └── silgydep ├── resmin ├── silgy.css └── silgy.js ├── LICENSE └── lib ├── users.sql ├── silgy_watcher.c ├── silgy_usr.h ├── silgy_lib.h └── silgy.h /logs/.logs_here: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /res/wait.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rekmus/silgy/master/res/wait.gif -------------------------------------------------------------------------------- /src/silgy.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | set SILGYDIR=.. 4 | 5 | ..\bin\silgy_app 8080 6 | -------------------------------------------------------------------------------- /src/silgy: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | export SILGYDIR=.. 4 | 5 | $SILGYDIR/bin/silgy_app 8080 6 | -------------------------------------------------------------------------------- /src/m.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | echo Making silgy_app... 4 | 5 | g++ silgy_app.cpp ^ 6 | ..\lib\silgy_eng.c ..\lib\silgy_lib.c ..\lib\silgy_usr.c ^ 7 | -I . -I ..\lib ^ 8 | -lws2_32 -lpsapi ^ 9 | -s -O3 ^ 10 | -o ..\bin\silgy_app ^ 11 | -static 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Silgy 2 | 3 | If you're starting a new project, [Node++](https://github.com/rekmus/nodepp) is now recommended. 4 | 5 | Please bear in mind that this Silgy repo is treated as deprecated and any new project should use [Node++](https://github.com/rekmus/nodepp) instead. Node++ is a direct Silgy's successor with numerous improvements and enhancements. 6 | -------------------------------------------------------------------------------- /src/m_vc.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | echo Making silgy_app using Microsoft compiler... 4 | 5 | cl silgy_app.cpp ^ 6 | ..\lib\silgy_eng.c ..\lib\silgy_lib.c ..\lib\silgy_usr.c ^ 7 | /EHsc ^ 8 | -I . -I ..\lib ^ 9 | /Fe..\bin\silgy_app 10 | 11 | echo. 12 | 13 | echo Make sure you have dirent.h from https://github.com/tronkko/dirent/tree/master/include 14 | 15 | echo Remember to set the environment with vcvars32 (path: C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin) 16 | -------------------------------------------------------------------------------- /src/m: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | 4 | echo Making silgy_app... 5 | 6 | g++ silgy_app.cpp \ 7 | ../lib/silgy_eng.c ../lib/silgy_lib.c ../lib/silgy_usr.c \ 8 | -I. -I../lib \ 9 | -lrt -lz \ 10 | -s -O3 \ 11 | -o ../bin/silgy_app 12 | 13 | 14 | echo Making silgy_svc... 15 | 16 | g++ silgy_svc.cpp \ 17 | ../lib/silgy_eng.c ../lib/silgy_lib.c ../lib/silgy_usr.c \ 18 | -D SILGY_SVC \ 19 | -I. -I../lib \ 20 | -lrt \ 21 | -s -O3 \ 22 | -o ../bin/silgy_svc 23 | 24 | 25 | echo Making silgy_watcher... 26 | 27 | gcc ../lib/silgy_watcher.c \ 28 | ../lib/silgy_lib.c \ 29 | -D SILGY_WATCHER \ 30 | -I. -I../lib \ 31 | -s -O3 \ 32 | -o ../bin/silgy_watcher 33 | -------------------------------------------------------------------------------- /bin/silgystart: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | export SILGYDIR=/home/ec2-user/live 4 | 5 | export SILGY_SVC_PROCESSES=0 6 | 7 | # --------------------------------------------------------------------- 8 | 9 | echo "Starting Silgy App..." 10 | 11 | # --------------------------------------------------------------------- 12 | # Main app 13 | 14 | nohup $SILGYDIR/bin/silgy_app > /dev/null 2>&1 & 15 | 16 | sleep 1 17 | 18 | # --------------------------------------------------------------------- 19 | # Services 20 | 21 | for i in `seq 1 $SILGY_SVC_PROCESSES` 22 | do 23 | nohup $SILGYDIR/bin/silgy_svc > /dev/null 2>&1 & 24 | done 25 | 26 | sleep 1 # return to prompt 27 | -------------------------------------------------------------------------------- /bin/silgystop: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | export SILGYDIR=/home/ec2-user/live 4 | 5 | # --------------------------------------------------------------------- 6 | 7 | echo "Stopping Silgy App..." 8 | 9 | # --------------------------------------------------------------------- 10 | # Services 11 | 12 | if [ -n "$(find $SILGYDIR/bin -name 's_*.pid' | head -1)" ] 13 | then 14 | for f in $SILGYDIR/bin/s_*.pid 15 | do 16 | kill `cat ${f}` 17 | done 18 | 19 | sleep 1 20 | fi 21 | 22 | # --------------------------------------------------------------------- 23 | # Main app 24 | 25 | if [ -f $SILGYDIR/bin/silgy_app.pid ] 26 | then 27 | kill `cat $SILGYDIR/bin/silgy_app.pid` 28 | fi 29 | 30 | # --------------------------------------------------------------------- 31 | -------------------------------------------------------------------------------- /resmin/silgy.css: -------------------------------------------------------------------------------- 1 | // ---------------------------------------- 2 | // wait animation 3 | .wt 4 | { 5 | display: none; 6 | position: fixed; 7 | top: 0; 8 | left: 0; 9 | width: 100%; 10 | height: 100%; 11 | z-index: 900; 12 | background: url(wait.gif) 50% 50% no-repeat; 13 | background-size: 52px; 14 | } 15 | 16 | 17 | // ---------------------------------------- 18 | // modal window 19 | .mw 20 | { 21 | font-size: 12pt; 22 | background-color: white; 23 | padding: 3px 12px 13px 14px; 24 | box-shadow: 4px 4px 16px 0px rgba(0,0,0,0.2); 25 | border: 1px solid #bbbbbb; 26 | z-index: 1000; 27 | } 28 | 29 | 30 | // ---------------------------------------- 31 | // yes/no buttons 32 | .ynb 33 | { 34 | width: 80px; 35 | height: 32px; 36 | margin-top: 20px; 37 | } 38 | -------------------------------------------------------------------------------- /src/silgy_app.h: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------- 2 | Silgy Web App 3 | Jurek Muszynski 4 | silgy.com 5 | ----------------------------------------------------------------------------- 6 | Hello World Sample Silgy Web Application 7 | -------------------------------------------------------------------------- */ 8 | 9 | #ifndef SILGY_APP_H 10 | #define SILGY_APP_H 11 | 12 | 13 | #define APP_WEBSITE "Silgy Hello World" 14 | #define APP_DOMAIN "example.com" 15 | #define APP_DESCRIPTION "Hello World Sample Silgy Web Application" 16 | #define APP_VERSION "1.0" 17 | 18 | 19 | /* app user session */ 20 | 21 | typedef struct { 22 | char dummy; // replace with your own struct members 23 | } ausession_t; 24 | 25 | 26 | #endif /* SILGY_APP_H */ 27 | -------------------------------------------------------------------------------- /bin/silgydep: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | export SILGYDEV=/home/ec2-user/dev 4 | export SILGYLIVE=/home/ec2-user/live 5 | 6 | # --------------------------------------------------------------------- 7 | 8 | echo "Deploying new Silgy App..." 9 | 10 | # --------------------------------------------------------------------- 11 | 12 | cp -p $SILGYDEV/bin/silgy_app $SILGYLIVE/bin 13 | cp -p $SILGYDEV/bin/silgy_svc $SILGYLIVE/bin 14 | cp -p $SILGYDEV/bin/silgy_watcher $SILGYLIVE/bin 15 | cp -p $SILGYDEV/bin/silgydep $SILGYLIVE/bin 16 | cp -p $SILGYDEV/bin/silgystart $SILGYLIVE/bin 17 | cp -p $SILGYDEV/bin/silgystop $SILGYLIVE/bin 18 | cp -p $SILGYDEV/bin/strings.* $SILGYLIVE/bin 2>/dev/null 19 | cp -p $SILGYDEV/bin/passwords.* $SILGYLIVE/bin 2>/dev/null 20 | 21 | cp -pr $SILGYDEV/res/* $SILGYLIVE/res 2>/dev/null 22 | cp -pr $SILGYDEV/resmin/* $SILGYLIVE/resmin 2>/dev/null 23 | cp -pr $SILGYDEV/snippets/* $SILGYLIVE/snippets 2>/dev/null 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Jurek Muszynski 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/silgy_svc.cpp: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------- 2 | Silgy Web App 3 | Jurek Muszynski 4 | silgy.com 5 | ----------------------------------------------------------------------------- 6 | Sample service module 7 | -------------------------------------------------------------------------- */ 8 | 9 | 10 | #include 11 | 12 | 13 | /* ======================================================================= */ 14 | /* =============================== SERVICES ============================== */ 15 | /* ======================================================================= */ 16 | 17 | 18 | /* -------------------------------------------------------------------------- 19 | Service 20 | -------------------------------------------------------------------------- */ 21 | void getCustomer(int ci) 22 | { 23 | OUT_HTML_HEADER; 24 | OUT("

%s

", APP_WEBSITE); 25 | OUT("

Hello from getCustomer service!

"); 26 | OUT_HTML_FOOTER; 27 | } 28 | 29 | 30 | /* -------------------------------------------------------------------------- 31 | Service 32 | -------------------------------------------------------------------------- */ 33 | void getAccounts(int ci) 34 | { 35 | OUT_HTML_HEADER; 36 | OUT("

%s

", APP_WEBSITE); 37 | OUT("

Hello from getAccounts service!

"); 38 | OUT_HTML_FOOTER; 39 | } 40 | 41 | 42 | /* ======================================================================= */ 43 | /* ========================== END OF SERVICES ============================ */ 44 | /* ======================================================================= */ 45 | 46 | 47 | 48 | /* -------------------------------------------------------------------------- 49 | Entry point 50 | -------------------------------------------------------------------------- */ 51 | void silgy_svc_main(int ci) 52 | { 53 | if ( SVC("getCustomer") ) 54 | getCustomer(ci); 55 | else if ( SVC("getAccounts") ) 56 | getAccounts(ci); 57 | } 58 | 59 | 60 | /* -------------------------------------------------------------------------- 61 | Server start 62 | Return true if successful 63 | -------------------------------------------------------------------------- */ 64 | bool silgy_svc_init() 65 | { 66 | return true; 67 | } 68 | 69 | 70 | /* -------------------------------------------------------------------------- 71 | Server stop 72 | -------------------------------------------------------------------------- */ 73 | void silgy_svc_done() 74 | { 75 | } 76 | -------------------------------------------------------------------------------- /lib/users.sql: -------------------------------------------------------------------------------- 1 | -- ---------------------------------------------------------------------------- 2 | -- Silgy user tables -- MySQL version 3 | -- ---------------------------------------------------------------------------- 4 | 5 | -- users 6 | 7 | create table users ( 8 | id int auto_increment primary key, 9 | login char(30), 10 | login_u char(30), -- uppercase version 11 | email char(120), 12 | email_u char(120), -- uppercase version 13 | name varchar(120), 14 | phone varchar(30), 15 | passwd1 char(30), -- base64 of SHA1 hash 16 | passwd2 char(30), -- base64 of SHA1 hash 17 | lang char(5), 18 | about varchar(250), 19 | avatar_name varchar(60), 20 | avatar_data blob, -- 64 kB 21 | group_id int, 22 | auth_level tinyint, -- 10 = user, 20 = customer, 30 = staff, 40 = moderator, 50 = admin, 100 = root 23 | status tinyint, -- 0 = inactive, 1 = active, 2 = locked, 3 = requires password change, 9 = deleted 24 | created datetime, 25 | last_login datetime, 26 | visits int, 27 | ula_cnt int, -- unsuccessful login attempt count 28 | ula_time datetime -- and time 29 | ); 30 | 31 | create index users_login on users (login_u); 32 | create index users_email on users (email_u); 33 | create index users_last_login on users (last_login); 34 | 35 | 36 | -- groups 37 | 38 | create table users_groups ( 39 | id int auto_increment primary key, 40 | name varchar(120), 41 | about varchar(250), 42 | auth_level tinyint 43 | ); 44 | 45 | 46 | -- user settings 47 | 48 | create table users_settings ( 49 | user_id int, 50 | us_key char(30), 51 | us_val varchar(250), 52 | primary key (user_id, us_key) 53 | ); 54 | 55 | 56 | -- user logins 57 | 58 | create table users_logins ( 59 | sesid char(15) primary key, 60 | uagent varchar(250), 61 | ip char(15), 62 | user_id int, 63 | csrft char(7), 64 | created datetime, 65 | last_used datetime 66 | ); 67 | 68 | create index users_logins_uid on users_logins (user_id); 69 | 70 | 71 | -- account activations 72 | 73 | create table users_activations ( 74 | linkkey char(30) primary key, 75 | user_id int, 76 | created datetime, 77 | activated datetime 78 | ); 79 | 80 | 81 | -- password resets 82 | 83 | create table users_p_resets ( 84 | linkkey char(20) primary key, 85 | user_id int, 86 | created datetime, 87 | tries smallint 88 | ); 89 | 90 | create index users_p_resets_uid on users_p_resets (user_id); 91 | 92 | 93 | -- messages 94 | 95 | create table users_messages ( 96 | user_id int, 97 | msg_id int, 98 | email varchar(120), 99 | message text, -- 64 kB limit 100 | created datetime, 101 | primary key (user_id, msg_id) 102 | ); 103 | -------------------------------------------------------------------------------- /lib/silgy_watcher.c: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------- 2 | Restart Silgy app if dead 3 | Jurek Muszynski 4 | -------------------------------------------------------------------------- */ 5 | 6 | 7 | #include "silgy.h" 8 | 9 | 10 | #define STOP_COMMAND "$SILGYDIR/bin/silgystop" 11 | #define START_COMMAND "$SILGYDIR/bin/silgystart" 12 | 13 | 14 | int G_httpPort; 15 | 16 | 17 | static char M_watcherStopCmd[256]; 18 | static char M_watcherStartCmd[256]; 19 | static int M_watcherWait; 20 | static int M_watcherLogRestart; 21 | 22 | 23 | /* -------------------------------------------------------------------------- 24 | Restart 25 | -------------------------------------------------------------------------- */ 26 | static void restart() 27 | { 28 | if ( M_watcherLogRestart > 0 ) 29 | { 30 | G_logLevel = M_watcherLogRestart; 31 | log_start("watcher", FALSE); 32 | } 33 | 34 | ALWAYS_T("Restarting..."); 35 | 36 | INF_T("Stopping..."); 37 | INF_T(M_watcherStopCmd); 38 | system(M_watcherStopCmd); 39 | 40 | lib_update_time_globals(); 41 | 42 | INF_T("Waiting %d second(s)...", M_watcherWait); 43 | sleep(M_watcherWait); 44 | 45 | lib_update_time_globals(); 46 | 47 | INF_T("Starting..."); 48 | INF_T(M_watcherStartCmd); 49 | system(M_watcherStartCmd); 50 | 51 | #ifdef APP_ADMIN_EMAIL 52 | if ( strlen(APP_ADMIN_EMAIL) ) 53 | { 54 | char message[1024]; 55 | strcpy(message, "Silgy Watcher had to restart web server."); 56 | silgy_email(APP_ADMIN_EMAIL, "Silgy restart", message); 57 | } 58 | #endif 59 | } 60 | 61 | 62 | /* -------------------------------------------------------------------------- 63 | main 64 | -------------------------------------------------------------------------- */ 65 | int main(int argc, char *argv[]) 66 | { 67 | char config[256]; 68 | 69 | /* library init ------------------------------------------------------ */ 70 | 71 | silgy_lib_init(); 72 | 73 | sort_messages(); 74 | 75 | G_initialized = 1; 76 | 77 | /* read the config file or set defaults ------------------------------ */ 78 | 79 | if ( G_appdir[0] ) 80 | { 81 | sprintf(config, "%s/bin/silgy.conf", G_appdir); 82 | if ( !lib_read_conf(config) ) /* no config file there */ 83 | { 84 | strcpy(config, "silgy.conf"); 85 | lib_read_conf(config); 86 | } 87 | } 88 | else /* no SILGYDIR -- try current dir */ 89 | { 90 | strcpy(config, "silgy.conf"); 91 | lib_read_conf(config); 92 | } 93 | 94 | /* ------------------------------------------------------------------- */ 95 | 96 | if ( !silgy_read_param_int("watcherLogLevel", &G_logLevel) ) 97 | G_logLevel = 0; /* don't create log file */ 98 | 99 | if ( !silgy_read_param_int("watcherLogToStdout", &G_logToStdout) ) 100 | G_logToStdout = 0; 101 | 102 | if ( !silgy_read_param_int("httpPort", &G_httpPort) ) 103 | G_httpPort = 80; 104 | 105 | if ( !silgy_read_param_str("watcherStopCmd", M_watcherStopCmd) ) 106 | strcpy(M_watcherStopCmd, STOP_COMMAND); 107 | 108 | if ( !silgy_read_param_str("watcherStartCmd", M_watcherStartCmd) ) 109 | strcpy(M_watcherStartCmd, START_COMMAND); 110 | 111 | if ( !silgy_read_param_int("watcherWait", &M_watcherWait) ) 112 | M_watcherWait = 10; 113 | 114 | if ( !silgy_read_param_int("watcherLogRestart", &M_watcherLogRestart) ) 115 | M_watcherLogRestart = 3; 116 | 117 | /* start log --------------------------------------------------------- */ 118 | 119 | if ( !log_start("watcher", FALSE) ) 120 | return EXIT_FAILURE; 121 | 122 | /* ------------------------------------------------------------------- */ 123 | 124 | INF_T("Trying to connect..."); 125 | 126 | G_RESTTimeout = 60000; /* 60 seconds */ 127 | 128 | char url[1024]; 129 | 130 | sprintf(url, "127.0.0.1:%d", G_httpPort); 131 | 132 | REST_HEADER_SET("User-Agent", "Silgy Watcher Bot"); 133 | 134 | if ( !CALL_REST_HTTP(NULL, NULL, "GET", url, 0) ) 135 | { 136 | lib_update_time_globals(); 137 | ERR_T("Couldn't connect"); 138 | restart(); 139 | } 140 | 141 | /* ------------------------------------------------------------------- */ 142 | 143 | lib_update_time_globals(); 144 | 145 | INF_T("silgy_watcher ended"); 146 | 147 | log_finish(); 148 | 149 | return EXIT_SUCCESS; 150 | } 151 | -------------------------------------------------------------------------------- /src/silgy_app.cpp: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------- 2 | Silgy Web App 3 | Jurek Muszynski 4 | silgy.com 5 | ----------------------------------------------------------------------------- 6 | Hello World Sample Silgy Web Application 7 | -------------------------------------------------------------------------- */ 8 | 9 | 10 | #include 11 | 12 | 13 | /* -------------------------------------------------------------------------------- 14 | Called after parsing HTTP request header 15 | ------------------------------ 16 | This is the main entry point for a request 17 | ------------------------------ 18 | Response status will be 200 by default 19 | Use RES_STATUS() if you want to change it 20 | -------------------------------------------------------------------------------- */ 21 | void silgy_app_main(int ci) 22 | { 23 | if ( REQ("") ) // landing page 24 | { 25 | OUT_HTML_HEADER; 26 | 27 | OUT("

%s

", APP_WEBSITE); 28 | OUT("

Welcome to my web app!

"); 29 | 30 | if ( REQ_DSK ) 31 | OUT("

You're on desktop.

"); 32 | else /* REQ_MOB */ 33 | OUT("

You're on the phone.

"); 34 | 35 | OUT("

Click here to try my welcoming bot.

"); 36 | 37 | OUT_HTML_FOOTER; 38 | } 39 | else if ( REQ("welcome") ) // welcoming bot 40 | { 41 | OUT_HTML_HEADER; 42 | OUT("

%s

", APP_WEBSITE); 43 | 44 | OUT("

Please enter your name:

"); 45 | OUT("
"); 46 | 47 | QSVAL qs_firstname; // query string value 48 | 49 | if ( QS("firstname", qs_firstname) ) // if present, bid welcome 50 | OUT("

Welcome %s, my dear friend!

", qs_firstname); 51 | 52 | OUT("

Back to landing page

"); 53 | 54 | OUT_HTML_FOOTER; 55 | } 56 | else // page not found 57 | { 58 | RES_STATUS(404); 59 | } 60 | } 61 | 62 | 63 | /* -------------------------------------------------------------------------------- 64 | Called when application starts 65 | ------------------------------ 66 | Return true if everything OK 67 | ------------------------------ 68 | Returning false will stop booting process, 69 | silgy_app_done() will be called and application will be terminated 70 | -------------------------------------------------------------------------------- */ 71 | bool silgy_app_init(int argc, char *argv[]) 72 | { 73 | return true; 74 | } 75 | 76 | 77 | /* -------------------------------------------------------------------------------- 78 | Called when new anonymous user session starts 79 | ------------------------------ 80 | Return true if everything OK 81 | ------------------------------ 82 | Returning false will cause the session to be closed 83 | and silgy_app_session_done() will be called 84 | Response status will be set to 500 85 | -------------------------------------------------------------------------------- */ 86 | bool silgy_app_session_init(int ci) 87 | { 88 | return true; 89 | } 90 | 91 | 92 | /* -------------------------------------------------------------------------------- 93 | ******* Only for USERS ******* 94 | ------------------------------ 95 | Called after successful authentication (using password or cookie) 96 | when user session is upgraded from anonymous to logged in 97 | ------------------------------ 98 | Return true if everything OK 99 | ------------------------------ 100 | Returning false will cause the session to be downgraded back to anonymous 101 | and silgy_app_user_logout() will be called 102 | -------------------------------------------------------------------------------- */ 103 | bool silgy_app_user_login(int ci) 104 | { 105 | return true; 106 | } 107 | 108 | 109 | /* -------------------------------------------------------------------------------- 110 | ******* Only for USERS ******* 111 | ------------------------------ 112 | Called when downgrading logged in user session to anonymous 113 | -------------------------------------------------------------------------------- */ 114 | void silgy_app_user_logout(int ci) 115 | { 116 | } 117 | 118 | 119 | /* -------------------------------------------------------------------------------- 120 | Called when closing anonymous user session 121 | After calling this the session memory will be zero-ed 122 | -------------------------------------------------------------------------------- */ 123 | void silgy_app_session_done(int ci) 124 | { 125 | } 126 | 127 | 128 | /* -------------------------------------------------------------------------------- 129 | Called when application shuts down 130 | -------------------------------------------------------------------------------- */ 131 | void silgy_app_done() 132 | { 133 | } 134 | -------------------------------------------------------------------------------- /resmin/silgy.js: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------- 2 | // Show wait animation 3 | // -------------------------------------------------------------------------- 4 | function wait() 5 | { 6 | if ( !document.getElementById("wait") ) 7 | { 8 | let w = document.createElement("div"); 9 | w.id = "wait"; 10 | w.className = "wt"; // see silgy.css 11 | w.style.display = "block"; 12 | document.body.appendChild(w); 13 | } 14 | else 15 | document.getElementById("wait").style.display = "block"; 16 | } 17 | 18 | 19 | // -------------------------------------------------------------------------- 20 | // Turn the spinning wheel off 21 | // -------------------------------------------------------------------------- 22 | function wait_off() 23 | { 24 | document.getElementById("wait").style.display = "none"; 25 | } 26 | 27 | 28 | // -------------------------------------------------------------------------- 29 | // Go to link 30 | // l = url 31 | // -------------------------------------------------------------------------- 32 | function gt(l) 33 | { 34 | wait(); 35 | window.location.href = l; 36 | } 37 | 38 | 39 | // -------------------------------------------------------------------------- 40 | // Append a paragraph to the page 41 | // -------------------------------------------------------------------------- 42 | function p(t) 43 | { 44 | let p = document.createElement("p"); 45 | if ( t ) p.innerHTML = t; 46 | document.body.appendChild(p); 47 | return p; 48 | } 49 | 50 | 51 | // -------------------------------------------------------------------------- 52 | // Enter or Esc key hit 53 | // -------------------------------------------------------------------------- 54 | function ent(e) 55 | { 56 | if (e.keyCode==13) // Enter 57 | { 58 | document.getElementById("sbm").click(); // submit 59 | return false; 60 | } 61 | else if (e.keyCode==27) // Esc 62 | { 63 | document.getElementById("cnc").click(); // cancel 64 | return false; 65 | } 66 | 67 | return true; 68 | } 69 | 70 | 71 | // -------------------------------------------------------------------------- 72 | // Return true if cookies are enabled 73 | // -------------------------------------------------------------------------- 74 | function cookies() 75 | { 76 | try 77 | { 78 | document.cookie = "ct=1"; 79 | let enabled = document.cookie.indexOf("ct=") !== -1; 80 | document.cookie = "ct=1; expires=Thu, 01-Jan-1970 00:00:01 GMT"; 81 | return enabled; 82 | } 83 | catch (e) 84 | { 85 | return false; 86 | } 87 | } 88 | 89 | 90 | // -------------------------------------------------------------------------- 91 | // Center div 92 | // Call after appendChild 93 | // d = div handle 94 | // -------------------------------------------------------------------------- 95 | function center(d) 96 | { 97 | d.style.position = "fixed"; 98 | d.style.top = "50%"; 99 | d.style.left = "50%"; 100 | d.style.marginTop = -d.offsetTop/2 + "px"; 101 | d.style.marginLeft = -d.offsetWidth/2 + "px"; 102 | } 103 | 104 | 105 | // -------------------------------------------------------------------------- 106 | // Create modal window 107 | // l1 = first line 108 | // l2 = second line 109 | // w = width (em) 110 | // -------------------------------------------------------------------------- 111 | function mw(l1, l2, w) 112 | { 113 | let d = document.createElement("div"); 114 | 115 | if ( w ) 116 | d.style.width = w + "em"; 117 | else 118 | d.style.width = "20em"; 119 | 120 | d.className = "mw"; 121 | d.id = "mw"; 122 | 123 | let s1 = document.createElement("span"); 124 | 125 | s1.innerHTML = "
" 126 | + "" + l1 + "" 127 | + "
" 128 | + "

"; 129 | 130 | d.appendChild(s1); 131 | 132 | if ( l2 ) 133 | { 134 | let s2 = document.createElement("span"); 135 | s2.innerHTML = l2; 136 | d.appendChild(s2); 137 | } 138 | 139 | document.body.appendChild(d); 140 | center(d); 141 | 142 | window.addEventListener("keydown", mw_off); // allow keyboard escape 143 | } 144 | 145 | 146 | // -------------------------------------------------------------------------- 147 | // Remove modal window 148 | // -------------------------------------------------------------------------- 149 | function mw_off(e) 150 | { 151 | if ( e && e.keyCode!=27 ) return; 152 | window.removeEventListener("keydown", mw_off); 153 | let d = document.getElementById("mw"); 154 | d.parentNode.removeChild(d); 155 | } 156 | 157 | 158 | // -------------------------------------------------------------------------- 159 | // Create Yes/No modal window 160 | // t = text to display 161 | // a = action if Yes 162 | // w = width (em) 163 | // -------------------------------------------------------------------------- 164 | function yn(t, a, w) 165 | { 166 | mw(t, "
 
", w); 167 | } 168 | 169 | 170 | // -------------------------------------------------------------------------- 171 | // Set client's time on the server 172 | // -------------------------------------------------------------------------- 173 | function set_tz() 174 | { 175 | let dt = new Date(); 176 | 177 | let x = new XMLHttpRequest(); 178 | 179 | x.open("POST", "/set_tz", true); 180 | x.send("tz=" + Intl.DateTimeFormat().resolvedOptions().timeZone + "&tzo=" + dt.getTimezoneOffset()); 181 | } 182 | -------------------------------------------------------------------------------- /lib/silgy_usr.h: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------- 2 | Silgy Web App Engine 3 | Jurek Muszynski 4 | silgy.com 5 | ----------------------------------------------------------------------------- 6 | Logged in users' functions 7 | -------------------------------------------------------------------------- */ 8 | 9 | #ifndef SILGY_USR_H 10 | #define SILGY_USR_H 11 | 12 | 13 | #define DB_UAGENT_LEN 250 /* User-Agent length stored in ulogins table */ 14 | #define PASSWD_RESET_KEY_LEN 20 /* password reset key length */ 15 | 16 | #ifdef APP_MIN_USERNAME_LEN /* minimum user name length */ 17 | #define MIN_USERNAME_LEN APP_MIN_USERNAME_LEN 18 | #else 19 | #define MIN_USERNAME_LEN 2 20 | #endif 21 | 22 | #ifdef APP_MIN_PASSWORD_LEN /* minimum password length */ 23 | #define MIN_PASSWORD_LEN APP_MIN_PASSWORD_LEN 24 | #else 25 | #define MIN_PASSWORD_LEN 5 /* default minimal password length */ 26 | #endif 27 | 28 | #ifndef MAX_ULA_BEFORE_FIRST_SLOW /* maximum unsuccessful login tries before slowing down to 1 per minute */ 29 | #define MAX_ULA_BEFORE_FIRST_SLOW 10 30 | #endif 31 | 32 | #ifndef MAX_ULA_BEFORE_SECOND_SLOW /* maximum unsuccessful login tries before slowing down to 1 per hour */ 33 | #define MAX_ULA_BEFORE_SECOND_SLOW 25 34 | #endif 35 | 36 | #ifndef MAX_ULA_BEFORE_THIRD_SLOW /* maximum unsuccessful login tries before slowing down to 1 per day */ 37 | #define MAX_ULA_BEFORE_THIRD_SLOW 100 38 | #endif 39 | 40 | #ifndef MAX_ULA_BEFORE_LOCK /* maximum unsuccessful login tries before user lockout */ 41 | #define MAX_ULA_BEFORE_LOCK 1000 42 | #endif 43 | 44 | 45 | /* user status */ 46 | 47 | #define USER_STATUS_INACTIVE 0 48 | #define USER_STATUS_ACTIVE 1 49 | #define USER_STATUS_LOCKED 2 50 | #define USER_STATUS_PASSWORD_CHANGE 3 51 | #define USER_STATUS_DELETED 9 52 | 53 | 54 | /* configurable parameters */ 55 | 56 | #ifndef DEF_USER_AUTH_LEVEL 57 | #define DEF_USER_AUTH_LEVEL AUTH_LEVEL_USER /* default user authorization level */ 58 | #endif 59 | 60 | #ifndef USER_ACTIVATION_HOURS 61 | #define USER_ACTIVATION_HOURS 48 /* activate user account within */ 62 | #endif 63 | 64 | #ifndef USER_KEEP_LOGGED_DAYS 65 | #define USER_KEEP_LOGGED_DAYS 30 /* ls cookie validity period */ 66 | #endif 67 | 68 | 69 | #define COMMON_PASSWORDS_FILE "passwords.txt" 70 | 71 | 72 | #ifndef REFUSE_10_COMMON_PASSWORDS 73 | #ifndef REFUSE_100_COMMON_PASSWORDS 74 | #ifndef REFUSE_1000_COMMON_PASSWORDS 75 | #ifndef REFUSE_10000_COMMON_PASSWORDS 76 | #ifndef DONT_REFUSE_COMMON_PASSWORDS 77 | #define DONT_REFUSE_COMMON_PASSWORDS 78 | #endif 79 | #endif 80 | #endif 81 | #endif 82 | #endif 83 | 84 | 85 | /* Silgy engine errors are 0 ... 99 */ 86 | 87 | /* ------------------------------------- */ 88 | /* errors -- red */ 89 | 90 | /* login */ 91 | #define ERR_INVALID_LOGIN 101 92 | #define ERR_USERNAME_TOO_SHORT 102 93 | #define ERR_USERNAME_CHARS 103 94 | #define ERR_USERNAME_TAKEN 104 95 | /* ------------------------------------- */ 96 | #define ERR_MAX_USR_LOGIN_ERROR 110 97 | /* ------------------------------------- */ 98 | /* email */ 99 | #define ERR_EMAIL_EMPTY 111 100 | #define ERR_EMAIL_FORMAT 112 101 | #define ERR_EMAIL_FORMAT_OR_EMPTY 113 102 | #define ERR_EMAIL_TAKEN 114 103 | /* ------------------------------------- */ 104 | #define ERR_MAX_USR_EMAIL_ERROR 120 105 | /* ------------------------------------- */ 106 | /* password */ 107 | #define ERR_INVALID_PASSWORD 121 108 | #define ERR_PASSWORD_TOO_SHORT 122 109 | #define ERR_IN_10_COMMON_PASSWORDS 123 110 | #define ERR_IN_100_COMMON_PASSWORDS 124 111 | #define ERR_IN_1000_COMMON_PASSWORDS 125 112 | #define ERR_IN_10000_COMMON_PASSWORDS 126 113 | /* ------------------------------------- */ 114 | #define ERR_MAX_USR_PASSWORD_ERROR 130 115 | /* ------------------------------------- */ 116 | /* repeat password */ 117 | #define ERR_PASSWORD_DIFFERENT 131 118 | /* ------------------------------------- */ 119 | #define ERR_MAX_USR_REPEAT_PASSWORD_ERROR 140 120 | /* ------------------------------------- */ 121 | /* old password */ 122 | #define ERR_OLD_PASSWORD 141 123 | /* ------------------------------------- */ 124 | #define ERR_MAX_USR_OLD_PASSWORD_ERROR 150 125 | /* ------------------------------------- */ 126 | /* session / link / other */ 127 | #define ERR_SESSION_EXPIRED 151 128 | #define ERR_LINK_BROKEN 152 129 | #define ERR_LINK_MAY_BE_EXPIRED 153 130 | #define ERR_LINK_EXPIRED 154 131 | #define ERR_LINK_TOO_MANY_TRIES 155 132 | #define ERR_ROBOT 156 133 | #define ERR_WEBSITE_FIRST_LETTER 157 134 | #define ERR_NOT_ACTIVATED 158 135 | /* ------------------------------------- */ 136 | #define ERR_MAX_USR_ERROR 199 137 | /* ------------------------------------- */ 138 | 139 | /* ------------------------------------- */ 140 | /* warnings -- yellow */ 141 | 142 | #define WAR_NO_EMAIL 201 143 | #define WAR_BEFORE_DELETE 202 144 | #define WAR_ULA_FIRST 203 145 | #define WAR_ULA_SECOND 204 146 | #define WAR_ULA_THIRD 205 147 | #define WAR_PASSWORD_CHANGE 206 148 | /* ------------------------------------- */ 149 | #define WAR_MAX_USR_WARNING 299 150 | /* ------------------------------------- */ 151 | 152 | /* ------------------------------------- */ 153 | /* messages -- green */ 154 | 155 | #define MSG_WELCOME_NO_ACTIVATION 301 156 | #define MSG_WELCOME_NEED_ACTIVATION 302 157 | #define MSG_WELCOME_AFTER_ACTIVATION 303 158 | #define MSG_USER_LOGGED_OUT 304 159 | #define MSG_CHANGES_SAVED 305 160 | #define MSG_REQUEST_SENT 306 161 | #define MSG_PASSWORD_CHANGED 307 162 | #define MSG_MESSAGE_SENT 308 163 | #define MSG_PROVIDE_FEEDBACK 309 164 | #define MSG_FEEDBACK_SENT 310 165 | #define MSG_USER_ALREADY_ACTIVATED 311 166 | #define MSG_ACCOUNT_DELETED 312 167 | /* ------------------------------------- */ 168 | #define MSG_MAX_USR_MESSAGE 399 169 | /* ------------------------------------- */ 170 | 171 | 172 | #define MSG_CAT_USR_LOGIN "msgLogin" 173 | #define MSG_CAT_USR_EMAIL "msgEmail" 174 | #define MSG_CAT_USR_PASSWORD "msgPassword" 175 | #define MSG_CAT_USR_REPEAT_PASSWORD "msgPasswordRepeat" 176 | #define MSG_CAT_USR_OLD_PASSWORD "msgPasswordOld" 177 | 178 | 179 | #ifndef LUSES_TIMEOUT 180 | #define LUSES_TIMEOUT 1800 /* logged in user session timeout in seconds (120 for tests / 1800 live) */ 181 | #endif /* it's now how long it stays in cache */ 182 | 183 | /* user authentication */ 184 | 185 | #ifndef USERSBYEMAIL 186 | #ifndef USERSBYLOGIN 187 | #define USERSBYLOGIN 188 | #endif 189 | #endif 190 | 191 | /* passwords' hashing padding */ 192 | 193 | #ifndef STR_001 194 | #define STR_001 "abcde" 195 | #endif 196 | #ifndef STR_002 197 | #define STR_002 "fghij" 198 | #endif 199 | #ifndef STR_003 200 | #define STR_003 "klmno" 201 | #endif 202 | #ifndef STR_004 203 | #define STR_004 "pqrst" 204 | #endif 205 | #ifndef STR_005 206 | #define STR_005 "uvwxy" 207 | #endif 208 | 209 | 210 | #define MAX_AVATAR_SIZE 65536 /* MySQL's BLOB size */ 211 | 212 | 213 | #define SET_USER_STR(key, val) silgy_usr_set_str(ci, key, val) 214 | #define SET_USR_STR(key, val) silgy_usr_set_str(ci, key, val) 215 | 216 | #define GET_USER_STR(key, val) silgy_usr_get_str(ci, key, val) 217 | #define GET_USR_STR(key, val) silgy_usr_get_str(ci, key, val) 218 | 219 | #define SET_USER_INT(key, val) silgy_usr_set_int(ci, key, val) 220 | #define SET_USR_INT(key, val) silgy_usr_set_int(ci, key, val) 221 | 222 | #define GET_USER_INT(key, val) silgy_usr_get_int(ci, key, val) 223 | #define GET_USR_INT(key, val) silgy_usr_get_int(ci, key, val) 224 | 225 | 226 | /* 227 | Brute-force ls cookie attack protection. 228 | It essentially defines how many different IPs can take part in a botnet attack. 229 | */ 230 | 231 | #ifdef MEM_TINY 232 | #define FAILED_LOGIN_CNT_SIZE 100 233 | #elif defined MEM_MEDIUM 234 | #define FAILED_LOGIN_CNT_SIZE 1000 235 | #elif defined MEM_LARGE 236 | #define FAILED_LOGIN_CNT_SIZE 10000 237 | #elif defined MEM_XLARGE 238 | #define FAILED_LOGIN_CNT_SIZE 10000 239 | #elif defined MEM_XXLARGE 240 | #define FAILED_LOGIN_CNT_SIZE 100000 241 | #elif defined MEM_XXXLARGE 242 | #define FAILED_LOGIN_CNT_SIZE 100000 243 | #elif defined MEM_XXXXLARGE 244 | #define FAILED_LOGIN_CNT_SIZE 100000 245 | #else /* MEM_SMALL -- default */ 246 | #define FAILED_LOGIN_CNT_SIZE 1000 247 | #endif 248 | 249 | typedef struct { 250 | char ip[INET_ADDRSTRLEN]; 251 | int cnt; 252 | time_t when; 253 | } failed_login_cnt_t; 254 | 255 | 256 | #ifdef __cplusplus 257 | extern "C" { 258 | #endif 259 | int silgy_usr_login(int ci); 260 | int silgy_usr_password_quality(const char *passwd); 261 | int silgy_usr_create_account(int ci); 262 | int silgy_usr_add_user(int ci, bool use_qs, const char *login, const char *email, const char *name, const char *passwd, const char *phone, const char *lang, const char *about, char group_id, char auth_level, char status); 263 | int silgy_usr_send_message(int ci); 264 | int silgy_usr_save_account(int ci); 265 | int silgy_usr_email_registered(int ci); 266 | char *silgy_usr_name(const char *login, const char *email, const char *name, int uid); 267 | int silgy_usr_send_passwd_reset_email(int ci); 268 | int silgy_usr_verify_passwd_reset_key(int ci, char *linkkey, int *uid); 269 | int silgy_usr_activate(int ci); 270 | int silgy_usr_save_avatar(int ci, int uid); 271 | int silgy_usr_get_avatar(int ci, int uid); 272 | int silgy_usr_change_password(int ci); 273 | int silgy_usr_reset_password(int ci); 274 | void silgy_usr_logout(int ci); 275 | int silgy_usr_set_str(int ci, const char *us_key, const char *us_val); 276 | int silgy_usr_get_str(int ci, const char *us_key, char *us_val); 277 | int silgy_usr_set_int(int ci, const char *us_key, int us_val); 278 | int silgy_usr_get_int(int ci, const char *us_key, int *us_val); 279 | /* for the engine */ 280 | void libusr_init(void); 281 | int libusr_luses_ok(int ci); 282 | void libusr_luses_close_timeouted(void); 283 | void libusr_luses_save_csrft(void); 284 | void libusr_luses_downgrade(int usi, int ci, bool usr_logout); 285 | #ifdef __cplusplus 286 | } // extern "C" 287 | #endif 288 | 289 | 290 | #endif /* SILGY_USR_H */ 291 | -------------------------------------------------------------------------------- /lib/silgy_lib.h: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------- 2 | Silgy Web App Engine 3 | Jurek Muszynski 4 | silgy.com 5 | ----------------------------------------------------------------------------- 6 | General purpose library 7 | -------------------------------------------------------------------------- */ 8 | 9 | #ifndef SILGY_LIB_H 10 | #define SILGY_LIB_H 11 | 12 | 13 | #define ALWAYS(str, ...) log_write(LOG_ALWAYS, str, ##__VA_ARGS__) 14 | #define ERR(str, ...) log_write(LOG_ERR, str, ##__VA_ARGS__) 15 | #define WAR(str, ...) log_write(LOG_WAR, str, ##__VA_ARGS__) 16 | #define INF(str, ...) log_write(LOG_INF, str, ##__VA_ARGS__) 17 | #define DBG(str, ...) log_write(LOG_DBG, str, ##__VA_ARGS__) 18 | 19 | #define ALWAYS_T(str, ...) log_write_time(LOG_ALWAYS, str, ##__VA_ARGS__) 20 | #define ERR_T(str, ...) log_write_time(LOG_ERR, str, ##__VA_ARGS__) 21 | #define WAR_T(str, ...) log_write_time(LOG_WAR, str, ##__VA_ARGS__) 22 | #define INF_T(str, ...) log_write_time(LOG_INF, str, ##__VA_ARGS__) 23 | #define DBG_T(str, ...) log_write_time(LOG_DBG, str, ##__VA_ARGS__) 24 | 25 | #define LOG_LINE "--------------------------------------------------" 26 | #define LOG_LINE_N "--------------------------------------------------\n" 27 | #define LOG_LINE_NN "--------------------------------------------------\n\n" 28 | #define ALWAYS_LINE ALWAYS(LOG_LINE) 29 | #define INF_LINE INF(LOG_LINE) 30 | #define DBG_LINE DBG(LOG_LINE) 31 | 32 | #define LOG_LINE_LONG "--------------------------------------------------------------------------------------------------" 33 | #define LOG_LINE_LONG_N "--------------------------------------------------------------------------------------------------\n" 34 | #define LOG_LINE_LONG_NN "--------------------------------------------------------------------------------------------------\n\n" 35 | #define ALWAYS_LINE_LONG ALWAYS(LOG_LINE_LONG) 36 | #define INF_LINE_LONG INF(LOG_LINE_LONG) 37 | #define DBG_LINE_LONG DBG(LOG_LINE_LONG) 38 | 39 | #define LOREM_IPSUM "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." 40 | 41 | #define PARAM(param) (0==strcmp(label, param)) 42 | 43 | #define UTF8_ANY(c) (((unsigned char)c & 0x80) == 0x80) 44 | #define UTF8_START(c) (UTF8_ANY(c) && ((unsigned char)c & 0x40) == 0x40) 45 | 46 | #define COPY(dst, src, dst_len) silgy_safe_copy(dst, src, dst_len) 47 | 48 | 49 | /* Query String Value */ 50 | 51 | typedef char QSVAL[QSBUF]; 52 | //typedef struct QSVAL { char x[QSBUF]; } QSVAL; 53 | 54 | typedef char QSVAL1K[1024]; 55 | typedef char QSVAL2K[2048]; 56 | typedef char QSVAL4K[4096]; 57 | typedef char QSVAL8K[8192]; 58 | typedef char QSVAL16K[16384]; 59 | typedef char QSVAL32K[32768]; 60 | typedef char QSVAL64K[65536]; 61 | typedef char QSVAL_TEXT[65536]; 62 | 63 | 64 | /* query string values' retrieval */ 65 | 66 | #define ESC_NONE (char)0 67 | #define ESC_SQL (char)1 68 | #define ESC_HTML (char)2 69 | 70 | #define QS_DONT_ESCAPE(param, val) get_qs_param(ci, param, val, MAX_URI_VAL_LEN, ESC_NONE) 71 | #define QS_SQL_ESCAPE(param, val) get_qs_param(ci, param, val, MAX_URI_VAL_LEN, ESC_SQL) 72 | #define QS_HTML_ESCAPE(param, val) get_qs_param(ci, param, val, MAX_URI_VAL_LEN, ESC_HTML) 73 | 74 | #define QS_TEXT_DONT_ESCAPE(param, val) get_qs_param(ci, param, val, 65535, ESC_NONE) 75 | #define QS_TEXT_SQL_ESCAPE(param, val) get_qs_param(ci, param, val, 65535, ESC_SQL) 76 | #define QS_TEXT_HTML_ESCAPE(param, val) get_qs_param(ci, param, val, 65535, ESC_HTML) 77 | 78 | #ifdef QS_DEF_HTML_ESCAPE 79 | #define QS(param, val) get_qs_param(ci, param, val, MAX_URI_VAL_LEN, ESC_HTML) 80 | #define QS1K(param, val) get_qs_param(ci, param, val, 1023, ESC_HTML) 81 | #define QS2K(param, val) get_qs_param(ci, param, val, 2047, ESC_HTML) 82 | #define QS4K(param, val) get_qs_param(ci, param, val, 4095, ESC_HTML) 83 | #define QS8K(param, val) get_qs_param(ci, param, val, 8191, ESC_HTML) 84 | #define QS16K(param, val) get_qs_param(ci, param, val, 16383, ESC_HTML) 85 | #define QS32K(param, val) get_qs_param(ci, param, val, 32767, ESC_HTML) 86 | #define QS64K(param, val) get_qs_param(ci, param, val, 65535, ESC_HTML) 87 | #define QS_TEXT(param, val) get_qs_param(ci, param, val, 65535, ESC_HTML) 88 | #endif 89 | #ifdef QS_DEF_SQL_ESCAPE 90 | #define QS(param, val) get_qs_param(ci, param, val, MAX_URI_VAL_LEN, ESC_SQL) 91 | #define QS1K(param, val) get_qs_param(ci, param, val, 1023, ESC_SQL) 92 | #define QS2K(param, val) get_qs_param(ci, param, val, 2047, ESC_SQL) 93 | #define QS4K(param, val) get_qs_param(ci, param, val, 4095, ESC_SQL) 94 | #define QS8K(param, val) get_qs_param(ci, param, val, 8191, ESC_SQL) 95 | #define QS16K(param, val) get_qs_param(ci, param, val, 16383, ESC_SQL) 96 | #define QS32K(param, val) get_qs_param(ci, param, val, 32767, ESC_SQL) 97 | #define QS64K(param, val) get_qs_param(ci, param, val, 65535, ESC_SQL) 98 | #define QS_TEXT(param, val) get_qs_param(ci, param, val, 65535, ESC_SQL) 99 | #endif 100 | #ifdef QS_DEF_DONT_ESCAPE 101 | #define QS(param, val) get_qs_param(ci, param, val, MAX_URI_VAL_LEN, ESC_NONE) 102 | #define QS1K(param, val) get_qs_param(ci, param, val, 1023, ESC_NONE) 103 | #define QS2K(param, val) get_qs_param(ci, param, val, 2047, ESC_NONE) 104 | #define QS4K(param, val) get_qs_param(ci, param, val, 4095, ESC_NONE) 105 | #define QS8K(param, val) get_qs_param(ci, param, val, 8191, ESC_NONE) 106 | #define QS16K(param, val) get_qs_param(ci, param, val, 16383, ESC_NONE) 107 | #define QS32K(param, val) get_qs_param(ci, param, val, 32767, ESC_NONE) 108 | #define QS64K(param, val) get_qs_param(ci, param, val, 65535, ESC_NONE) 109 | #define QS_TEXT(param, val) get_qs_param(ci, param, val, 65535, ESC_NONE) 110 | #endif 111 | 112 | #define QSI(param, val) lib_qsi(ci, param, val) 113 | #define QSU(param, val) lib_qsu(ci, param, val) 114 | #define QSF(param, val) lib_qsf(ci, param, val) 115 | #define QSD(param, val) lib_qsd(ci, param, val) 116 | #define QSB(param, val) lib_qsb(ci, param, val) 117 | 118 | 119 | #define RES_HEADER(key, val) lib_res_header(ci, key, val) 120 | 121 | 122 | #ifdef APP_EMAIL_FROM_USER 123 | #define EMAIL_FROM_USER APP_EMAIL_FROM_USER 124 | #else 125 | #define EMAIL_FROM_USER "noreply" 126 | #endif 127 | 128 | 129 | #define CONNECT 0 130 | #define READ 1 131 | #define WRITE 2 132 | #define SHUTDOWN 3 133 | 134 | 135 | #define MAX_SHM_SEGMENTS 100 136 | 137 | 138 | /* API authorization system */ 139 | 140 | #define AUTH_NONE 0x00 141 | #define AUTH_CREATE 0x01 142 | #define AUTH_READ 0x02 143 | #define AUTH_UPDATE 0x04 144 | #define AUTH_DELETE 0x08 145 | #define AUTH_FULL 0xFF 146 | 147 | #define IS_AUTH_CREATE(flags) ((flags & AUTH_CREATE) == AUTH_CREATE) 148 | #define IS_AUTH_READ(flags) ((flags & AUTH_READ) == AUTH_READ) 149 | #define IS_AUTH_UPDATE(flags) ((flags & AUTH_UPDATE) == AUTH_UPDATE) 150 | #define IS_AUTH_DELETE(flags) ((flags & AUTH_DELETE) == AUTH_DELETE) 151 | 152 | 153 | 154 | /* languages */ 155 | 156 | #ifndef MAX_LANGUAGES 157 | #define MAX_LANGUAGES 250 158 | #endif 159 | 160 | typedef struct { 161 | char lang[LANG_LEN+1]; 162 | int first_index; 163 | int next_lang_index; 164 | } lang_t; 165 | 166 | 167 | 168 | /* messages */ 169 | 170 | #ifndef MAX_MSG_LEN 171 | #define MAX_MSG_LEN 255 172 | #endif 173 | 174 | #ifndef MAX_MESSAGES 175 | #define MAX_MESSAGES 1000 176 | #endif 177 | 178 | typedef struct { 179 | int code; 180 | char lang[LANG_LEN+1]; 181 | char message[MAX_MSG_LEN+1]; 182 | } message_t; 183 | 184 | 185 | #define silgy_message(code) lib_get_message(ci, code) 186 | #define MSG(code) lib_get_message(ci, code) 187 | #define MSG_CAT_GREEN(code) silgy_is_msg_main_cat(code, MSG_CAT_MESSAGE) 188 | #define MSG_CAT_ORANGE(code) silgy_is_msg_main_cat(code, MSG_CAT_WARNING) 189 | #define MSG_CAT_RED(code) silgy_is_msg_main_cat(code, MSG_CAT_ERROR) 190 | 191 | #define OUT_MSG_DESCRIPTION(code) lib_send_msg_description(ci, code) 192 | 193 | #define OUT_HTML_HEADER lib_out_html_header(ci) 194 | #define OUT_HTML_FOOTER lib_out_html_footer(ci) 195 | #define OUT_SNIPPET(name) lib_out_snippet(ci, name) 196 | #define OUT_SNIPPET_MD(name) lib_out_snippet_md(ci, name) 197 | 198 | #define GET_COOKIE(key, val) lib_get_cookie(ci, key, val) 199 | #define SET_COOKIE(key, val, days) lib_set_cookie(ci, key, val, days) 200 | 201 | 202 | /* strings */ 203 | 204 | #ifndef STRINGS_SEP 205 | #define STRINGS_SEP '|' 206 | #endif 207 | 208 | #ifndef STRINGS_LANG 209 | #define STRINGS_LANG "EN-US" 210 | #endif 211 | 212 | #ifndef MAX_STR_LEN 213 | #define MAX_STR_LEN 255 214 | #endif 215 | 216 | #ifndef MAX_STRINGS 217 | #define MAX_STRINGS 1000 218 | #endif 219 | 220 | typedef struct { 221 | char lang[LANG_LEN+1]; 222 | char string_upper[MAX_STR_LEN+1]; 223 | char string_in_lang[MAX_STR_LEN+1]; 224 | } string_t; 225 | 226 | 227 | 228 | /* format amount */ 229 | 230 | #define AMT(val) silgy_amt(val) 231 | 232 | 233 | 234 | /* REST calls */ 235 | 236 | #define REST_HEADER_KEY_LEN 255 237 | #define REST_HEADER_VAL_LEN 1023 238 | 239 | typedef struct { 240 | char key[REST_HEADER_KEY_LEN+1]; 241 | char value[REST_HEADER_VAL_LEN+1]; 242 | } rest_header_t; 243 | 244 | 245 | #define REST_MAX_HEADERS 100 246 | #define REST_HEADERS_RESET lib_rest_headers_reset() 247 | #define REST_HEADER_SET(key, val) lib_rest_header_set(key, val) 248 | #define REST_HEADER_UNSET(key) lib_rest_header_unset(key) 249 | 250 | 251 | #ifdef JSON_NO_AUTO_AMPERSANDS 252 | #define CALL_REST_HTTP(req, res, method, url, keep) lib_rest_req(req, res, method, url, FALSE, keep) 253 | #define CALL_REST_JSON(req, res, method, url, keep) lib_rest_req(req, res, method, url, TRUE, keep) 254 | #else 255 | #define CALL_REST_HTTP(req, res, method, url, keep) lib_rest_req((char*)req, (char*)res, method, url, FALSE, keep) 256 | #define CALL_REST_JSON(req, res, method, url, keep) lib_rest_req(&req, &res, method, url, TRUE, keep) 257 | #endif 258 | 259 | /* aliases -- highest level -- 'keep' always TRUE */ 260 | #define CALL_REST_RAW(req, res, method, url) CALL_REST_HTTP(req, res, method, url, TRUE) 261 | #define CALL_HTTP(req, res, method, url) CALL_REST_HTTP(req, res, method, url, TRUE) 262 | #define CALL_REST(req, res, method, url) CALL_REST_JSON(req, res, method, url, TRUE) 263 | 264 | 265 | #define CALL_REST_DEFAULT_TIMEOUT 10000 /* in ms -- to avoid blocking forever */ 266 | 267 | #define REST_RES_HEADER_LEN 4095 268 | #define REST_ADDRESSES_CACHE_SIZE 100 269 | 270 | 271 | #define CALL_HTTP_STATUS G_rest_status 272 | #define CALL_REST_STATUS CALL_HTTP_STATUS 273 | #define CALL_HTTP_CONTENT_TYPE G_rest_content_type 274 | #define CALL_REST_CONTENT_TYPE CALL_HTTP_CONTENT_TYPE 275 | #define CALL_HTTP_STATUS_OK (G_rest_status>=200 && G_rest_status<=204) 276 | #define CALL_REST_STATUS_OK CALL_HTTP_STATUS_OK 277 | 278 | 279 | /* JSON */ 280 | 281 | #define JSON_INTEGER 0 282 | #define JSON_UNSIGNED 1 283 | #define JSON_FLOAT 2 284 | #define JSON_DOUBLE 3 285 | #define JSON_STRING 4 286 | #define JSON_BOOL 5 287 | #define JSON_RECORD 6 288 | #define JSON_ARRAY 7 289 | 290 | #ifndef JSON_KEY_LEN 291 | #define JSON_KEY_LEN 31 292 | #endif 293 | #ifndef JSON_VAL_LEN 294 | #define JSON_VAL_LEN 255 295 | #endif 296 | 297 | #ifdef APP_JSON_MAX_ELEMS /* in one JSON struct */ 298 | #define JSON_MAX_ELEMS APP_JSON_MAX_ELEMS 299 | #else 300 | #define JSON_MAX_ELEMS 10 301 | #endif 302 | 303 | #ifdef APP_JSON_MAX_LEVELS 304 | #define JSON_MAX_LEVELS APP_JSON_MAX_LEVELS 305 | #else 306 | #ifdef MEM_TINY 307 | #define JSON_MAX_LEVELS 2 308 | #else 309 | #define JSON_MAX_LEVELS 4 310 | #endif 311 | #endif /* APP_JSON_MAX_LEVELS */ 312 | 313 | #ifdef MEM_TINY 314 | #define JSON_POOL_SIZE 100 /* for storing sub-JSONs */ 315 | #else 316 | #define JSON_POOL_SIZE 1000 /* for storing sub-JSONs */ 317 | #endif 318 | 319 | 320 | /* single JSON element */ 321 | 322 | typedef struct { 323 | char name[JSON_KEY_LEN+1]; 324 | char value[JSON_VAL_LEN+1]; 325 | char type; 326 | } json_elem_t; 327 | 328 | /* JSON object */ 329 | 330 | typedef struct { 331 | int cnt; 332 | char array; 333 | json_elem_t rec[JSON_MAX_ELEMS]; 334 | } json_t; 335 | 336 | typedef json_t JSON; 337 | 338 | 339 | #define JSON_MAX_FLOAT_LEN 8 340 | 341 | 342 | #ifdef APP_JSON_BUFSIZE 343 | #define JSON_BUFSIZE APP_JSON_BUFSIZE 344 | #else 345 | #define JSON_BUFSIZE 65568 346 | #endif 347 | 348 | 349 | #ifdef JSON_NO_AUTO_AMPERSANDS 350 | 351 | #define JSON_TO_STRING(json) lib_json_to_string(json) 352 | #define JSON_TO_STRING_PRETTY(json) lib_json_to_string_pretty(json) 353 | #define JSON_FROM_STRING(json, str) lib_json_from_string(json, str, 0, 0) 354 | 355 | 356 | #define JSON_ADD_STR(json, name, val) lib_json_add(json, name, val, 0, 0, 0, 0, JSON_STRING, -1) 357 | #define JSON_ADD_STR_A(json, i, val) lib_json_add(json, NULL, val, 0, 0, 0, 0, JSON_STRING, i) 358 | #define JSON_ADD_INT(json, name, val) lib_json_add(json, name, NULL, val, 0, 0, 0, JSON_INTEGER, -1) 359 | #define JSON_ADD_INT_A(json, i, val) lib_json_add(json, NULL, NULL, val, 0, 0, 0, JSON_INTEGER, i) 360 | #define JSON_ADD_UINT(json, name, val) lib_json_add(json, name, NULL, 0, val, 0, 0, JSON_UNSIGNED, -1) 361 | #define JSON_ADD_UINT_A(json, i, val) lib_json_add(json, NULL, NULL, 0, val, 0, 0, JSON_UNSIGNED, i) 362 | #define JSON_ADD_FLOAT(json, name, val) lib_json_add(json, name, NULL, 0, 0, val, 0, JSON_FLOAT, -1) 363 | #define JSON_ADD_FLOAT_A(json, i, val) lib_json_add(json, NULL, NULL, 0, 0, val, 0, JSON_FLOAT, i) 364 | #define JSON_ADD_DOUBLE(json, name, val) lib_json_add(json, name, NULL, 0, 0, 0, val, JSON_DOUBLE, -1) 365 | #define JSON_ADD_DOUBLE_A(json, i, val) lib_json_add(json, NULL, NULL, 0, 0, 0, val, JSON_DOUBLE, i) 366 | #define JSON_ADD_BOOL(json, name, val) lib_json_add(json, name, NULL, val, 0, 0, 0, JSON_BOOL, -1) 367 | #define JSON_ADD_BOOL_A(json, i, val) lib_json_add(json, NULL, NULL, val, 0, 0, 0, JSON_BOOL, i) 368 | 369 | #define JSON_ADD_RECORD(json, name, val) lib_json_add_record(json, name, val, FALSE, -1) 370 | #define JSON_ADD_RECORD_A(json, i ,val) lib_json_add_record(json, NULL, val, FALSE, i) 371 | 372 | #define JSON_ADD_ARRAY(json, name, val) lib_json_add_record(json, name, val, TRUE, -1) 373 | #define JSON_ADD_ARRAY_A(json, i, val) lib_json_add_record(json, NULL, val, TRUE, i) 374 | 375 | #define JSON_PRESENT(json, name) lib_json_present(json, name) 376 | 377 | #define JSON_GET_STR(json, name) lib_json_get_str(json, name, -1) 378 | #define JSON_GET_STR_A(json, i) lib_json_get_str(json, NULL, i) 379 | #define JSON_GET_INT(json, name) lib_json_get_int(json, name, -1) 380 | #define JSON_GET_INT_A(json, i) lib_json_get_int(json, NULL, i) 381 | #define JSON_GET_UINT(json, name) lib_json_get_uint(json, name, -1) 382 | #define JSON_GET_UINT_A(json, i) lib_json_get_uint(json, NULL, i) 383 | #define JSON_GET_FLOAT(json, name) lib_json_get_float(json, name, -1) 384 | #define JSON_GET_FLOAT_A(json, i) lib_json_get_float(json, NULL, i) 385 | #define JSON_GET_DOUBLE(json, name) lib_json_get_double(json, name, -1) 386 | #define JSON_GET_DOUBLE_A(json, i) lib_json_get_double(json, NULL, i) 387 | #define JSON_GET_BOOL(json, name) lib_json_get_bool(json, name, -1) 388 | #define JSON_GET_BOOL_A(json, i) lib_json_get_bool(json, NULL, i) 389 | 390 | #define JSON_GET_RECORD(json, name, val) lib_json_get_record(json, name, val, -1) 391 | #define JSON_GET_RECORD_A(json, i, val) lib_json_get_record(json, NULL, val, i) 392 | 393 | #define JSON_GET_ARRAY(json, name, val) lib_json_get_record(json, name, val, -1) 394 | #define JSON_GET_ARRAY_A(json, i, val) lib_json_get_record(json, NULL, val, i) 395 | 396 | 397 | #define JSON_RESET(json) lib_json_reset(json) 398 | #define JSON_COUNT(json) json.cnt 399 | 400 | #define JSON_LOG_DBG(json, name) lib_json_log_dbg(json, name) 401 | #define JSON_LOG_INF(json, name) lib_json_log_inf(json, name) 402 | 403 | #else /* JSON_NO_AUTO_AMPERSANDS not defined */ 404 | 405 | #define JSON_TO_STRING(json) lib_json_to_string(&json) 406 | #define JSON_TO_STRING_PRETTY(json) lib_json_to_string_pretty(&json) 407 | #define JSON_FROM_STRING(json, str) lib_json_from_string(&json, str, 0, 0) 408 | 409 | 410 | #define JSON_ADD_STR(json, name, val) lib_json_add(&json, name, val, 0, 0, 0, 0, JSON_STRING, -1) 411 | #define JSON_ADD_STR_A(json, i, val) lib_json_add(&json, NULL, val, 0, 0, 0, 0, JSON_STRING, i) 412 | #define JSON_ADD_INT(json, name, val) lib_json_add(&json, name, NULL, val, 0, 0, 0, JSON_INTEGER, -1) 413 | #define JSON_ADD_INT_A(json, i, val) lib_json_add(&json, NULL, NULL, val, 0, 0, 0, JSON_INTEGER, i) 414 | #define JSON_ADD_UINT(json, name, val) lib_json_add(&json, name, NULL, 0, val, 0, 0, JSON_UNSIGNED, -1) 415 | #define JSON_ADD_UINT_A(json, i, val) lib_json_add(&json, NULL, NULL, 0, val, 0, 0, JSON_UNSIGNED, i) 416 | #define JSON_ADD_FLOAT(json, name, val) lib_json_add(&json, name, NULL, 0, 0, val, 0, JSON_FLOAT, -1) 417 | #define JSON_ADD_FLOAT_A(json, i, val) lib_json_add(&json, NULL, NULL, 0, 0, val, 0, JSON_FLOAT, i) 418 | #define JSON_ADD_DOUBLE(json, name, val) lib_json_add(&json, name, NULL, 0, 0, 0, val, JSON_DOUBLE, -1) 419 | #define JSON_ADD_DOUBLE_A(json, i, val) lib_json_add(&json, NULL, NULL, 0, 0, 0, val, JSON_DOUBLE, i) 420 | #define JSON_ADD_BOOL(json, name, val) lib_json_add(&json, name, NULL, val, 0, 0, 0, JSON_BOOL, -1) 421 | #define JSON_ADD_BOOL_A(json, i, val) lib_json_add(&json, NULL, NULL, val, 0, 0, 0, JSON_BOOL, i) 422 | 423 | #define JSON_ADD_RECORD(json, name, val) lib_json_add_record(&json, name, &val, FALSE, -1) 424 | #define JSON_ADD_RECORD_A(json, i, val) lib_json_add_record(&json, NULL, &val, FALSE, i) 425 | 426 | #define JSON_ADD_ARRAY(json, name, val) lib_json_add_record(&json, name, &val, TRUE, -1) 427 | #define JSON_ADD_ARRAY_A(json, i, val) lib_json_add_record(&json, NULL, &val, TRUE, i) 428 | 429 | #define JSON_PRESENT(json, name) lib_json_present(&json, name) 430 | 431 | #define JSON_GET_STR(json, name) lib_json_get_str(&json, name, -1) 432 | #define JSON_GET_STR_A(json, i) lib_json_get_str(&json, NULL, i) 433 | #define JSON_GET_INT(json, name) lib_json_get_int(&json, name, -1) 434 | #define JSON_GET_INT_A(json, i) lib_json_get_int(&json, NULL, i) 435 | #define JSON_GET_UINT(json, name) lib_json_get_uint(&json, name, -1) 436 | #define JSON_GET_UINT_A(json, i) lib_json_get_uint(&json, NULL, i) 437 | #define JSON_GET_FLOAT(json, name) lib_json_get_float(&json, name, -1) 438 | #define JSON_GET_FLOAT_A(json, i) lib_json_get_float(&json, NULL, i) 439 | #define JSON_GET_DOUBLE(json, name) lib_json_get_double(&json, name, -1) 440 | #define JSON_GET_DOUBLE_A(json, i) lib_json_get_double(&json, NULL, i) 441 | #define JSON_GET_BOOL(json, name) lib_json_get_bool(&json, name, -1) 442 | #define JSON_GET_BOOL_A(json, i) lib_json_get_bool(&json, NULL, i) 443 | 444 | #define JSON_GET_RECORD(json, name, val) lib_json_get_record(&json, name, &val, -1) 445 | #define JSON_GET_RECORD_A(json, i, val) lib_json_get_record(&json, NULL, &val, i) 446 | 447 | #define JSON_GET_ARRAY(json, name, val) lib_json_get_record(&json, name, &val, -1) 448 | #define JSON_GET_ARRAY_A(json, i, val) lib_json_get_record(&json, NULL, &val, i) 449 | 450 | 451 | #define JSON_RESET(json) lib_json_reset(&json) 452 | #define JSON_COUNT(json) json.cnt 453 | 454 | #define JSON_LOG_DBG(json, name) lib_json_log_dbg(&json, name) 455 | #define JSON_LOG_INF(json, name) lib_json_log_inf(&json, name) 456 | 457 | #endif /* JSON_NO_AUTO_AMPERSANDS */ 458 | 459 | 460 | /* for backward compatibility */ 461 | #define silgy_read_param(param, val) silgy_read_param_str(param, val) 462 | 463 | 464 | #define AI_USERS_ALL 0 /* all users */ 465 | #define AI_USERS_YAU 1 /* yearly active */ 466 | #define AI_USERS_MAU 2 /* monthly active */ 467 | #define AI_USERS_DAU 3 /* daily active */ 468 | 469 | 470 | #ifdef __cplusplus 471 | extern "C" { 472 | #endif 473 | void silgy_lib_init(void); 474 | void silgy_lib_done(void); 475 | void silgy_safe_copy(char *dst, const char *src, size_t dst_len); 476 | void silgy_set_tz(int ci); 477 | time_t silgy_ua_time(int ci); 478 | char *silgy_ua_today(int ci); 479 | char *silgy_today(void); 480 | char *silgy_render_md(char *dest, const char *src, size_t len); 481 | char *silgy_json_enc(const char *src); 482 | bool lib_csrft_ok(int ci); 483 | void silgy_add_message(int code, const char *lang, const char *message, ...); 484 | int compare_messages(const void *a, const void *b); 485 | void sort_messages(void); 486 | char *lib_get_message(int ci, int code); 487 | bool silgy_is_msg_main_cat(int code, const char *cat); 488 | void silgy_add_string(const char *lang, const char *str, const char *str_lang); 489 | const char *lib_get_string(int ci, const char *str); 490 | char *urlencode(const char *src); 491 | bool lib_open_db(void); 492 | void lib_close_db(void); 493 | bool lib_file_exists(const char *fname); 494 | void lib_get_exec_name(char *dst, const char *path); 495 | void lib_update_time_globals(void); 496 | bool read_snippets(bool first_scan, const char *path); 497 | char *silgy_get_snippet(const char *name); 498 | unsigned silgy_get_snippet_len(const char *name); 499 | void lib_out_snippet(int ci, const char *name); 500 | void lib_out_snippet_md(int ci, const char *name); 501 | void lib_setnonblocking(int sock); 502 | void lib_out_html_header(int ci); 503 | void lib_out_html_footer(int ci); 504 | void lib_append_css(int ci, const char *fname, bool first); 505 | void lib_append_script(int ci, const char *fname, bool first); 506 | char *uri_decode(char *src, int srclen, char *dest, int maxlen); 507 | bool get_qs_param(int ci, const char *fieldname, char *retbuf, int maxlen, char esc_type); 508 | bool get_qs_param_raw(int ci, const char *fieldname, char *retbuf, int maxlen); 509 | char *get_qs_param_multipart(int ci, const char *fieldname, unsigned *retlen, char *retfname); 510 | bool lib_qsi(int ci, const char *fieldname, int *retbuf); 511 | bool lib_qsu(int ci, const char *fieldname, unsigned *retbuf); 512 | bool lib_qsf(int ci, const char *fieldname, float *retbuf); 513 | bool lib_qsd(int ci, const char *fieldname, double *retbuf); 514 | bool lib_qsb(int ci, const char *fieldname, bool *retbuf); 515 | void lib_set_res_status(int ci, int status); 516 | bool lib_res_header(int ci, const char *hdr, const char *val); 517 | bool lib_get_cookie(int ci, const char *key, char *value); 518 | bool lib_set_cookie(int ci, const char *key, const char *value, int days); 519 | void lib_set_res_content_type(int ci, const char *str); 520 | void lib_set_res_location(int ci, const char *str, ...); 521 | void lib_set_res_content_disposition(int ci, const char *str, ...); 522 | void lib_send_msg_description(int ci, int code); 523 | void silgy_admin_info(int ci, int users, admin_info_t ai[], int ai_cnt, bool header_n_footer); 524 | void lib_rest_headers_reset(void); 525 | void lib_rest_header_set(const char *key, const char *value); 526 | void lib_rest_header_unset(const char *key); 527 | bool lib_rest_req(const void *req, void *res, const char *method, const char *url, bool json, bool keep); 528 | int lib_finish_with_timeout(int sock, char oper, char readwrite, char *buffer, int len, int *msec, void *ssl, int level); 529 | void log_ssl_error(int ssl_err); 530 | void lib_get_app_dir(void); 531 | double lib_elapsed(struct timespec *start); 532 | int lib_get_memory(void); 533 | void lib_log_memory(void); 534 | char *silgy_filter_strict(const char *src); 535 | char *lib_add_spaces(const char *src, int len); 536 | char *lib_add_lspaces(const char *src, int len); 537 | char *get_file_ext(const char *fname); 538 | char get_res_type(const char *fname); 539 | void date_str2rec(const char *str, date_t *rec); 540 | void date_rec2str(char *str, date_t *rec); 541 | time_t time_http2epoch(const char *str); 542 | time_t time_db2epoch(const char *str); 543 | char *time_epoch2http(time_t epoch); 544 | char *time_epoch2db(time_t epoch); 545 | void lib_set_datetime_formats(const char *lang); 546 | char *silgy_amt(double val); 547 | void amt(char *stramt, long long in_amt); 548 | void amtd(char *stramt, double in_amt); 549 | void lib_amt(char *stramt, long in_amt); 550 | void lib_amtd(char *stramt, double in_amt); 551 | void samts(char *stramt, const char *in_amt); 552 | void lib_normalize_float(char *str); 553 | void ftm(char *strtm, long in_tm); 554 | char *fmt_date(short year, short month, short day); 555 | char const *san(const char *str); 556 | char *san_long(const char *str); 557 | char *silgy_sql_esc(const char *str); 558 | char *silgy_html_esc(const char *str); 559 | void sanitize_sql(char *dst, const char *str, int len); 560 | void sanitize_html(char *dst, const char *str, int len); 561 | char *silgy_html_unesc(const char *str); 562 | char *uri_encode(const char *str); 563 | char *upper(const char *str); 564 | char *stp_right(char *str); 565 | bool strdigits(const char *src); 566 | char *nospaces(char *dst, const char *src); 567 | void init_random_numbers(void); 568 | void silgy_random(char *dest, int len); 569 | void msleep(int msec); 570 | void lib_json_reset(JSON *json); 571 | char *lib_json_to_string(JSON *json); 572 | char *lib_json_to_string_pretty(JSON *json); 573 | bool lib_json_from_string(JSON *json, const char *src, int len, int level); 574 | bool lib_json_add(JSON *json, const char *name, const char *str_value, int int_value, unsigned uint_value, float flo_value, double dbl_value, char type, int i); 575 | bool lib_json_add_record(JSON *json, const char *name, JSON *json_sub, bool is_array, int i); 576 | bool lib_json_get(JSON *json, const char *name, char *str_value, int *num_value, char type); 577 | bool lib_json_present(JSON *json, const char *name); 578 | char *lib_json_get_str(JSON *json, const char *name, int i); 579 | int lib_json_get_int(JSON *json, const char *name, int i); 580 | unsigned lib_json_get_uint(JSON *json, const char *name, int i); 581 | float lib_json_get_float(JSON *json, const char *name, int i); 582 | double lib_json_get_double(JSON *json, const char *name, int i); 583 | bool lib_json_get_bool(JSON *json, const char *name, int i); 584 | bool lib_json_get_record(JSON *json, const char *name, JSON *json_sub, int i); 585 | void lib_json_log_dbg(JSON *json, const char *name); 586 | void lib_json_log_inf(JSON *json, const char *name); 587 | void get_byteorder(void); 588 | time_t db2epoch(const char *str); 589 | bool silgy_email(const char *to, const char *subject, const char *message); 590 | bool silgy_email_attach(const char *to, const char *subject, const char *message, const char *att_name, const char *att_data, int att_data_len); 591 | int silgy_minify(char *dest, const char *src); 592 | void date_inc(char *str, int days, int *dow); 593 | int date_cmp(const char *str1, const char *str2); 594 | bool lib_read_conf(const char *file); 595 | bool silgy_read_param_str(const char *param, char *dest); 596 | bool silgy_read_param_int(const char *param, int *dest); 597 | char *lib_create_pid_file(const char *name); 598 | char *lib_shm_create(unsigned bytes, int index); 599 | void lib_shm_delete(int index); 600 | bool log_start(const char *prefix, bool test); 601 | void log_write_time(int level, const char *message, ...); 602 | void log_write(int level, const char *message, ...); 603 | void log_long(const char *str, int len, const char *desc); 604 | void log_flush(void); 605 | void log_finish(void); 606 | #ifdef ICONV 607 | char *silgy_convert(const char *src, const char *cp_from, const char *cp_to); 608 | #endif 609 | 610 | char *md5(const char* str); 611 | 612 | int Base64encode_len(int len); 613 | int Base64encode(char *coded_dst, const char *plain_src, int len_plain_src); 614 | int Base64decode_len(const char *coded_src); 615 | int Base64decode(char *plain_dst, const char *coded_src); 616 | 617 | #ifdef _WIN32 /* Windows */ 618 | int getpid(void); 619 | int clock_gettime_win(struct timespec *spec); 620 | char *stpcpy(char *dest, const char *src); 621 | char *stpncpy(char *dest, const char *src, size_t len); 622 | #endif /* _WIN32 */ 623 | 624 | #ifndef strnstr 625 | char *strnstr(const char *haystack, const char *needle, size_t len); 626 | #endif 627 | 628 | #ifdef __cplusplus 629 | } // extern "C" 630 | #endif 631 | 632 | 633 | #include 634 | 635 | #ifdef __cplusplus 636 | extern "C" { 637 | #endif 638 | 639 | typedef struct { 640 | uint32_t state[5]; 641 | uint32_t count[2]; 642 | uint8_t buffer[64]; 643 | } SHA1_CTX; 644 | 645 | #define SHA1_DIGEST_SIZE 20 646 | 647 | void libSHA1(unsigned char *ptr, unsigned int size, unsigned char *outbuf); 648 | 649 | void digest_to_hex(const uint8_t digest[SHA1_DIGEST_SIZE], char *output); 650 | 651 | 652 | #ifdef __cplusplus 653 | } 654 | #endif 655 | 656 | #endif /* SILGY_LIB_H */ 657 | -------------------------------------------------------------------------------- /lib/silgy.h: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------- 2 | Silgy Web App Engine 3 | Jurek Muszynski 4 | silgy.com 5 | Started: August 2015 6 | -------------------------------------------------------------------------- */ 7 | 8 | #ifndef SILGY_H 9 | #define SILGY_H 10 | 11 | #ifdef _WIN32 /* Windows */ 12 | #ifdef _MSC_VER /* Microsoft compiler */ 13 | /* libraries */ 14 | #pragma comment(lib, "ws2_32.lib") 15 | #pragma comment(lib, "psapi.lib") /* GetProcessMemoryInfo */ 16 | /* __VA_ARGS__ issue */ 17 | #define EXPAND_VA(x) x 18 | /* access function */ 19 | #define F_OK 0 /* test for existence of file */ 20 | #define X_OK 0x01 /* test for execute or search permission */ 21 | #define W_OK 0x02 /* test for write permission */ 22 | #define R_OK 0x04 /* test for read permission */ 23 | #endif /* _MSC_VER */ 24 | #undef _WIN32_WINNT 25 | #define _WIN32_WINNT 0x0501 /* Windows XP or higher required */ 26 | #include 27 | #include 28 | #include 29 | #define CLOCK_MONOTONIC 0 /* dummy */ 30 | #undef OUT 31 | #endif /* _WIN32 */ 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | #ifndef _WIN32 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #endif /* _WIN32 */ 50 | 51 | #include 52 | #include 53 | #include 54 | 55 | #ifdef __cplusplus 56 | #include 57 | #include 58 | #else /* C */ 59 | #include 60 | typedef char bool; 61 | #define false ((char)0) 62 | #define true ((char)1) 63 | #endif /* __cplusplus */ 64 | 65 | 66 | #define WEB_SERVER_VERSION "4.5.9" 67 | /* alias */ 68 | #define SILGY_VERSION WEB_SERVER_VERSION 69 | 70 | 71 | #ifndef FALSE 72 | #define FALSE false 73 | #endif 74 | #ifndef TRUE 75 | #define TRUE true 76 | #endif 77 | 78 | 79 | /* pure C string type */ 80 | 81 | typedef char str1k[1024]; 82 | typedef char str2k[1024*2]; 83 | typedef char str4k[1024*4]; 84 | typedef char str8k[1024*8]; 85 | typedef char str16k[1024*16]; 86 | typedef char str32k[1024*32]; 87 | typedef char str64k[1024*64]; 88 | typedef char str128k[1024*128]; 89 | typedef char str256k[1024*256]; 90 | 91 | 92 | #define OK 0 93 | #define SUCCEED OK 94 | #define FAIL -1 95 | 96 | #define EOS ((char)0) /* End Of String */ 97 | 98 | 99 | /* log levels */ 100 | 101 | #define LOG_ALWAYS 0 /* print always */ 102 | #define LOG_ERR 1 /* print errors only */ 103 | #define LOG_WAR 2 /* print errors and warnings */ 104 | #define LOG_INF 3 /* print errors and warnings and info */ 105 | #define LOG_DBG 4 /* for debug mode -- most detailed */ 106 | 107 | 108 | #define MAX_URI_VAL_LEN 255 /* max value length received in URI -- sufficient for 99% cases */ 109 | #define MAX_LONG_URI_VAL_LEN 65535 /* max long value length received in URI -- 64 kB - 1 B */ 110 | 111 | #define QSBUF MAX_URI_VAL_LEN+1 112 | #define QS_BUF QSBUF 113 | 114 | #define WEBSITE_LEN 63 115 | #define CONTENT_TYPE_LEN 63 116 | #define CONTENT_DISP_LEN 127 117 | 118 | #define LOGIN_LEN 30 119 | #define EMAIL_LEN 120 120 | #define UNAME_LEN 120 121 | #define PHONE_LEN 30 122 | #define ABOUT_LEN 250 123 | 124 | 125 | #define VIEW_DEFAULT '0' 126 | #define VIEW_DESKTOP '1' 127 | #define VIEW_MOBILE '2' 128 | 129 | 130 | #define SQLBUF 4096 /* SQL query buffer size */ 131 | 132 | 133 | 134 | /* UTF-8 */ 135 | 136 | #define CHAR_POUND "£" 137 | #define CHAR_COPYRIGHT "©" 138 | #define CHAR_N_ACUTE "ń" 139 | #define CHAR_DOWN_ARROWHEAD1 "˅" 140 | #define CHAR_LONG_DASH "—" 141 | #define CHAR_EURO "€" 142 | #define CHAR_UP "↑" 143 | #define CHAR_DOWN "↓" 144 | #define CHAR_MINUS "−" 145 | #define CHAR_VEL "∨" 146 | #define CHAR_VERTICAL_ELLIPSIS "⋮" 147 | #define CHAR_COUNTERSINK "⌵" 148 | #define CHAR_DOUBLE_TRIANGLE_U "⏫" 149 | #define CHAR_DOUBLE_TRIANGLE_D "⏬" 150 | #define CHAR_DOWN_TRIANGLE_B "▼" 151 | #define CHAR_DOWN_TRIANGLE_W "▽" 152 | #define CHAR_CLOSE "✕" 153 | #define CHAR_HEAVY_PLUS "➕" 154 | #define CHAR_HEAVY_MINUS "➖" 155 | #define CHAR_DOWN_ARROWHEAD2 "﹀" 156 | #define CHAR_FULLW_PLUS "+" 157 | #define CHAR_LESS_EQUAL "≤" 158 | #define CHAR_GREATER_EQUAL "≥" 159 | 160 | 161 | #ifndef SILGY_SVC 162 | #ifndef SILGY_WATCHER 163 | #define SILGY_APP 164 | #endif 165 | #endif 166 | 167 | 168 | #include "silgy_app.h" 169 | 170 | 171 | /* select() vs poll() vs epoll() */ 172 | 173 | #ifdef _WIN32 174 | #define FD_MON_SELECT /* WSAPoll doesn't seem to be a reliable alternative */ 175 | #undef FD_MON_POLL 176 | #undef FD_MON_EPOLL 177 | #ifdef ASYNC 178 | #undef ASYNC 179 | #endif 180 | #else 181 | #ifndef FD_MON_SELECT 182 | #define FD_MON_POLL 183 | #endif 184 | #endif /* _WIN32 */ 185 | 186 | 187 | #ifdef SILGY_WATCHER 188 | #define SILGY_CLIENT 189 | #ifdef HTTPS 190 | #undef HTTPS 191 | #endif 192 | #endif 193 | 194 | #ifdef SILGY_CLIENT 195 | #ifdef DBMYSQL 196 | #undef DBMYSQL 197 | #endif 198 | #ifdef USERS 199 | #undef USERS 200 | #endif 201 | #endif /* SILGY_CLIENT */ 202 | 203 | 204 | #ifdef DBMYSQL 205 | #include 206 | #include 207 | #endif 208 | 209 | #ifdef HTTPS 210 | #include 211 | #include 212 | #endif 213 | 214 | 215 | /* request macros */ 216 | 217 | #define REQ_METHOD conn[ci].method 218 | #define REQ_GET (0==strcmp(conn[ci].method, "GET")) 219 | #define REQ_POST (0==strcmp(conn[ci].method, "POST")) 220 | #define REQ_PUT (0==strcmp(conn[ci].method, "PUT")) 221 | #define REQ_DELETE (0==strcmp(conn[ci].method, "DELETE")) 222 | #define REQ_OPTIONS (0==strcmp(conn[ci].method, "OPTIONS")) 223 | #define REQ_URI conn[ci].uri 224 | #define REQ_CONTENT_TYPE conn[ci].in_ctypestr 225 | #define REQ_DSK !conn[ci].mobile 226 | #define REQ_MOB conn[ci].mobile 227 | #define REQ_BOT conn[ci].bot 228 | #define REQ_LANG conn[ci].lang 229 | 230 | #define PROTOCOL (conn[ci].secure?"https":"http") 231 | #define COLON_POSITION (conn[ci].secure?5:4) 232 | 233 | 234 | /* defaults */ 235 | 236 | #ifndef MEM_TINY 237 | #ifndef MEM_MEDIUM 238 | #ifndef MEM_LARGE 239 | #ifndef MEM_XLARGE 240 | #ifndef MEM_XXLARGE 241 | #ifndef MEM_XXXLARGE 242 | #ifndef MEM_XXXXLARGE 243 | #ifndef MEM_SMALL 244 | #define MEM_SMALL /* default memory model */ 245 | #endif 246 | #endif 247 | #endif 248 | #endif 249 | #endif 250 | #endif 251 | #endif 252 | #endif 253 | 254 | #ifndef OUTFAST 255 | #ifndef OUTCHECK 256 | #define OUTCHECKREALLOC /* default output type */ 257 | #endif 258 | #endif 259 | 260 | #ifndef QS_DEF_SQL_ESCAPE 261 | #ifndef QS_DEF_DONT_ESCAPE 262 | #define QS_DEF_HTML_ESCAPE /* default query string security */ 263 | #endif 264 | #endif 265 | 266 | /* generate output as fast as possible */ 267 | 268 | #ifdef SILGY_SVC 269 | 270 | #ifdef OUTFAST 271 | #define OUTSS(str) (p_content = stpcpy(p_content, str)) 272 | #define OUT_BIN(data, len) (len=(len>G_async_res_data_size?G_async_res_data_size:len), memcpy(p_content, data, len), p_content += len) 273 | #elif defined (OUTCHECK) 274 | #define OUTSS(str) svc_out_check(str) 275 | #define OUT_BIN(data, len) (len=(len>G_async_res_data_size?G_async_res_data_size:len), memcpy(p_content, data, len), p_content += len) 276 | #else /* OUTCHECKREALLOC */ 277 | #define OUTSS(str) svc_out_check_realloc(str) 278 | #define OUT_BIN(data, len) svc_out_check_realloc_bin(data, len) 279 | #endif 280 | 281 | #else /* SILGY_APP */ 282 | 283 | #define HOUT(str) (conn[ci].p_header = stpcpy(conn[ci].p_header, str)) 284 | 285 | #ifdef OUTFAST 286 | #define OUTSS(str) (conn[ci].p_content = stpcpy(conn[ci].p_content, str)) 287 | #define OUT_BIN(data, len) (len=(len>OUT_BUFSIZE-OUT_HEADER_BUFSIZE?OUT_BUFSIZE-OUT_HEADER_BUFSIZE:len), memcpy(conn[ci].p_content, data, len), conn[ci].p_content += len) 288 | #else 289 | #ifdef OUTCHECK 290 | #define OUTSS(str) eng_out_check(ci, str) 291 | #define OUT_BIN(data, len) (len=(len>OUT_BUFSIZE-OUT_HEADER_BUFSIZE?OUT_BUFSIZE-OUT_HEADER_BUFSIZE:len), memcpy(conn[ci].p_content, data, len), conn[ci].p_content += len) 292 | #else /* OUTCHECKREALLOC */ 293 | #define OUTSS(str) eng_out_check_realloc(ci, str) 294 | #define OUT_BIN(data, len) eng_out_check_realloc_bin(ci, data, len) 295 | #endif 296 | #endif /* OUTFAST */ 297 | 298 | #endif /* SILGY_SVC */ 299 | 300 | #ifdef _MSC_VER /* Microsoft compiler */ 301 | #define OUT(...) (sprintf(G_tmp, EXPAND_VA(__VA_ARGS__)), OUTSS(G_tmp)) 302 | #else /* GCC */ 303 | #define OUTM(str, ...) (sprintf(G_tmp, str, __VA_ARGS__), OUTSS(G_tmp)) /* OUT with multiple args */ 304 | #define CHOOSE_OUT(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, NAME, ...) NAME /* single or multiple? */ 305 | #define OUT(...) CHOOSE_OUT(__VA_ARGS__, OUTM, OUTM, OUTM, OUTM, OUTM, OUTM, OUTM, OUTM, OUTM, OUTM, OUTM, OUTM, OUTM, OUTSS)(__VA_ARGS__) 306 | #endif /* _MSC_VER */ 307 | 308 | 309 | /* convenient & fast string building */ 310 | 311 | #define OUTP_BEGIN(buf) char *p4outp=buf 312 | 313 | #define OUTPS(str) (p4outp = stpcpy(p4outp, str)) 314 | 315 | #ifdef _MSC_VER /* Microsoft compiler */ 316 | #define OUTP(...) (sprintf(G_tmp, EXPAND_VA(__VA_ARGS__)), OUTPS(G_tmp)) 317 | #else /* GCC */ 318 | #define OUTPM(str, ...) (sprintf(G_tmp, str, __VA_ARGS__), OUTPS(G_tmp)) /* OUTP with multiple args */ 319 | #define CHOOSE_OUTP(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, NAME, ...) NAME /* single or multiple? */ 320 | #define OUTP(...) CHOOSE_OUTP(__VA_ARGS__, OUTPM, OUTPM, OUTPM, OUTPM, OUTPM, OUTPM, OUTPM, OUTPM, OUTPM, OUTPM, OUTPM, OUTPM, OUTPM, OUTPS)(__VA_ARGS__) 321 | #endif /* _MSC_VER */ 322 | 323 | #define OUTP_END *p4outp = EOS 324 | 325 | 326 | 327 | /* HTTP header -- resets respbuf! */ 328 | #define PRINT_HTTP_STATUS(val) (sprintf(G_tmp, "HTTP/1.1 %d %s\r\n", val, get_http_descr(val)), HOUT(G_tmp)) 329 | 330 | /* date */ 331 | #define PRINT_HTTP_DATE (sprintf(G_tmp, "Date: %s\r\n", M_resp_date), HOUT(G_tmp)) 332 | 333 | /* cache control */ 334 | #define PRINT_HTTP_CACHE_PUBLIC HOUT("Cache-Control: public, max-age=31536000\r\n") 335 | #define PRINT_HTTP_NO_CACHE HOUT("Cache-Control: private, must-revalidate, no-store, no-cache, max-age=0\r\n") 336 | #define PRINT_HTTP_EXPIRES_STATICS (sprintf(G_tmp, "Expires: %s\r\n", M_expires_stat), HOUT(G_tmp)) 337 | #define PRINT_HTTP_EXPIRES_GENERATED (sprintf(G_tmp, "Expires: %s\r\n", M_expires_gen), HOUT(G_tmp)) 338 | #define PRINT_HTTP_LAST_MODIFIED(str) (sprintf(G_tmp, "Last-Modified: %s\r\n", str), HOUT(G_tmp)) 339 | 340 | /* connection */ 341 | #define PRINT_HTTP_CONNECTION(ci) (sprintf(G_tmp, "Connection: %s\r\n", conn[ci].keep_alive?"keep-alive":"close"), HOUT(G_tmp)) 342 | 343 | /* vary */ 344 | #define PRINT_HTTP_VARY_DYN HOUT("Vary: Accept-Encoding, User-Agent\r\n") 345 | #define PRINT_HTTP_VARY_STAT HOUT("Vary: Accept-Encoding\r\n") 346 | #define PRINT_HTTP_VARY_UIR HOUT("Vary: Upgrade-Insecure-Requests\r\n") 347 | 348 | /* content language */ 349 | #define PRINT_HTTP_LANGUAGE HOUT("Content-Language: en-us\r\n") 350 | 351 | /* content length */ 352 | #define PRINT_HTTP_CONTENT_LEN(len) (sprintf(G_tmp, "Content-Length: %u\r\n", len), HOUT(G_tmp)) 353 | 354 | /* content encoding */ 355 | #define PRINT_HTTP_CONTENT_ENCODING_DEFLATE HOUT("Content-Encoding: deflate\r\n") 356 | 357 | /* Security ------------------------------------------------------------------ */ 358 | 359 | /* HSTS */ 360 | #ifndef HSTS_MAX_AGE 361 | #define HSTS_MAX_AGE 31536000 /* a year */ 362 | #endif 363 | #ifdef HSTS_INCLUDE_SUBDOMAINS 364 | #define PRINT_HTTP_HSTS (sprintf(G_tmp, "Strict-Transport-Security: max-age=%d; includeSubDomains\r\n", HSTS_MAX_AGE), HOUT(G_tmp)) 365 | #else 366 | #define PRINT_HTTP_HSTS (sprintf(G_tmp, "Strict-Transport-Security: max-age=%d\r\n", HSTS_MAX_AGE), HOUT(G_tmp)) 367 | #endif 368 | 369 | #ifdef HTTPS 370 | #ifndef NO_HSTS 371 | #if HSTS_MAX_AGE > 0 372 | #define HSTS_ON 373 | #endif 374 | #endif 375 | #endif 376 | 377 | /* cookie */ 378 | #ifdef HSTS_ON 379 | #define PRINT_HTTP_COOKIE_A(ci) (sprintf(G_tmp, "Set-Cookie: as=%s; %sHttpOnly\r\n", conn[ci].cookie_out_a, G_test?"":"Secure; "), HOUT(G_tmp)) 380 | #define PRINT_HTTP_COOKIE_L(ci) (sprintf(G_tmp, "Set-Cookie: ls=%s; %sHttpOnly\r\n", conn[ci].cookie_out_l, G_test?"":"Secure; "), HOUT(G_tmp)) 381 | #define PRINT_HTTP_COOKIE_A_EXP(ci) (sprintf(G_tmp, "Set-Cookie: as=%s; Expires=%s; %sHttpOnly\r\n", conn[ci].cookie_out_a, conn[ci].cookie_out_a_exp, G_test?"":"Secure; "), HOUT(G_tmp)) 382 | #define PRINT_HTTP_COOKIE_L_EXP(ci) (sprintf(G_tmp, "Set-Cookie: ls=%s; Expires=%s; %sHttpOnly\r\n", conn[ci].cookie_out_l, conn[ci].cookie_out_l_exp, G_test?"":"Secure; "), HOUT(G_tmp)) 383 | #else 384 | #define PRINT_HTTP_COOKIE_A(ci) (sprintf(G_tmp, "Set-Cookie: as=%s; HttpOnly\r\n", conn[ci].cookie_out_a), HOUT(G_tmp)) 385 | #define PRINT_HTTP_COOKIE_L(ci) (sprintf(G_tmp, "Set-Cookie: ls=%s; HttpOnly\r\n", conn[ci].cookie_out_l), HOUT(G_tmp)) 386 | #define PRINT_HTTP_COOKIE_A_EXP(ci) (sprintf(G_tmp, "Set-Cookie: as=%s; Expires=%s; HttpOnly\r\n", conn[ci].cookie_out_a, conn[ci].cookie_out_a_exp), HOUT(G_tmp)) 387 | #define PRINT_HTTP_COOKIE_L_EXP(ci) (sprintf(G_tmp, "Set-Cookie: ls=%s; Expires=%s; HttpOnly\r\n", conn[ci].cookie_out_l, conn[ci].cookie_out_l_exp), HOUT(G_tmp)) 388 | #endif 389 | 390 | /* framing */ 391 | #define PRINT_HTTP_SAMEORIGIN HOUT("X-Frame-Options: SAMEORIGIN\r\n") 392 | 393 | /* content type guessing */ 394 | #define PRINT_HTTP_NOSNIFF HOUT("X-Content-Type-Options: nosniff\r\n") 395 | 396 | /* identity */ 397 | #define PRINT_HTTP_SERVER HOUT("Server: Silgy\r\n") 398 | 399 | /* must be last! */ 400 | #define PRINT_HTTP_END_OF_HEADER HOUT("\r\n") 401 | 402 | 403 | #define OUT_HEADER_BUFSIZE 4096 /* response header buffer length */ 404 | 405 | 406 | #ifndef CUST_HDR_LEN 407 | #define CUST_HDR_LEN 255 408 | #endif 409 | 410 | #ifndef MAX_HOSTS /* M_hosts size */ 411 | #define MAX_HOSTS 10 412 | #endif 413 | 414 | #ifndef MAX_PAYLOAD_SIZE /* max incoming POST data length (16 MB) */ 415 | #define MAX_PAYLOAD_SIZE 16777216 416 | #endif 417 | 418 | #define MAX_LOG_STR_LEN 4095 /* max log string length */ 419 | #define MAX_METHOD_LEN 7 /* method length */ 420 | #define MAX_URI_LEN 2047 /* max request URI length */ 421 | #define MAX_LABEL_LEN 255 /* max request label length */ 422 | #define MAX_VALUE_LEN 255 /* max request value length */ 423 | #define MAX_RESOURCE_LEN 127 /* max resource's name length -- as a first part of URI */ 424 | #define MAX_RESOURCES 10000 /* for M_auth_levels */ 425 | 426 | /* mainly memory usage */ 427 | 428 | #ifdef MEM_TINY 429 | #define IN_BUFSIZE 4096 /* incoming request buffer length (4 kB) */ 430 | #define OUT_BUFSIZE 65536 /* initial HTTP response buffer length (64 kB) */ 431 | #define MAX_CONNECTIONS 10 /* max TCP connections */ 432 | #define MAX_SESSIONS 5 /* max user sessions */ 433 | #elif defined MEM_MEDIUM 434 | #define IN_BUFSIZE 8192 /* incoming request buffer length (8 kB) */ 435 | #define OUT_BUFSIZE 262144 /* initial HTTP response buffer length (256 kB) */ 436 | #define MAX_CONNECTIONS 200 /* max TCP connections (2 per user session) */ 437 | #define MAX_SESSIONS 100 /* max user sessions */ 438 | #elif defined MEM_LARGE 439 | #define IN_BUFSIZE 8192 /* incoming request buffer length (8 kB) */ 440 | #define OUT_BUFSIZE 262144 /* initial HTTP response buffer length (256 kB) */ 441 | #define MAX_CONNECTIONS 1000 /* max TCP connections */ 442 | #define MAX_SESSIONS 500 /* max user sessions */ 443 | #elif defined MEM_XLARGE 444 | #define IN_BUFSIZE 8192 /* incoming request buffer length (8 kB) */ 445 | #define OUT_BUFSIZE 262144 /* initial HTTP response buffer length (256 kB) */ 446 | #define MAX_CONNECTIONS 5000 /* max TCP connections */ 447 | #define MAX_SESSIONS 2500 /* max user sessions */ 448 | #elif defined MEM_XXLARGE 449 | #define IN_BUFSIZE 8192 /* incoming request buffer length (8 kB) */ 450 | #define OUT_BUFSIZE 262144 /* initial HTTP response buffer length (256 kB) */ 451 | #define MAX_CONNECTIONS 10000 /* max TCP connections */ 452 | #define MAX_SESSIONS 5000 /* max user sessions */ 453 | #elif defined MEM_XXXLARGE 454 | #define IN_BUFSIZE 8192 /* incoming request buffer length (8 kB) */ 455 | #define OUT_BUFSIZE 262144 /* initial HTTP response buffer length (256 kB) */ 456 | #define MAX_CONNECTIONS 20000 /* max TCP connections */ 457 | #define MAX_SESSIONS 10000 /* max user sessions */ 458 | #elif defined MEM_XXXXLARGE 459 | #define IN_BUFSIZE 8192 /* incoming request buffer length (8 kB) */ 460 | #define OUT_BUFSIZE 262144 /* initial HTTP response buffer length (256 kB) */ 461 | #define MAX_CONNECTIONS 50000 /* max TCP connections */ 462 | #define MAX_SESSIONS 25000 /* max user sessions */ 463 | #else /* MEM_SMALL -- default */ 464 | #define IN_BUFSIZE 8192 /* incoming request buffer length (8 kB) */ 465 | #define OUT_BUFSIZE 131072 /* initial HTTP response buffer length (128 kB) */ 466 | #define MAX_CONNECTIONS 20 /* max TCP connections */ 467 | #define MAX_SESSIONS 10 /* max user sessions */ 468 | #endif 469 | 470 | #ifndef TMP_BUFSIZE /* temporary string buffer size */ 471 | #define TMP_BUFSIZE OUT_BUFSIZE 472 | #endif 473 | 474 | #ifdef SILGY_SVC 475 | #undef MAX_CONNECTIONS 476 | #define MAX_CONNECTIONS 1 /* conn, uses & auses still as arrays to keep the same macros */ 477 | #undef MAX_SESSIONS 478 | #define MAX_SESSIONS 1 479 | #endif /* SILGY_SVC */ 480 | 481 | #ifdef FD_MON_SELECT 482 | #if MAX_CONNECTIONS > FD_SETSIZE-2 483 | #undef MAX_CONNECTIONS 484 | #define MAX_CONNECTIONS FD_SETSIZE-2 485 | #endif 486 | #endif /* FD_MON_SELECT */ 487 | 488 | #define CLOSING_SESSION_CI MAX_CONNECTIONS 489 | 490 | #ifndef CONN_TIMEOUT 491 | #define CONN_TIMEOUT 180 /* idle connection timeout in seconds */ 492 | #endif 493 | 494 | #ifndef USES_TIMEOUT 495 | #define USES_TIMEOUT 600 /* anonymous user session timeout in seconds */ 496 | #endif 497 | 498 | #define NOT_CONNECTED -1 499 | 500 | #define CONN_STATE_DISCONNECTED '0' 501 | #define CONN_STATE_ACCEPTING 'a' 502 | #define CONN_STATE_CONNECTED '1' 503 | #define CONN_STATE_READY_FOR_PARSE 'p' 504 | #define CONN_STATE_READY_FOR_PROCESS 'P' 505 | #define CONN_STATE_READING_DATA 'd' 506 | #define CONN_STATE_WAITING_FOR_ASYNC 'A' 507 | #define CONN_STATE_READY_TO_SEND_HEADER 'H' 508 | #define CONN_STATE_READY_TO_SEND_BODY 'B' 509 | #define CONN_STATE_SENDING_BODY 'S' 510 | 511 | #ifdef __linux__ 512 | #define MONOTONIC_CLOCK_NAME CLOCK_MONOTONIC_RAW 513 | #else 514 | #define MONOTONIC_CLOCK_NAME CLOCK_MONOTONIC 515 | #endif 516 | 517 | #define STR(str) lib_get_string(ci, str) 518 | 519 | #ifndef MAX_BLACKLIST 520 | #define MAX_BLACKLIST 10000 521 | #endif 522 | #ifndef MAX_WHITELIST 523 | #define MAX_WHITELIST 10000 524 | #endif 525 | 526 | #ifndef APP_WEBSITE 527 | #define APP_WEBSITE "Silgy Web Application" 528 | #endif 529 | #ifndef APP_DOMAIN 530 | #define APP_DOMAIN "" 531 | #endif 532 | #ifndef APP_VERSION 533 | #define APP_VERSION "1.0" 534 | #endif 535 | #ifndef APP_LOGIN_URI 536 | #define APP_LOGIN_URI "/login" 537 | #endif 538 | 539 | 540 | /* compression settings */ 541 | 542 | #ifndef COMPRESS_TRESHOLD 543 | #define COMPRESS_TRESHOLD 500 544 | #endif 545 | 546 | #ifndef COMPRESS_LEVEL 547 | #define COMPRESS_LEVEL Z_BEST_SPEED 548 | #endif 549 | 550 | #define SHOULD_BE_COMPRESSED(len, type) (len > COMPRESS_TRESHOLD && (type==RES_HTML || type==RES_TEXT || type==RES_JSON || type==RES_CSS || type==RES_JS || type==RES_SVG || type==RES_EXE || type==RES_BMP)) 551 | 552 | 553 | #ifdef APP_SESID_LEN 554 | #define SESID_LEN APP_SESID_LEN 555 | #else 556 | #define SESID_LEN 15 /* ~ 89 bits of entropy */ 557 | #endif 558 | 559 | #ifndef CSRFT_LEN 560 | #define CSRFT_LEN 7 561 | #endif 562 | 563 | #define LANG_LEN 5 564 | 565 | 566 | /* response caching */ 567 | 568 | #ifndef EXPIRES_STATICS 569 | #define EXPIRES_STATICS 90 /* days */ 570 | #endif 571 | 572 | #ifndef EXPIRES_GENERATED 573 | #define EXPIRES_GENERATED 30 /* days */ 574 | #endif 575 | 576 | 577 | /* authorization levels */ 578 | 579 | #define AUTH_LEVEL_NONE 0 /* no session */ 580 | #define AUTH_LEVEL_ANONYMOUS 1 /* anonymous session */ 581 | #define AUTH_LEVEL_LOGGED 2 /* logged in session with lowest authorization level */ 582 | #define AUTH_LEVEL_LOGGEDIN 2 583 | #define AUTH_LEVEL_USER 10 584 | #define AUTH_LEVEL_CUSTOMER 20 585 | #define AUTH_LEVEL_STAFF 30 586 | #define AUTH_LEVEL_MODERATOR 40 587 | #define AUTH_LEVEL_ADMIN 50 588 | #define AUTH_LEVEL_ROOT 100 589 | #define AUTH_LEVEL_NOBODY 125 /* for resources' whitelisting */ 590 | 591 | #ifndef DEF_RES_AUTH_LEVEL 592 | #define DEF_RES_AUTH_LEVEL AUTH_LEVEL_NONE /* default resource authorization level */ 593 | #endif 594 | 595 | 596 | /* errors */ 597 | 598 | /* 0 always means OK */ 599 | #define ERR_INVALID_REQUEST 1 600 | #define ERR_UNAUTHORIZED 2 601 | #define ERR_FORBIDDEN 3 602 | #define ERR_NOT_FOUND 4 603 | #define ERR_METHOD 5 604 | #define ERR_INT_SERVER_ERROR 6 605 | #define ERR_SERVER_TOOBUSY 7 606 | #define ERR_FILE_TOO_BIG 8 607 | #define ERR_REDIRECTION 9 608 | #define ERR_ASYNC_NO_SUCH_SERVICE 10 609 | #define ERR_ASYNC_TIMEOUT 11 610 | #define ERR_REMOTE_CALL 12 611 | #define ERR_REMOTE_CALL_STATUS 13 612 | #define ERR_REMOTE_CALL_DATA 14 613 | #define ERR_CSRFT 15 614 | #define ERR_RECORD_NOT_FOUND 16 615 | /* ------------------------------------- */ 616 | #define ERR_MAX_ENGINE_ERROR 99 617 | /* ------------------------------------- */ 618 | 619 | 620 | #define MSG_CAT_OK "OK" 621 | #define MSG_CAT_ERROR "err" 622 | #define MSG_CAT_WARNING "war" 623 | #define MSG_CAT_MESSAGE "msg" 624 | 625 | 626 | /* statics */ 627 | 628 | #define NOT_STATIC -1 629 | #ifdef APP_MAX_STATICS /* max static resources */ 630 | #define MAX_STATICS APP_MAX_STATICS 631 | #else 632 | #define MAX_STATICS 1000 633 | #endif 634 | 635 | #define STATIC_PATH_LEN 1024 636 | 637 | #define STATIC_SOURCE_INTERNAL 0 638 | #define STATIC_SOURCE_RES 1 639 | #define STATIC_SOURCE_RESMIN 2 640 | #define STATIC_SOURCE_SNIPPET 3 641 | 642 | #ifndef MAX_SNIPPETS 643 | #define MAX_SNIPPETS 1000 644 | #endif 645 | 646 | 647 | /* asynchronous calls */ 648 | 649 | #define ASYNC_STATE_FREE '0' 650 | #define ASYNC_STATE_SENT '1' 651 | #define ASYNC_STATE_RECEIVED '2' 652 | #define ASYNC_STATE_TIMEOUTED '3' 653 | 654 | 655 | #ifndef ASYNC_MQ_MAXMSG 656 | #define ASYNC_MQ_MAXMSG 10 /* max messages in a message queue */ 657 | #endif 658 | 659 | #ifndef MAX_ASYNC_REQS 660 | #define MAX_ASYNC_REQS MAX_SESSIONS /* max simultaneous async requests */ 661 | #endif 662 | 663 | #ifndef ASYNC_REQ_MSG_SIZE 664 | #define ASYNC_REQ_MSG_SIZE 16384 /* request message size */ 665 | #endif 666 | 667 | #ifndef ASYNC_RES_MSG_SIZE 668 | #define ASYNC_RES_MSG_SIZE 16384 /* response message size */ 669 | #endif 670 | 671 | #define ASYNC_REQ_QUEUE "/silgy_req" /* request queue name */ 672 | #define ASYNC_RES_QUEUE "/silgy_res" /* response queue name */ 673 | #define ASYNC_DEF_TIMEOUT 60 /* in seconds */ 674 | #define ASYNC_MAX_TIMEOUT 1800 /* in seconds ==> 30 minutes */ 675 | 676 | #define ASYNC_PAYLOAD_MSG 0 677 | #define ASYNC_PAYLOAD_SHM 1 678 | 679 | #define ASYNC_SHM_SIZE MAX_PAYLOAD_SIZE 680 | 681 | /* these are flags */ 682 | #define ASYNC_CHUNK_FIRST 0x040000 683 | #define ASYNC_CHUNK_LAST 0x080000 684 | #define ASYNC_CHUNK_IS_FIRST(n) ((n & ASYNC_CHUNK_FIRST) == ASYNC_CHUNK_FIRST) 685 | #define ASYNC_CHUNK_IS_LAST(n) ((n & ASYNC_CHUNK_LAST) == ASYNC_CHUNK_LAST) 686 | 687 | #ifdef SILGY_SVC 688 | #define SVC(svc) (0==strcmp(G_service, svc)) 689 | #define ASYNC_ERR_CODE G_error_code 690 | #else 691 | #define SVC(svc) (0==strcmp(conn[ci].service, svc)) 692 | #define ASYNC_ERR_CODE conn[ci].async_err_code 693 | #endif /* SILGY_SVC */ 694 | 695 | #ifdef ASYNC_USE_APP_CONTINUE /* the old way (temporarily) */ 696 | #define CALL_ASYNC(svc, data) eng_async_req(ci, svc, data, TRUE, G_ASYNCDefTimeout, 0) 697 | #define CALL_ASYNC_TM(svc, data, tmout) eng_async_req(ci, svc, data, TRUE, tmout, 0) 698 | #define CALL_ASYNC_NR(svc, data) eng_async_req(ci, svc, data, FALSE, 0, 0) 699 | #else 700 | #define CALL_ASYNC(svc) eng_async_req(ci, svc, NULL, TRUE, G_ASYNCDefTimeout, 0) 701 | #define CALL_ASYNC_TM(svc, tmout) eng_async_req(ci, svc, NULL, TRUE, tmout, 0) 702 | #define CALL_ASYNC_NR(svc) eng_async_req(ci, svc, NULL, FALSE, 0, 0) 703 | #endif /* ASYNC_USE_APP_CONTINUE */ 704 | 705 | #define CALL_ASYNC_BIN(svc, data, size) eng_async_req(ci, svc, data, TRUE, G_ASYNCDefTimeout, size) 706 | 707 | 708 | /* resource / content types */ 709 | 710 | /* incoming */ 711 | 712 | #define CONTENT_TYPE_URLENCODED 'U' 713 | #define CONTENT_TYPE_JSON 'J' 714 | #define CONTENT_TYPE_MULTIPART 'M' 715 | #define CONTENT_TYPE_OCTET_STREAM 'O' 716 | 717 | /* outgoing */ 718 | 719 | #define CONTENT_TYPE_UNSET '-' 720 | #define CONTENT_TYPE_USER '+' 721 | #define RES_TEXT 'T' 722 | #define RES_HTML 'H' 723 | #define RES_CSS 'C' 724 | #define RES_JS 'S' 725 | #define RES_GIF 'G' 726 | #define RES_JPG 'J' 727 | #define RES_ICO 'I' 728 | #define RES_PNG 'P' 729 | #define RES_BMP 'B' 730 | #define RES_SVG 'V' 731 | #define RES_JSON 'O' 732 | #define RES_PDF 'A' 733 | #define RES_AMPEG 'M' 734 | #define RES_EXE 'X' 735 | #define RES_ZIP 'Z' 736 | 737 | 738 | #define URI(uri) eng_is_uri(ci, uri) 739 | #define REQ(res) (0==strcmp(conn[ci].resource, res)) 740 | #define REQ0(res) (0==strcmp(conn[ci].resource, res)) 741 | #define REQ1(res) (0==strcmp(conn[ci].req1, res)) 742 | #define REQ2(res) (0==strcmp(conn[ci].req2, res)) 743 | #define REQ3(res) (0==strcmp(conn[ci].req3, res)) 744 | #define ID conn[ci].id 745 | #define US uses[conn[ci].usi] 746 | #define AUS auses[conn[ci].usi] 747 | #define HOST(str) (0==strcmp(conn[ci].host_normalized, upper(str))) 748 | #define REQ_GET_HEADER(header) eng_get_header(ci, header) 749 | 750 | #define REQ_DATA conn[ci].in_data 751 | 752 | #define REST_HEADER_PASS(header) eng_rest_header_pass(ci, header) 753 | 754 | 755 | /* response macros */ 756 | 757 | #define RES_STATUS(val) lib_set_res_status(ci, val) 758 | #define RES_CONTENT_TYPE(str) lib_set_res_content_type(ci, str) 759 | #define RES_LOCATION(str, ...) lib_set_res_location(ci, str, ##__VA_ARGS__) 760 | #define RES_REDIRECT(str, ...) RES_LOCATION(str, ##__VA_ARGS__) 761 | #define RES_DONT_CACHE conn[ci].dont_cache=TRUE 762 | #define RES_KEEP_CONTENT conn[ci].keep_content=TRUE 763 | #define RES_CONTENT_DISPOSITION(str, ...) lib_set_res_content_disposition(ci, str, ##__VA_ARGS__) 764 | 765 | #define REDIRECT_TO_LANDING sprintf(conn[ci].location, "%s://%s", PROTOCOL, conn[ci].host) 766 | 767 | #define APPEND_CSS(name, first) lib_append_css(ci, name, first) 768 | #define APPEND_SCRIPT(name, first) lib_append_script(ci, name, first) 769 | 770 | 771 | 772 | #define SVC_NAME_LEN 63 /* async service name length */ 773 | 774 | 775 | //#define UA_IE (0==strcmp(conn[ci].uagent, "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko") || 0==strcmp(conn[ci].uagent, "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko")) 776 | #define UA_IE (0==strncmp(conn[ci].uagent, "Mozilla/5.0 (Windows NT ", 24) && strstr(conn[ci].uagent, "; WOW64; Trident/7.0; rv:11.0) like Gecko")) 777 | 778 | 779 | /* Date-Time */ 780 | 781 | //#define DT_NULL "2000-01-01 00:00:00" 782 | #define DT_NULL "0000-00-00 00:00:00" 783 | #define DT_NOW G_dt 784 | #define DT_TODAY silgy_today() 785 | #define DT_NOW_LOCAL time_epoch2db(silgy_ua_time(ci)) 786 | #define DT_TODAY_LOCAL silgy_ua_today(ci) 787 | #define DT_IS_NULL(dt) (0==strcmp(dt, DT_NULL)) 788 | 789 | 790 | 791 | /* HTTP status */ 792 | 793 | typedef struct { 794 | int status; 795 | char description[128]; 796 | } http_status_t; 797 | 798 | 799 | /* date */ 800 | 801 | typedef struct { 802 | short year; 803 | char month; 804 | char day; 805 | } date_t; 806 | 807 | 808 | /* user session */ 809 | 810 | typedef struct { 811 | /* id */ 812 | char sesid[SESID_LEN+1]; 813 | /* connection data */ 814 | char ip[INET_ADDRSTRLEN]; 815 | char uagent[MAX_VALUE_LEN+1]; 816 | char referer[MAX_VALUE_LEN+1]; 817 | char lang[LANG_LEN+1]; 818 | bool logged; 819 | /* users table record */ 820 | int uid; 821 | char login[LOGIN_LEN+1]; 822 | char email[EMAIL_LEN+1]; 823 | char name[UNAME_LEN+1]; 824 | char phone[PHONE_LEN+1]; 825 | char about[ABOUT_LEN+1]; 826 | int group_id; 827 | char auth_level; 828 | /* time zone info */ 829 | short tz_offset; 830 | bool tz_set; 831 | /* CSRF token */ 832 | char csrft[CSRFT_LEN+1]; 833 | /* internal */ 834 | time_t last_activity; 835 | } usession_t; 836 | 837 | 838 | #define CUSTOMER (US.auth_level==AUTH_LEVEL_CUSTOMER) 839 | #define STAFF (US.auth_level==AUTH_LEVEL_STAFF) 840 | #define MODERATOR (US.auth_level==AUTH_LEVEL_MODERATOR) 841 | #define ADMIN (US.auth_level==AUTH_LEVEL_ADMIN) 842 | #define ROOT (US.auth_level==AUTH_LEVEL_ROOT) 843 | 844 | #define LOGGED US.logged 845 | #define UID US.uid 846 | 847 | 848 | #define CSRFT_REFRESH silgy_random(US.csrft, CSRFT_LEN) 849 | #define CSRFT_OUT_INPUT OUT("", US.csrft) 850 | #define OUT_CSRFT CSRFT_OUT_INPUT 851 | #define CSRFT_OK lib_csrft_ok(ci) 852 | 853 | 854 | 855 | /* counters */ 856 | 857 | typedef struct { 858 | unsigned req; /* all parsed requests */ 859 | unsigned req_dsk; /* all requests with desktop UA */ 860 | unsigned req_mob; /* all requests with mobile UA */ 861 | unsigned req_bot; /* all requests with HTTP header indicating well-known search-engine bots */ 862 | unsigned visits; /* all visits to domain (Host=APP_DOMAIN) landing page (no action/resource), excl. bots that got 200 */ 863 | unsigned visits_dsk; /* like visits -- desktop only */ 864 | unsigned visits_mob; /* like visits -- mobile only */ 865 | unsigned blocked; /* attempts from blocked IP */ 866 | double elapsed; /* sum of elapsed time of all requests for calculating average */ 867 | double average; /* average request elapsed */ 868 | } counters_t; 869 | 870 | 871 | /* asynchorous processing */ 872 | 873 | /* request */ 874 | 875 | typedef struct { 876 | unsigned call_id; 877 | int ai; 878 | int ci; 879 | char service[SVC_NAME_LEN+1]; 880 | /* pass some request details over */ 881 | bool secure; 882 | char ip[INET_ADDRSTRLEN]; 883 | char method[MAX_METHOD_LEN+1]; 884 | bool post; 885 | char payload_location; 886 | char uri[MAX_URI_LEN+1]; 887 | char resource[MAX_RESOURCE_LEN+1]; 888 | char req1[MAX_RESOURCE_LEN+1]; 889 | char req2[MAX_RESOURCE_LEN+1]; 890 | char req3[MAX_RESOURCE_LEN+1]; 891 | char id[MAX_RESOURCE_LEN+1]; 892 | char uagent[MAX_VALUE_LEN+1]; 893 | bool mobile; 894 | char referer[MAX_VALUE_LEN+1]; 895 | unsigned clen; 896 | char in_cookie[MAX_VALUE_LEN+1]; 897 | char host[MAX_VALUE_LEN+1]; 898 | char website[WEBSITE_LEN+1]; 899 | char lang[LANG_LEN+1]; 900 | char in_ctype; 901 | char boundary[MAX_VALUE_LEN+1]; 902 | char response; 903 | int status; 904 | char cust_headers[CUST_HDR_LEN+1]; 905 | int cust_headers_len; 906 | char ctype; 907 | char ctypestr[CONTENT_TYPE_LEN+1]; 908 | char cdisp[CONTENT_DISP_LEN+1]; 909 | char cookie_out_a[SESID_LEN+1]; 910 | char cookie_out_a_exp[32]; 911 | char cookie_out_l[SESID_LEN+1]; 912 | char cookie_out_l_exp[32]; 913 | char location[MAX_URI_LEN+1]; 914 | int usi; 915 | bool bot; 916 | bool dont_cache; 917 | bool keep_content; 918 | usession_t uses; 919 | #ifndef ASYNC_EXCLUDE_AUSES 920 | ausession_t auses; 921 | #endif 922 | counters_t cnts_today; 923 | counters_t cnts_yesterday; 924 | counters_t cnts_day_before; 925 | int days_up; 926 | int open_conn; 927 | int open_conn_hwm; 928 | int sessions; 929 | int sessions_hwm; 930 | char last_modified[32]; 931 | int blacklist_cnt; 932 | } async_req_hdr_t; 933 | 934 | typedef struct { 935 | async_req_hdr_t hdr; 936 | char data[ASYNC_REQ_MSG_SIZE-sizeof(async_req_hdr_t)]; 937 | } async_req_t; 938 | 939 | 940 | /* async requests stored on the silgy_app's side */ 941 | 942 | typedef struct { 943 | int ci; 944 | char state; 945 | time_t sent; 946 | int timeout; 947 | } areq_t; 948 | 949 | 950 | /* response -- the first chunk */ 951 | 952 | typedef struct { 953 | int err_code; 954 | int status; 955 | char cust_headers[CUST_HDR_LEN+1]; 956 | int cust_headers_len; 957 | char ctype; 958 | char ctypestr[CONTENT_TYPE_LEN+1]; 959 | char cdisp[CONTENT_DISP_LEN+1]; 960 | char cookie_out_a[SESID_LEN+1]; 961 | char cookie_out_a_exp[32]; 962 | char cookie_out_l[SESID_LEN+1]; 963 | char cookie_out_l_exp[32]; 964 | char location[MAX_URI_LEN+1]; 965 | bool dont_cache; 966 | bool keep_content; 967 | int rest_status; 968 | unsigned rest_req; 969 | double rest_elapsed; 970 | usession_t uses; 971 | #ifndef ASYNC_EXCLUDE_AUSES 972 | ausession_t auses; 973 | #endif 974 | int invalidate_uid; 975 | int invalidate_ci; 976 | } async_res_hdr_t; 977 | 978 | typedef struct { 979 | int ai; 980 | int chunk; 981 | int ci; 982 | int len; 983 | async_res_hdr_t hdr; 984 | char data[ASYNC_RES_MSG_SIZE-sizeof(async_res_hdr_t)-sizeof(int)*4]; 985 | } async_res_t; 986 | 987 | 988 | /* response -- the second type for the chunks > 1 */ 989 | 990 | typedef struct { 991 | int ai; 992 | int chunk; 993 | int ci; 994 | int len; 995 | char data[ASYNC_RES_MSG_SIZE-sizeof(int)*4]; 996 | } async_res_data_t; 997 | 998 | 999 | 1000 | /* connection */ 1001 | 1002 | #ifdef SILGY_SVC 1003 | typedef struct { /* request details for silgy_svc */ 1004 | bool secure; 1005 | char ip[INET_ADDRSTRLEN]; 1006 | char method[MAX_METHOD_LEN+1]; 1007 | bool post; 1008 | char uri[MAX_URI_LEN+1]; 1009 | char resource[MAX_RESOURCE_LEN+1]; 1010 | char req1[MAX_RESOURCE_LEN+1]; 1011 | char req2[MAX_RESOURCE_LEN+1]; 1012 | char req3[MAX_RESOURCE_LEN+1]; 1013 | char id[MAX_RESOURCE_LEN+1]; 1014 | char uagent[MAX_VALUE_LEN+1]; 1015 | bool mobile; 1016 | char referer[MAX_VALUE_LEN+1]; 1017 | unsigned clen; 1018 | char in_cookie[MAX_VALUE_LEN+1]; 1019 | unsigned in_data_allocated; 1020 | char host[MAX_VALUE_LEN+1]; 1021 | char website[WEBSITE_LEN+1]; 1022 | char lang[LANG_LEN+1]; 1023 | char in_ctype; 1024 | char boundary[MAX_VALUE_LEN+1]; 1025 | char *in_data; 1026 | int status; 1027 | char cust_headers[CUST_HDR_LEN+1]; 1028 | int cust_headers_len; 1029 | char ctype; 1030 | char ctypestr[CONTENT_TYPE_LEN+1]; 1031 | char cdisp[CONTENT_DISP_LEN+1]; 1032 | char cookie_out_a[SESID_LEN+1]; 1033 | char cookie_out_a_exp[32]; 1034 | char cookie_out_l[SESID_LEN+1]; 1035 | char cookie_out_l_exp[32]; 1036 | char location[MAX_URI_LEN+1]; 1037 | int usi; 1038 | bool bot; 1039 | bool dont_cache; 1040 | bool keep_content; 1041 | } conn_t; 1042 | #else /* SILGY_APP */ 1043 | typedef struct { 1044 | /* what comes in */ 1045 | #ifdef _WIN32 /* Windows */ 1046 | SOCKET fd; /* file descriptor */ 1047 | #else 1048 | int fd; /* file descriptor */ 1049 | #endif /* _WIN32 */ 1050 | bool secure; /* https? */ 1051 | char ip[INET_ADDRSTRLEN]; /* client IP */ 1052 | char pip[INET_ADDRSTRLEN]; /* proxy IP */ 1053 | char in[IN_BUFSIZE]; /* the whole incoming request */ 1054 | char method[MAX_METHOD_LEN+1]; /* HTTP method */ 1055 | unsigned was_read; /* request bytes read so far */ 1056 | bool upgrade2https; /* Upgrade-Insecure-Requests = 1 */ 1057 | /* parsed HTTP request starts here */ 1058 | bool head_only; /* request method = HEAD */ 1059 | bool post; /* request method = POST */ 1060 | char uri[MAX_URI_LEN+1]; /* requested URI string */ 1061 | char resource[MAX_RESOURCE_LEN+1]; /* from URI (REQ0) */ 1062 | char req1[MAX_RESOURCE_LEN+1]; /* from URI -- level 1 */ 1063 | char req2[MAX_RESOURCE_LEN+1]; /* from URI -- level 2 */ 1064 | char req3[MAX_RESOURCE_LEN+1]; /* from URI -- level 3 */ 1065 | char id[MAX_RESOURCE_LEN+1]; /* from URI -- last part */ 1066 | char proto[16]; /* HTTP request version */ 1067 | char uagent[MAX_VALUE_LEN+1]; /* user agent string */ 1068 | bool mobile; 1069 | bool keep_alive; 1070 | char referer[MAX_VALUE_LEN+1]; 1071 | unsigned clen; /* incoming & outgoing content length */ 1072 | char in_cookie[MAX_VALUE_LEN+1]; 1073 | char cookie_in_a[SESID_LEN+1]; /* anonymous */ 1074 | char cookie_in_l[SESID_LEN+1]; /* logged in */ 1075 | char host[MAX_VALUE_LEN+1]; 1076 | char host_normalized[MAX_VALUE_LEN+1]; 1077 | char website[WEBSITE_LEN+1]; 1078 | char lang[LANG_LEN+1]; 1079 | time_t if_mod_since; 1080 | char in_ctypestr[MAX_VALUE_LEN+1]; /* content type as an original string */ 1081 | char in_ctype; /* content type */ 1082 | char boundary[MAX_VALUE_LEN+1]; /* for POST multipart/form-data type */ 1083 | char authorization[MAX_VALUE_LEN+1]; /* Authorization */ 1084 | bool accept_deflate; 1085 | int host_id; 1086 | /* POST data */ 1087 | char *in_data; /* POST data */ 1088 | /* what goes out */ 1089 | unsigned out_hlen; /* outgoing header length */ 1090 | unsigned out_len; /* outgoing length (all) */ 1091 | char *out_start; 1092 | #ifdef OUTCHECKREALLOC 1093 | char *out_data_alloc; /* allocated space for rendered content */ 1094 | #else 1095 | char out_data_alloc[OUT_BUFSIZE]; 1096 | #endif 1097 | unsigned out_data_allocated; /* number of allocated bytes */ 1098 | char *out_data; /* pointer to the data to send */ 1099 | int status; /* HTTP status */ 1100 | char cust_headers[CUST_HDR_LEN+1]; 1101 | int cust_headers_len; 1102 | unsigned data_sent; /* how many content bytes have been sent */ 1103 | char ctype; /* content type */ 1104 | char ctypestr[CONTENT_TYPE_LEN+1]; /* user (custom) content type */ 1105 | char cdisp[CONTENT_DISP_LEN+1]; /* content disposition */ 1106 | time_t modified; 1107 | char cookie_out_a[SESID_LEN+1]; 1108 | char cookie_out_a_exp[32]; /* cookie expires */ 1109 | char cookie_out_l[SESID_LEN+1]; 1110 | char cookie_out_l_exp[32]; /* cookie expires */ 1111 | char location[MAX_URI_LEN+1]; /* redirection */ 1112 | /* internal stuff */ 1113 | unsigned req; /* request count */ 1114 | struct timespec proc_start; /* start processing time */ 1115 | double elapsed; /* processing time in ms */ 1116 | char conn_state; /* connection state (STATE_XXX) */ 1117 | char *p_header; /* current header pointer */ 1118 | char *p_content; /* current content pointer */ 1119 | #ifdef HTTPS 1120 | SSL *ssl; 1121 | #endif 1122 | int ssl_err; 1123 | char required_auth_level; /* required authorization level */ 1124 | int usi; /* user session index */ 1125 | int static_res; /* static resource index in M_stat */ 1126 | time_t last_activity; 1127 | bool bot; 1128 | bool expect100; 1129 | bool dont_cache; 1130 | bool keep_content; /* don't reset already rendered content on error */ 1131 | #ifdef FD_MON_POLL 1132 | int pi; /* pollfds array index */ 1133 | #endif 1134 | #ifdef ASYNC 1135 | char service[SVC_NAME_LEN+1]; 1136 | int async_err_code; 1137 | // int ai; /* async responses array index */ 1138 | #endif 1139 | } conn_t; 1140 | #endif /* SILGY_SVC */ 1141 | 1142 | 1143 | /* static resources */ 1144 | 1145 | typedef struct { 1146 | char host[MAX_VALUE_LEN+1]; 1147 | char name[STATIC_PATH_LEN]; 1148 | char type; 1149 | char *data; 1150 | unsigned len; 1151 | char *data_deflated; 1152 | unsigned len_deflated; 1153 | time_t modified; 1154 | char source; 1155 | } stat_res_t; 1156 | 1157 | 1158 | /* admin info */ 1159 | 1160 | typedef struct { 1161 | char sql[1024]; 1162 | char th[256]; 1163 | char type[32]; 1164 | } admin_info_t; 1165 | 1166 | 1167 | /* counters formatted */ 1168 | 1169 | typedef struct { 1170 | char req[64]; 1171 | char req_dsk[64]; 1172 | char req_mob[64]; 1173 | char req_bot[64]; 1174 | char visits[64]; 1175 | char visits_dsk[64]; 1176 | char visits_mob[64]; 1177 | char blocked[64]; 1178 | char average[64]; 1179 | } counters_fmt_t; 1180 | 1181 | 1182 | 1183 | #include 1184 | 1185 | #ifdef USERS 1186 | #include 1187 | #endif 1188 | 1189 | 1190 | 1191 | #ifdef __cplusplus 1192 | extern "C" { 1193 | #endif 1194 | 1195 | /* read from the config file */ 1196 | 1197 | extern int G_logLevel; 1198 | extern int G_logToStdout; 1199 | extern int G_logCombined; 1200 | extern int G_httpPort; 1201 | extern int G_httpsPort; 1202 | extern char G_cipherList[1024]; 1203 | extern char G_certFile[256]; 1204 | extern char G_certChainFile[256]; 1205 | extern char G_keyFile[256]; 1206 | extern char G_dbHost[128]; 1207 | extern int G_dbPort; 1208 | extern char G_dbName[128]; 1209 | extern char G_dbUser[128]; 1210 | extern char G_dbPassword[128]; 1211 | extern int G_usersRequireAccountActivation; 1212 | extern char G_blockedIPList[256]; 1213 | extern char G_whiteList[256]; 1214 | extern int G_ASYNCId; 1215 | extern int G_ASYNCDefTimeout; 1216 | extern int G_RESTTimeout; 1217 | extern int G_test; 1218 | 1219 | /* end of config params */ 1220 | 1221 | extern int G_pid; /* pid */ 1222 | extern char G_appdir[256]; /* application root dir */ 1223 | extern int G_days_up; /* web server's days up */ 1224 | extern conn_t conn[MAX_CONNECTIONS+1]; /* HTTP connections & requests -- by far the most important structure around */ 1225 | extern int G_open_conn; /* number of open connections */ 1226 | extern int G_open_conn_hwm; /* highest number of open connections (high water mark) */ 1227 | extern char G_tmp[TMP_BUFSIZE]; /* temporary string buffer */ 1228 | extern usession_t uses[MAX_SESSIONS+1]; /* engine user sessions -- they start from 1 */ 1229 | extern ausession_t auses[MAX_SESSIONS+1]; /* app user sessions, using the same index (usi) */ 1230 | extern int G_sessions; /* number of active user sessions */ 1231 | extern int G_sessions_hwm; /* highest number of active user sessions (high water mark) */ 1232 | extern time_t G_now; /* current time */ 1233 | extern struct tm *G_ptm; /* human readable current time */ 1234 | extern char G_last_modified[32]; /* response header field with server's start time */ 1235 | extern bool G_initialized; 1236 | 1237 | /* messages */ 1238 | extern message_t G_messages[MAX_MESSAGES]; 1239 | extern int G_next_msg; 1240 | extern lang_t G_msg_lang[MAX_LANGUAGES]; 1241 | extern int G_next_msg_lang; 1242 | 1243 | /* strings */ 1244 | extern string_t G_strings[MAX_STRINGS]; 1245 | extern int G_next_str; 1246 | extern lang_t G_str_lang[MAX_LANGUAGES]; 1247 | extern int G_next_str_lang; 1248 | 1249 | /* snippets */ 1250 | extern stat_res_t G_snippets[MAX_SNIPPETS]; 1251 | extern int G_snippets_cnt; 1252 | 1253 | #ifdef HTTPS 1254 | extern bool G_ssl_lib_initialized; 1255 | #endif 1256 | 1257 | #ifdef DBMYSQL 1258 | extern MYSQL *G_dbconn; /* database connection */ 1259 | #endif 1260 | 1261 | /* asynchorous processing */ 1262 | #ifndef _WIN32 1263 | extern char G_req_queue_name[256]; 1264 | extern char G_res_queue_name[256]; 1265 | extern mqd_t G_queue_req; /* request queue */ 1266 | extern mqd_t G_queue_res; /* response queue */ 1267 | #endif /* _WIN32 */ 1268 | extern int G_async_req_data_size; /* how many bytes are left for data */ 1269 | extern int G_async_res_data_size; /* how many bytes are left for data */ 1270 | 1271 | extern char G_dt[20]; /* datetime for database or log (YYYY-MM-DD hh:mm:ss) */ 1272 | extern bool G_index_present; /* index.html present in res? */ 1273 | 1274 | #ifdef SILGY_SVC 1275 | extern async_req_t req; 1276 | extern async_res_t res; 1277 | #ifdef OUTCHECKREALLOC 1278 | extern char *out_data; 1279 | #endif 1280 | extern char *p_content; 1281 | extern char G_service[SVC_NAME_LEN+1]; 1282 | extern int G_error_code; 1283 | extern int G_usi; 1284 | #endif /* SILGY_SVC */ 1285 | 1286 | extern char G_blacklist[MAX_BLACKLIST+1][INET_ADDRSTRLEN]; 1287 | extern int G_blacklist_cnt; /* G_blacklist length */ 1288 | 1289 | extern char G_whitelist[MAX_WHITELIST+1][INET_ADDRSTRLEN]; 1290 | extern int G_whitelist_cnt; /* G_whitelist length */ 1291 | /* counters */ 1292 | extern counters_t G_cnts_today; /* today's counters */ 1293 | extern counters_t G_cnts_yesterday; /* yesterday's counters */ 1294 | extern counters_t G_cnts_day_before; /* day before's counters */ 1295 | /* REST */ 1296 | extern int G_rest_status; /* last REST call response status */ 1297 | extern unsigned G_rest_req; /* REST calls counter */ 1298 | extern double G_rest_elapsed; /* REST calls elapsed for calculating average */ 1299 | extern double G_rest_average; /* REST calls average elapsed */ 1300 | extern char G_rest_content_type[MAX_VALUE_LEN+1]; 1301 | extern int G_rest_res_len; 1302 | extern int G_new_user_id; 1303 | extern int G_qs_len; 1304 | 1305 | 1306 | #ifdef __cplusplus 1307 | } /* extern "C" */ 1308 | #endif 1309 | 1310 | 1311 | 1312 | 1313 | /* prototypes */ 1314 | 1315 | #ifdef __cplusplus 1316 | extern "C" { 1317 | #endif 1318 | 1319 | /* public engine functions */ 1320 | 1321 | void silgy_set_auth_level(const char *path, char level); 1322 | int eng_uses_start(int ci, const char *sesid); 1323 | void eng_uses_downgrade_by_uid(int uid, int ci); 1324 | void eng_async_req(int ci, const char *service, const char *data, char response, int timeout, int size); 1325 | void silgy_add_to_static_res(const char *name, const char *src); 1326 | void eng_block_ip(const char *value, bool autoblocked); 1327 | bool eng_is_uri(int ci, const char *uri); 1328 | bool silgy_set_host_res(const char *host, const char *res, const char *resmin); 1329 | void eng_out_check(int ci, const char *str); 1330 | void eng_out_check_realloc(int ci, const char *str); 1331 | void eng_out_check_realloc_bin(int ci, const char *data, int len); 1332 | char *eng_get_header(int ci, const char *header); 1333 | void eng_rest_header_pass(int ci, const char *header); 1334 | 1335 | /* public app functions */ 1336 | 1337 | #ifdef SILGY_SVC 1338 | void svc_out_check(const char *str); 1339 | void svc_out_check_realloc(const char *str); 1340 | void svc_out_check_realloc_bin(const char *data, int len); 1341 | bool silgy_svc_init(void); 1342 | void silgy_svc_main(int ci); 1343 | void silgy_svc_done(void); 1344 | #ifdef APP_ERROR_PAGE 1345 | void silgy_app_error_page(int ci, int code); 1346 | #endif 1347 | #ifdef APP_ACTIVATION_EMAIL 1348 | int silgy_app_user_activation_email(int ci, int uid, const char *email, const char *linkkey); 1349 | #endif 1350 | #else /* not SILGY_SVC */ 1351 | bool silgy_app_init(int argc, char *argv[]); 1352 | void silgy_app_done(void); 1353 | void silgy_app_main(int ci); 1354 | bool silgy_app_session_init(int ci); 1355 | void silgy_app_session_done(int ci); 1356 | #ifdef ASYNC 1357 | #ifdef ASYNC_USE_APP_CONTINUE /* depreciated */ 1358 | void silgy_app_continue(int ci, const char *data); 1359 | #endif 1360 | #endif 1361 | #ifdef APP_ERROR_PAGE 1362 | void silgy_app_error_page(int ci, int code); 1363 | #endif 1364 | #ifdef EVERY_SECOND 1365 | void app_every_second(void); 1366 | #endif 1367 | #ifdef APP_ACTIVATION_EMAIL 1368 | int silgy_app_user_activation_email(int ci, int uid, const char *email, const char *linkkey); 1369 | #endif 1370 | #endif /* SILGY_SVC */ 1371 | 1372 | #ifdef USERS 1373 | bool silgy_app_user_login(int ci); 1374 | void silgy_app_user_logout(int ci); 1375 | #endif 1376 | 1377 | #ifdef __cplusplus 1378 | } /* extern "C" */ 1379 | #endif 1380 | 1381 | 1382 | 1383 | #endif /* SILGY_H */ 1384 | --------------------------------------------------------------------------------