You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
183 lines
4.1 KiB
183 lines
4.1 KiB
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <time.h>
|
|
|
|
#include <fcgi_config.h>
|
|
#include <fcgiapp.h>
|
|
|
|
#include <lua5.1/lua.h>
|
|
#include <pthread.h>
|
|
|
|
#include "lua.h"
|
|
#include "config.h"
|
|
#include "lua-fastcgi.h"
|
|
|
|
|
|
static char *http_status_strings[] = {
|
|
[200] = "OK",
|
|
[403] = "Forbidden",
|
|
[404] = "Not Found",
|
|
[500] = "Internal Server Error"
|
|
};
|
|
|
|
|
|
#define senderror(status_code,error_string) \
|
|
if(!state.committed){ \
|
|
FCGX_FPrintF(request.out, "Status: %d %s\r\n", status_code, http_status_strings[status_code]); \
|
|
FCGX_FPrintF(request.out, "Content-Type: %s\r\n\r\n", config->content_type); \
|
|
state.committed = 1; \
|
|
} \
|
|
FCGX_PutS(error_string, state.response);
|
|
|
|
|
|
#ifdef DEBUG
|
|
static void printcfg(LF_config *cfg)
|
|
{
|
|
printf("Listen: %s\n", cfg->listen);
|
|
printf("Backlog: %d\n", cfg->backlog);
|
|
printf("Threads: %d\n", cfg->threads);
|
|
printf("Sandbox: %d\n", cfg->sandbox);
|
|
printf("Max Memory: %zu\n", cfg->mem_max);
|
|
printf("Max Output: %zu\n", cfg->output_max);
|
|
printf("CPU usec: %lu\n", cfg->cpu_usec);
|
|
printf("CPU sec: %lu\n", cfg->cpu_sec);
|
|
printf("Default Content Type: %s\n", cfg->content_type);
|
|
printf("\n");
|
|
}
|
|
|
|
|
|
static void printvars(FCGX_Request *request)
|
|
{
|
|
for(int i=0; request->envp[i] != NULL; i++){
|
|
printf("%s\n", request->envp[i]);
|
|
}
|
|
printf("\n");
|
|
}
|
|
#endif
|
|
|
|
|
|
void *thread_run(void *arg)
|
|
{
|
|
LF_params *params = arg;
|
|
LF_config *config = params->config;
|
|
LF_limits *limits = LF_newlimits();
|
|
LF_state state;
|
|
lua_State *l;
|
|
|
|
FCGX_Request request;
|
|
FCGX_InitRequest(&request, params->socket, 0);
|
|
|
|
for(;;){
|
|
LF_setlimits(
|
|
limits, config->mem_max, config->output_max,
|
|
config->cpu_sec, config->cpu_usec
|
|
);
|
|
|
|
l = LF_newstate(config->sandbox, config->content_type);
|
|
|
|
if(FCGX_Accept_r(&request)){
|
|
printf("FCGX_Accept_r() failure\n");
|
|
LF_closestate(l);
|
|
continue;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
printvars(&request);
|
|
struct timespec rstart, rend;
|
|
clock_gettime(CLOCK_MONOTONIC, &rstart);
|
|
#endif
|
|
|
|
LF_parserequest(l, &request, &state);
|
|
|
|
#ifdef DEBUG
|
|
clock_gettime(CLOCK_MONOTONIC, &rend);
|
|
// Assumes the request returns in less than a second (which it should)
|
|
printf("Request parsed in %luns\n", (rend.tv_nsec-rstart.tv_nsec));
|
|
#endif
|
|
|
|
LF_enablelimits(l, limits);
|
|
|
|
switch(LF_loadscript(l)){
|
|
case 0:
|
|
if(lua_pcall(l, 0, 0, 0)){
|
|
if(lua_isstring(l, -1)){
|
|
senderror(500, lua_tostring(l, -1));
|
|
} else {
|
|
senderror(500, "unspecified lua error");
|
|
}
|
|
} else if(!state.committed){
|
|
senderror(200, "");
|
|
}
|
|
break;
|
|
|
|
case LF_ERRACCESS: senderror(403, "access denied"); break;
|
|
case LF_ERRMEMORY: senderror(500, "not enough memory"); break;
|
|
case LF_ERRNOTFOUND:
|
|
printf("404\n");
|
|
senderror(404, "no such file or directory");
|
|
break;
|
|
case LF_ERRSYNTAX: senderror(500, lua_tostring(l, -1)); break;
|
|
case LF_ERRBYTECODE: senderror(403, "compiled bytecode not supported"); break;
|
|
case LF_ERRNOPATH: senderror(500, "SCRIPT_FILENAME not provided"); break;
|
|
case LF_ERRNONAME: senderror(500, "SCRIPT_NAME not provided"); break;
|
|
}
|
|
|
|
FCGX_Finish_r(&request);
|
|
LF_closestate(l);
|
|
}
|
|
}
|
|
|
|
|
|
int main()
|
|
{
|
|
if(FCGX_Init() != 0){
|
|
printf("FCGX_Init() failure\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
LF_config *config = LF_createconfig();
|
|
if(config == NULL){
|
|
printf("LF_createconfig(): memory allocation error\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
if(LF_loadconfig(config, "./lua-fastcgi.lua")){
|
|
printf("Error loading lua-fastcgi.lua\n");
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
printcfg(config);
|
|
#endif
|
|
|
|
int socket = FCGX_OpenSocket(config->listen, config->backlog);
|
|
if(socket < 0){
|
|
printf("FCGX_OpenSocket() failure: could not open %s\n", config->listen);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
LF_params *params = malloc(sizeof(LF_params));
|
|
params->socket = socket;
|
|
params->config = config;
|
|
|
|
if(config->threads == 1){
|
|
thread_run(params);
|
|
} else {
|
|
pthread_attr_t attr;
|
|
pthread_attr_init(&attr);
|
|
pthread_t threads[config->threads];
|
|
for(int i=0; i < config->threads; i++){
|
|
int r = pthread_create(&threads[i], &attr, &thread_run, params);
|
|
if(r){
|
|
printf("Thread creation error: %d\n", r);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
pthread_join(threads[0], NULL);
|
|
}
|
|
|
|
return 0;
|
|
}
|