/* * SPL - The SPL Programming Language * Copyright (C) 2004, 2005 Clifford Wolf * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * webspl.c: CGI Script for using SPL for web applications */ #include #include #include #include #include #include #include #include #include #include #include "spl.h" #include "webspl_common.h" #include "compat.h" static struct spl_vm *vm; static struct spl_task *task; static void get_session_lock(const char *basedir, const char *session) { char *lockfile; int fd, retries = 0; create_dumpdir(basedir); expire_dumpdir(basedir, EXPIRE_DUMPDIR_TIMEOUT, EXPIRE_DUMPDIR_INTERVAL); my_asprintf(&lockfile, "%s/webspl_cache/%.*s.lock", basedir, (int)strcspn(session, ":"), session); retry_lock: fd = open(lockfile, O_CREAT|O_EXCL, 0600); if ( fd == -1 && errno == EEXIST ) { my_sleep(1); if ( retries++ > 10 ) { spl_report(SPL_REPORT_HOST, vm, "Stalled lock on session file!\n"); exit(0); } goto retry_lock; } close(fd); free(lockfile); } static void free_session_lock(const char *basedir, const char *session) { char *lockfile; my_asprintf(&lockfile, "%s/webspl_cache/%.*s.lock", basedir, (int)strcspn(session, ":"), session); unlink(lockfile); free(lockfile); } int main() { char basedir[1024] = "/tmp"; char *script_file = getenv("PATH_TRANSLATED"); char *scriptdir = script_file; getcwd(basedir, 1024); if (!scriptdir) { printf("Content-type: text/plain\n\n"); printf("Called webspl.cgi directly!\n"); printf("This script should only be used as action handler!\n\n"); printf("For debuging, e.g.:\n"); printf("QUERY_STRING='sid=HVMwQjeajMv3cOtAAP5WEUEP:wsfc_4&switch=3' \\\n"); printf("PATH_TRANSLATED='cfpmanager/cfpmanager.webspl' ./webspl.cgi\n\n"); return 1; } if ( scriptdir ) { char *lastslash = strrchr(scriptdir, '/'); if ( lastslash ) { char *new_scriptdir = malloc(lastslash-scriptdir + 1); strncpy(new_scriptdir, scriptdir, lastslash-scriptdir); new_scriptdir[lastslash-scriptdir] = 0; scriptdir = new_scriptdir; } else scriptdir = basedir; } else scriptdir = basedir; chdir(scriptdir); struct cgi_config *cfg = cgi_config_read(script_file); printf("Cache-Control: no-cache, must-revalidate, no-store\n"); printf("Pragma: nocache\n"); printf("Expires: 0\n"); SPL_REGISTER_BUILTIN_MODULE(cgi); spl_report = spl_mod_cgi_reportfunc; vm = spl_vm_create(); my_asprintf(&vm->path, ".:./spl_modules:%s/spl_modules:%s", basedir, spl_system_modules_dir()); my_asprintf(&vm->codecache_dir, "%s/webspl_cache", basedir); vm->runloop = spl_simple_runloop; spl_builtin_register_all(vm); spl_clib_reg(vm, "write", spl_mod_cgi_write, 0); vm->cgi_ctx = spl_mod_cgi_get_cgi_ctx(0, cfg); if ( !*vm->cgi_ctx->session ) { respawn_this_session: free(vm->cgi_ctx->session); vm->cgi_ctx->session = get_new_session(); get_session_lock(basedir, vm->cgi_ctx->session); int script_file_len = strlen(script_file); if (script_file_len > 8 && !strcmp(script_file+script_file_len-8, ".websplb")) { struct spl_code *code = spl_code_get(0); code->code_type = SPL_CODE_MAPPED; code->code = spl_mmap_file(script_file, &code->size); if (!code->code) { spl_report(SPL_REPORT_HOST, vm, "Can't open bytecode file!\n"); spl_code_put(code); return 1; } task = spl_task_create(vm, "main"); task->flags |= SPL_TASK_FLAG_PUBLIC; spl_task_setcode(task, code); task->code->id = strdup(script_file); } else { char *spl_source = spl_malloc_file(script_file, 0); if ( !spl_source ) { spl_report(SPL_REPORT_HOST, vm, "Can't open script file!\n"); return 1; } struct spl_asm *as = spl_asm_create(); as->vm = vm; if ( spl_compiler(as, spl_source, script_file, spl_malloc_file, 1) ) return 1; spl_asm_add(as, SPL_OP_HALT, "1"); spl_optimizer(as); task = spl_task_create(vm, "main"); task->flags |= SPL_TASK_FLAG_PUBLIC; spl_task_setcode(task, spl_asm_dump(as)); task->code->id = strdup(script_file); spl_asm_destroy(as); free(spl_source); } } else { char *dumpfile; my_asprintf(&dumpfile, "%s/webspl_cache/%.*s.spld", basedir, (int)strcspn(vm->cgi_ctx->session, ":"), vm->cgi_ctx->session); get_session_lock(basedir, vm->cgi_ctx->session); FILE *f = fopen(dumpfile, "r"); if (!f) { if (cgi_config_get_int(cfg, "spl.respawnsessions")) { free_session_lock(basedir, vm->cgi_ctx->session); goto respawn_this_session; } const char *expirelocation = cgi_config_get_str(cfg, "spl.expirelocation"); if (expirelocation) printf("Content-Type: text/html\n\n" "\n" " \n", expirelocation); else spl_report(SPL_REPORT_HOST, vm, "Can't read dumpfile!\n"); free_session_lock(basedir, vm->cgi_ctx->session); return 1; } spl_restore_ascii(vm, f); fclose(f); char *task_name = strchr(vm->cgi_ctx->session, ':'); if ( task_name ) task = spl_task_lookup(vm, task_name+1); else task = spl_task_lookup(vm, "main"); if ( !task || !(task->flags & SPL_TASK_FLAG_PUBLIC) ) { spl_report(SPL_REPORT_HOST, vm, "Can't find task or task is not public!\n"); free_session_lock(basedir, vm->cgi_ctx->session); return 1; } task->flags &= ~SPL_TASK_FLAG_PAUSED; } while ( task && task->code ) { spl_gc_maybe(vm); task = spl_schedule(task); if ( spl_exec(task) < 0 ) break; } char *dumpfile; my_asprintf(&dumpfile, "%s/webspl_cache/%.*s.spld", basedir, (int)strcspn(vm->cgi_ctx->session, ":"), vm->cgi_ctx->session); task = spl_task_lookup(vm, "main"); if ( task && task->code ) { FILE *f = fopen(dumpfile, "w"); if ( f ) { if (spl_dump_ascii(vm, f)) spl_report(SPL_REPORT_HOST, vm, "Dump failed: %s\n", dumpfile); fclose(f); } else spl_report(SPL_REPORT_HOST, vm, "Can't write dumpfile: %s\n", dumpfile); } else unlink(dumpfile); free(dumpfile); free_session_lock(basedir, vm->cgi_ctx->session); if (vm->cgi_ctx) { if (vm->cgi_ctx->config) { cgi_config_free(vm->cgi_ctx->config); vm->cgi_ctx->config = 0; } spl_mod_cgi_free_cgi_ctx(vm->cgi_ctx); vm->cgi_ctx = 0; } spl_vm_destroy(vm); return 0; }