Newer
Older
session->req.send_location=MOVED_STAT;
if(cgi_status[0]==0)
SAFECOPY(cgi_status,"302 Moved Temporarily");
}
break;
case HEAD_STATUS:
SAFECOPY(cgi_status,value);
break;
case HEAD_TYPE:
got_valid_headers=TRUE;
default:
session->req.dynamic_heads
=add_list(session->req.dynamic_heads,buf);
}
}
}
else {
if(got_valid_headers) {
session->req.dynamic=IS_CGI;
if(cgi_status[0]==0)
SAFECOPY(cgi_status,"200 OK");
send_headers(session,cgi_status);
}
done_parsing_headers=TRUE;
}
}
}
if(FD_ISSET(err_pipe[0],&read_set)) {
buf[i]=0;
start=time(NULL);
}
else {
if((time(NULL)-start) >= startup->max_cgi_inactivity) {
lprintf(LOG_ERR,"%04d CGI Script %s Timed out",session->socket,cmdline);
done_reading=TRUE;
start=0;
/* Drain STDERR */
tv.tv_sec=1;
tv.tv_usec=0;
FD_ZERO(&read_set);
FD_SET(err_pipe[0],&read_set);
if(select(high_fd+1,&read_set,&write_set,NULL,&tv)>0)
if(FD_ISSET(err_pipe[0],&read_set)) {
while(pipereadline(err_pipe[0],buf,sizeof(buf))!=-1)
lprintf(LOG_ERR,"%s",buf);
if(!done_wait) {
if(start)
lprintf(LOG_NOTICE,"%04d CGI Script %s still alive on client exit",session->socket,cmdline);
kill(child,SIGTERM);
mswait(1000);
done_wait = (waitpid(child,&status,WNOHANG)==child);
kill(child,SIGKILL);
done_wait = (waitpid(child,&status,0)==child);
}
close(in_pipe[1]); /* close write-end of pipe */
close(out_pipe[0]); /* close read-end of pipe */
close(err_pipe[0]); /* close read-end of pipe */
if(!got_valid_headers) {
lprintf(LOG_ERR,"%04d CGI Script %s did not generate valid headers",session->socket,cmdline);
return(FALSE);
}
if(!done_parsing_headers) {
lprintf(LOG_ERR,"%04d CGI Script %s did not send data header termination",session->socket,cmdline);
return(FALSE);
}
if(!done_parsing_headers || !got_valid_headers) {
return(FALSE);
}
return(TRUE);
/* Win32 exec_cgi() */
return(FALSE);
/********************/
/* JavaScript stuff */
/********************/
JSObject* DLLCALL js_CreateHttpReplyObject(JSContext* cx
,JSObject* parent, http_session_t *session)
{
JSObject* reply;
JSObject* headers;
jsval val;
JSString* js_str;
/* Return existing object if it's already been created */
if(JS_GetProperty(cx,parent,"http_reply",&val) && val!=JSVAL_VOID) {
reply = JSVAL_TO_OBJECT(val);
JS_ClearScope(cx,reply);
}
else
reply = JS_DefineObject(cx, parent, "http_reply", NULL
, NULL, JSPROP_ENUMERATE|JSPROP_READONLY);
if((js_str=JS_NewStringCopyZ(cx, "200 OK"))==NULL)
return(FALSE);
JS_DefineProperty(cx, reply, "status", STRING_TO_JSVAL(js_str)
,NULL,NULL,JSPROP_ENUMERATE);
/* Return existing object if it's already been created */
if(JS_GetProperty(cx,reply,"header",&val) && val!=JSVAL_VOID) {
headers = JSVAL_TO_OBJECT(val);
JS_ClearScope(cx,headers);
}
else
headers = JS_DefineObject(cx, reply, "header", NULL
, NULL, JSPROP_ENUMERATE|JSPROP_READONLY);
if((js_str=JS_NewStringCopyZ(cx, "text/html"))==NULL)
return(FALSE);
JS_DefineProperty(cx, headers, "Content-Type", STRING_TO_JSVAL(js_str)
,NULL,NULL,JSPROP_ENUMERATE);
return(reply);
}
JSObject* DLLCALL js_CreateHttpRequestObject(JSContext* cx
,JSObject* parent, http_session_t *session)
/* JSObject* cookie; */
JSObject* headers;
JSString* js_str;
jsval val;
/* Return existing object if it's already been created */
if(JS_GetProperty(cx,parent,"http_request",&val) && val!=JSVAL_VOID) {
else
request = JS_DefineObject(cx, parent, "http_request", NULL
, NULL, JSPROP_ENUMERATE|JSPROP_READONLY);
if((js_str=JS_NewStringCopyZ(session->js_cx, methods[session->req.method]))==NULL)
JS_DefineProperty(session->js_cx, request, "method", STRING_TO_JSVAL(js_str)
,NULL,NULL,JSPROP_ENUMERATE|JSPROP_READONLY);
if((js_str=JS_NewStringCopyZ(session->js_cx, session->req.virtual_path))==NULL)
JS_DefineProperty(session->js_cx, request, "virtual_path", STRING_TO_JSVAL(js_str)
,NULL,NULL,JSPROP_ENUMERATE|JSPROP_READONLY);
/* Return existing object if it's already been created */
if(JS_GetProperty(cx,request,"query",&val) && val!=JSVAL_VOID) {
else
query = JS_DefineObject(cx, request, "query", NULL
, NULL, JSPROP_ENUMERATE|JSPROP_READONLY);
/* Return existing object if it's already been created */
if(JS_GetProperty(cx,request,"header",&val) && val!=JSVAL_VOID) {
headers = JSVAL_TO_OBJECT(val);
JS_ClearScope(cx,headers);
}
else
headers = JS_DefineObject(cx, request, "header", NULL
, NULL, JSPROP_ENUMERATE|JSPROP_READONLY);
session->js_query=query;
session->js_header=headers;
session->js_request=request;
static void
js_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report)
{
char line[64];
char file[MAX_PATH+1];
char* warning;
http_session_t* session;
if((session=(http_session_t*)JS_GetContextPrivate(cx))==NULL)
return;
if(report==NULL) {
lprintf(LOG_ERR,"%04d !JavaScript: %s", session->socket, message);
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
if(session->req.fp!=NULL)
fprintf(session->req.fp,"!JavaScript: %s", message);
return;
}
if(report->filename)
sprintf(file," %s",report->filename);
else
file[0]=0;
if(report->lineno)
sprintf(line," line %u",report->lineno);
else
line[0]=0;
if(JSREPORT_IS_WARNING(report->flags)) {
if(JSREPORT_IS_STRICT(report->flags))
warning="strict warning";
else
warning="warning";
} else
warning="";
lprintf(LOG_ERR,"%04d !JavaScript %s%s%s: %s",session->socket,warning,file,line,message);
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
if(session->req.fp!=NULL)
fprintf(session->req.fp,"!JavaScript %s%s%s: %s",warning,file,line,message);
}
static JSBool
js_write(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
uintN i;
JSString * str;
http_session_t* session;
if((session=(http_session_t*)JS_GetContextPrivate(cx))==NULL)
return(JS_FALSE);
if(session->req.fp==NULL)
return(JS_FALSE);
for(i=0; i<argc; i++) {
if((str=JS_ValueToString(cx, argv[i]))==NULL)
continue;
fprintf(session->req.fp,"%s",JS_GetStringBytes(str));
}
return(JS_TRUE);
}
static JSBool
js_writeln(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
uintN i;
JSString * str;
http_session_t* session;
if((session=(http_session_t*)JS_GetContextPrivate(cx))==NULL)
return(JS_FALSE);
if(session->req.fp==NULL)
return(JS_FALSE);
for (i=0; i<argc;i++) {
if((str=JS_ValueToString(cx, argv[i]))==NULL)
continue;
fprintf(session->req.fp,"%s",JS_GetStringBytes(str));
}
fprintf(session->req.fp,"\n");
return(JS_TRUE);
}
static JSFunctionSpec js_global_functions[] = {
{"write", js_write, 1}, /* write to HTML file */
{"writeln", js_writeln, 1}, /* write line to HTML file */
{0}
};
static JSContext*
js_initcx(JSRuntime* runtime, SOCKET sock, JSObject** glob, http_session_t *session)
{
JSContext* js_cx;
JSObject* js_glob;
BOOL success=FALSE;
lprintf(LOG_INFO,"%04d JavaScript: Initializing context (stack: %lu bytes)"
,sock,startup->js_cx_stack);
if((js_cx = JS_NewContext(runtime, startup->js_cx_stack))==NULL)
return(NULL);
lprintf(LOG_INFO,"%04d JavaScript: Context created",sock);
JS_SetErrorReporter(js_cx, js_ErrorReporter);
do {
lprintf(LOG_INFO,"%04d JavaScript: Initializing Global object",sock);
if((js_glob=js_CreateGlobalObject(js_cx, &scfg, NULL))==NULL)
break;
if (!JS_DefineFunctions(js_cx, js_glob, js_global_functions))
break;
lprintf(LOG_INFO,"%04d JavaScript: Initializing System object",sock);
if(js_CreateSystemObject(js_cx, js_glob, &scfg, uptime, startup->host_name, SOCKLIB_DESC)==NULL)
break;
if(js_CreateServerObject(js_cx,js_glob,&js_server_props)==NULL)
break;
if(glob!=NULL)
*glob=js_glob;
success=TRUE;
} while(0);
if(!success) {
JS_DestroyContext(js_cx);
session->js_cx=NULL;
return(NULL);
}
return(js_cx);
}
static BOOL js_setup(http_session_t* session)
if(session->js_runtime == NULL) {
lprintf(LOG_INFO,"%04d JavaScript: Creating runtime: %lu bytes"
,session->socket,startup->js_max_bytes);
if((session->js_runtime=JS_NewRuntime(startup->js_max_bytes))==NULL) {
lprintf(LOG_ERR,"%04d !ERROR creating JavaScript runtime",session->socket);
send_error(session,"500 Error creating JavaScript runtime");
return(FALSE);
}
}
if(session->js_cx==NULL) { /* Context not yet created, create it now */
if(((session->js_cx=js_initcx(session->js_runtime, session->socket
lprintf(LOG_ERR,"%04d !ERROR initializing JavaScript context",session->socket);
send_error(session,"500 Error initializing JavaScript context");
return(FALSE);
}
if(js_CreateUserClass(session->js_cx, session->js_glob, &scfg)==NULL)
lprintf(LOG_ERR,"%04d !JavaScript ERROR creating user class",session->socket);
if(js_CreateFileClass(session->js_cx, session->js_glob)==NULL)
lprintf(LOG_ERR,"%04d !JavaScript ERROR creating File class",session->socket);
if(js_CreateSocketClass(session->js_cx, session->js_glob)==NULL)
lprintf(LOG_ERR,"%04d !JavaScript ERROR creating Socket class",session->socket);
if(js_CreateMsgBaseClass(session->js_cx, session->js_glob, &scfg)==NULL)
lprintf(LOG_ERR,"%04d !JavaScript ERROR creating MsgBase class",session->socket);
argv=JS_NewArrayObject(session->js_cx, 0, NULL);
JS_DefineProperty(session->js_cx, session->js_glob, "argv", OBJECT_TO_JSVAL(argv)
,NULL,NULL,JSPROP_READONLY|JSPROP_ENUMERATE);
JS_DefineProperty(session->js_cx, session->js_glob, "argc", INT_TO_JSVAL(0)
,NULL,NULL,JSPROP_READONLY|JSPROP_ENUMERATE);
}
lprintf(LOG_INFO,"%04d JavaScript: Initializing HttpRequest object",session->socket);
if(js_CreateHttpRequestObject(session->js_cx, session->js_glob, session)==NULL) {
lprintf(LOG_ERR,"%04d !ERROR initializing JavaScript HttpRequest object",session->socket);
send_error(session,"500 Error initializing JavaScript HttpRequest object");
return(FALSE);
}
lprintf(LOG_INFO,"%04d JavaScript: Initializing HttpReply object",session->socket);
if(js_CreateHttpReplyObject(session->js_cx, session->js_glob, session)==NULL) {
lprintf(LOG_ERR,"%04d !ERROR initializing JavaScript HttpReply object",session->socket);
send_error(session,"500 Error initializing JavaScript HttpReply object");
return(FALSE);
}
lprintf(LOG_INFO,"%04d JavaScript: Initializing User Objects",session->socket);
if(!js_CreateUserObjects(session->js_cx, session->js_glob, &scfg, NULL
,NULL /* ftp index file */, NULL /* subscan */)) {
lprintf(LOG_ERR,"%04d !ERROR initializing JavaScript User Objects",session->socket);
send_error(session,"500 Error initializing JavaScript User Objects");
return(FALSE);
}
JS_SetContextPrivate(session->js_cx, session);
return(TRUE);
}
static BOOL exec_ssjs(http_session_t* session) {
JSString* js_str;
JSScript* js_script;
jsval rval;
jsval val;
JSObject* reply;
JSIdArray* heads;
JSObject* headers;
char path[MAX_PATH+1];
char str[MAX_REQUEST_LINE+1];
int i;
if((js_str=JS_NewStringCopyZ(session->js_cx, session->req.physical_path))==NULL)
return(FALSE);
JS_DefineProperty(session->js_cx, session->js_request, "real_path", STRING_TO_JSVAL(js_str)
,NULL,NULL,JSPROP_ENUMERATE|JSPROP_READONLY);
if((js_str=JS_NewStringCopyZ(session->js_cx, session->req.ars))==NULL)
return(FALSE);
JS_DefineProperty(session->js_cx, session->js_request, "ars", STRING_TO_JSVAL(js_str)
,NULL,NULL,JSPROP_ENUMERATE|JSPROP_READONLY);
if((js_str=JS_NewStringCopyZ(session->js_cx, session->req.host))==NULL)
return(FALSE);
JS_DefineProperty(session->js_cx, session->js_request, "host", STRING_TO_JSVAL(js_str)
,NULL,NULL,JSPROP_ENUMERATE|JSPROP_READONLY);
if((js_str=JS_NewStringCopyZ(session->js_cx, http_vers[session->http_ver]))==NULL)
return(FALSE);
JS_DefineProperty(session->js_cx, session->js_request, "http_ver", STRING_TO_JSVAL(js_str)
,NULL,NULL,JSPROP_ENUMERATE|JSPROP_READONLY);
if((js_str=JS_NewStringCopyZ(session->js_cx, session->host_ip))==NULL)
return(FALSE);
JS_DefineProperty(session->js_cx, session->js_request, "remote_ip", STRING_TO_JSVAL(js_str)
,NULL,NULL,JSPROP_ENUMERATE|JSPROP_READONLY);
if((js_str=JS_NewStringCopyZ(session->js_cx, session->host_name))==NULL)
return(FALSE);
JS_DefineProperty(session->js_cx, session->js_request, "remote_host", STRING_TO_JSVAL(js_str)
,NULL,NULL,JSPROP_ENUMERATE|JSPROP_READONLY);
do {
/* RUN SCRIPT */
JS_ClearPendingException(session->js_cx);
if((js_script=JS_CompileFile(session->js_cx, session->js_glob
,session->req.physical_path))==NULL) {
lprintf(LOG_ERR,"%04d !JavaScript FAILED to compile script (%s)"
,session->socket,session->req.physical_path);
return(FALSE);
}
JS_ExecuteScript(session->js_cx, session->js_glob, js_script, &rval);
} while(0);
/* Read http_reply object */
JS_GetProperty(session->js_cx,session->js_glob,"http_reply",&val);
reply = JSVAL_TO_OBJECT(val);
JS_GetProperty(session->js_cx,reply,"status",&val);
SAFECOPY(session->req.status,JS_GetStringBytes(JSVAL_TO_STRING(val)));
JS_GetProperty(session->js_cx,reply,"header",&val);
headers = JSVAL_TO_OBJECT(val);
heads=JS_Enumerate(session->js_cx,headers);
for(i=0;i<heads->length;i++) {
JS_IdToValue(session->js_cx,heads->vector[i],&val);
js_str=JSVAL_TO_STRING(val);
JS_GetProperty(session->js_cx,headers,JS_GetStringBytes(js_str),&val);
safe_snprintf(str,sizeof(str),"%s: %s"
,JS_GetStringBytes(js_str),JS_GetStringBytes(JSVAL_TO_STRING(val)));
session->req.dynamic_heads=add_list(session->req.dynamic_heads,str);
}
JS_DestroyIdArray(session->js_cx, heads);
/* Free up temporary resources here */
if(js_script!=NULL)
JS_DestroyScript(session->js_cx, js_script);
if(session->req.fp!=NULL)
fclose(session->req.fp);
SAFECOPY(session->req.physical_path, path);
session->req.dynamic=IS_SSJS;
return(TRUE);
}
static void respond(http_session_t * session)
{
BOOL send_file=TRUE;
if(session->req.dynamic==IS_CGI) {
return;
}
close_request(session);
return;
}
if(session->req.dynamic==IS_SSJS) { /* Server-Side JavaScript */
if(!exec_ssjs(session)) {
return;
}
sprintf(session->req.physical_path
,"%s/SBBS_SSJS.%d.html",startup->cgi_temp_dir,session->socket);
}
session->req.mime_type=get_mime_type(strrchr(session->req.physical_path,'.'));
send_file=send_headers(session,session->req.status);
if(session->req.method==HTTP_HEAD)
send_file=FALSE;
if(send_file) {
lprintf(LOG_INFO,"%04d Sending file: %s",session->socket, session->req.physical_path);
snt=sock_sendfile(session->socket,session->req.physical_path);
if(session->req.ld!=NULL) {
if(snt<0)
snt=0;
session->req.ld->size=snt;
}
lprintf(LOG_INFO,"%04d Sent file: %s",session->socket, session->req.physical_path);
close_request(session);
}
void http_session_thread(void* arg)
{
char* host_name;
HOSTENT* host;
SOCKET socket;
char redir_req[MAX_REQUEST_LINE+1];
char *redirp;
http_session_t session=*(http_session_t*)arg; /* copies arg BEFORE it's freed */
int loop_count;
socket=session.socket;
lprintf(LOG_DEBUG,"%04d Session thread started", session.socket);
thread_up(TRUE /* setuid */);
session.finished=FALSE;
if(startup->options&BBS_OPT_NO_HOST_LOOKUP)
host=NULL;
else
host=gethostbyaddr ((char *)&session.addr.sin_addr
,sizeof(session.addr.sin_addr),AF_INET);
if(host!=NULL && host->h_name!=NULL)
host_name=host->h_name;
else
host_name=session.host_ip;
SAFECOPY(session.host_name,host_name);
if(!(startup->options&BBS_OPT_NO_HOST_LOOKUP)) {
lprintf(LOG_INFO,"%04d Hostname: %s", session.socket, host_name);
for(i=0;host!=NULL && host->h_aliases!=NULL
&& host->h_aliases[i]!=NULL;i++)
lprintf(LOG_INFO,"%04d HostAlias: %s", session.socket, host->h_aliases[i]);
if(trashcan(&scfg,host_name,"host")) {
close_socket(session.socket);
lprintf(LOG_NOTICE,"%04d !CLIENT BLOCKED in host.can: %s", session.socket, host_name);
/* host_ip wasn't defined in http_session_thread */
if(trashcan(&scfg,session.host_ip,"ip")) {
close_socket(session.socket);
lprintf(LOG_NOTICE,"%04d !CLIENT BLOCKED in ip.can: %s", session.socket, session.host_ip);
thread_down();
return;
}
active_clients++;
update_clients();
SAFECOPY(session.username,unknown);
SAFECOPY(session.client.addr,session.host_ip);
SAFECOPY(session.client.host,session.host_name);
session.client.port=ntohs(session.addr.sin_port);
session.client.time=time(NULL);
session.client.protocol="http";
session.client.user=session.username;
session.client.size=sizeof(session.client);
client_on(session.socket, &session.client, TRUE);
if(session.socket!=INVALID_SOCKET && startup!=NULL && startup->socket_open!=NULL)
startup->socket_open(startup->cbdata,TRUE);
while(!session.finished && server_socket!=INVALID_SOCKET) {
memset(&(session.req), 0, sizeof(session.req));
SAFECOPY(session.req.status,"200 OK");
session.req.send_location=NO_LOCATION;
redirp=NULL;
loop_count=0;
while((redirp==NULL || session.req.send_location >= MOVED_TEMP)
&& !session.finished && server_socket!=INVALID_SOCKET) {
session.req.send_location=NO_LOCATION;
session.req.ld=NULL;
if(startup->options&WEB_OPT_HTTP_LOGGING) {
if((session.req.ld=(struct log_data*)malloc(sizeof(struct log_data)))==NULL)
lprintf(LOG_ERR,"%04d Cannot allocate memory for log data!",session.socket);
if(session.req.ld!=NULL) {
memset(session.req.ld,0,sizeof(struct log_data));
session.req.ld->hostname=strdup(session.host_name);
}
if(get_req(&session,redirp)) {
/* At this point, if redirp is non-NULL then the headers have already been parsed */
if((session.http_ver<HTTP_1_0)||redirp!=NULL||parse_headers(&session)) {
if(check_request(&session)) {
if(session.req.send_location < MOVED_TEMP || session.req.virtual_path[0]!='/' || loop_count++ >= MAX_REDIR_LOOPS) {
respond(&session);
}
safe_snprintf(redir_req,sizeof(redir_req),"%s %s%s%s",methods[session.req.method]
,session.req.virtual_path,session.http_ver<HTTP_1_0?"":" ",http_vers[session.http_ver]);
lprintf(LOG_DEBUG,"%04d Internal Redirect to: %s",socket,redir_req);
redirp=redir_req;
}
}
}
}
}
}
if(session.js_cx!=NULL) {
lprintf(LOG_INFO,"%04d JavaScript: Destroying context",socket);
JS_DestroyContext(session.js_cx); /* Free Context */
session.js_cx=NULL;
}
if(session.js_runtime!=NULL) {
lprintf(LOG_INFO,"%04d JavaScript: Destroying runtime",socket);
JS_DestroyRuntime(session.js_runtime);
}
active_clients--;
update_clients();
client_off(session.socket);
if(startup!=NULL && startup->socket_open!=NULL)
startup->socket_open(startup->cbdata,FALSE);
thread_down();
lprintf(LOG_INFO,"%04d Session thread terminated (%u clients, %u threads remain, %lu served)"
,socket, active_clients, thread_count, served);
}
void DLLCALL web_terminate(void)
{
lprintf(LOG_INFO,"%04d Web Server terminate",server_socket);
terminate_server=TRUE;
}
static void cleanup(int code)
{
free_cfg(&scfg);
listFree(&log_list);
mime_types=iniFreeNamedStringList(mime_types);
semfile_list_free(&recycle_semfiles);
semfile_list_free(&shutdown_semfiles);
if(server_socket!=INVALID_SOCKET) {
close_socket(server_socket);
server_socket=INVALID_SOCKET;
}
update_clients();
#ifdef _WINSOCKAPI_
if(WSAInitialized && WSACleanup()!=0)
lprintf(LOG_ERR,"0000 !WSACleanup ERROR %d",ERROR_VALUE);
#endif
thread_down();
status("Down");
if(terminate_server || code)
lprintf(LOG_INFO,"#### Web Server thread terminated (%u threads remain, %lu clients served)"
,thread_count, served);
if(startup!=NULL && startup->terminated!=NULL)
startup->terminated(startup->cbdata,code);
}
const char* DLLCALL web_ver(void)
{
static char ver[256];
char compiler[32];
DESCRIBE_COMPILER(compiler);
sscanf("$Revision$", "%*s %s", revision);
sprintf(ver,"%s %s%s "
"Compiled %s %s with %s"
,server_name
,revision
#ifdef _DEBUG
," Debug"
#else
,""
#endif
,__DATE__, __TIME__, compiler);
return(ver);
}
void http_logging_thread(void* arg)
{
char base[MAX_PATH+1];
char filename[MAX_PATH+1];
char newfilename[MAX_PATH+1];
FILE* logfile=NULL;
http_logging_thread_running=TRUE;
terminate_http_logging_thread=FALSE;
SAFECOPY(base,arg);
if(!base[0])
SAFEPRINTF(base,"%slogs/http-",scfg.logs_dir);
filename[0]=0;
newfilename[0]=0;
thread_up(TRUE /* setuid */);
lprintf(LOG_INFO,"0000 http logging thread started");
for(;!terminate_http_logging_thread;) {
struct log_data *ld;
char sizestr[100];
sem_wait(&log_sem);
if(terminate_http_logging_thread)
break;
pthread_mutex_lock(&log_mutex);
ld=listRemoveNode(&log_list, FIRST_NODE);
pthread_mutex_unlock(&log_mutex);
lprintf(LOG_ERR,"0000 http logging thread received NULL linked list log entry");
continue;
}
SAFECOPY(newfilename,base);
strftime(strchr(newfilename,0),15,"%Y-%m-%d.log",&ld->completed);
if(strcmp(newfilename,filename)) {
fclose(logfile);
SAFECOPY(filename,newfilename);
logfile=fopen(filename,"ab");
lprintf(LOG_INFO,"0000 http logfile is now: %s",filename);
}
if(logfile!=NULL) {
sprintf(sizestr,"%d",ld->size);
strftime(timestr,sizeof(timestr),"%d/%b/%Y:%H:%M:%S %z",&ld->completed);
while(lock(fileno(logfile),0,1) && !terminate_http_logging_thread) {
fprintf(logfile,"%s %s %s [%s] \"%s\" %d %s \"%s\" \"%s\"\n"
,ld->hostname?(ld->hostname[0]?ld->hostname:"-"):"-"
,ld->ident?(ld->ident[0]?ld->ident:"-"):"-"
,ld->user?(ld->user[0]?ld->user:"-"):"-"
,timestr
,ld->request?(ld->request[0]?ld->request:"-"):"-"
,ld->status
,ld->size?sizestr:"-"
,ld->referrer?(ld->referrer[0]?ld->referrer:"-"):"-"
,ld->agent?(ld->agent[0]?ld->agent:"-"):"-");
fflush(logfile);
unlock(fileno(logfile),0,1);
FREE_AND_NULL(ld->hostname);
FREE_AND_NULL(ld->ident);
FREE_AND_NULL(ld->user);
FREE_AND_NULL(ld->request);
FREE_AND_NULL(ld->referrer);
FREE_AND_NULL(ld->agent);
FREE_AND_NULL(ld);
}
else {
logfile=fopen(filename,"ab");
lprintf(LOG_ERR,"0000 http logfile %s was not open!",filename);
}
}
fclose(logfile);
thread_down();
lprintf(LOG_INFO,"0000 http logging thread terminated");
http_logging_thread_running=FALSE;
}
void DLLCALL web_server(void* arg)
{
int i;
int result;
time_t start;
WORD host_port;
char host_ip[32];
char path[MAX_PATH+1];
char logstr[256];
SOCKADDR_IN server_addr={0};
SOCKADDR_IN client_addr;
socklen_t client_addr_len;
SOCKET client_socket;
SOCKET high_socket_set;
fd_set socket_set;
time_t t;
time_t initialized=0;
char compiler[32];
http_session_t * session;
struct timeval tv;
startup=(web_startup_t*)arg;
if(startup==NULL) {
sbbs_beep(100,500);
fprintf(stderr, "No startup structure passed!\n");
return;
}
if(startup->size!=sizeof(web_startup_t)) { /* verify size */
sbbs_beep(100,500);
sbbs_beep(300,500);
sbbs_beep(100,500);
fprintf(stderr, "Invalid startup structure!\n");
return;
}
#ifdef _THREAD_SUID_BROKEN
startup->seteuid(TRUE);
#endif
/* Setup intelligent defaults */
if(startup->port==0) startup->port=IPPORT_HTTP;
if(startup->root_dir[0]==0) SAFECOPY(startup->root_dir,WEB_DEFAULT_ROOT_DIR);
if(startup->error_dir[0]==0) SAFECOPY(startup->error_dir,WEB_DEFAULT_ERROR_DIR);
if(startup->cgi_dir[0]==0) SAFECOPY(startup->error_dir,WEB_DEFAULT_CGI_DIR);
if(startup->max_inactivity==0) startup->max_inactivity=120; /* seconds */
if(startup->sem_chk_freq==0) startup->sem_chk_freq=2; /* seconds */
if(startup->js_max_bytes==0) startup->js_max_bytes=JAVASCRIPT_MAX_BYTES;
if(startup->js_cx_stack==0) startup->js_cx_stack=JAVASCRIPT_CONTEXT_STACK;
if(startup->ssjs_ext[0]==0) SAFECOPY(startup->ssjs_ext,"ssjs");
sprintf(js_server_props.version,"%s %s",server_name,revision);
js_server_props.version_detail=web_ver();
js_server_props.clients=&active_clients;
js_server_props.options=&startup->options;
js_server_props.interface_addr=&startup->interface_addr;
/* Copy html directories */
SAFECOPY(root_dir,startup->root_dir);
SAFECOPY(error_dir,startup->error_dir);
SAFECOPY(cgi_dir,startup->cgi_dir);
/* Change to absolute path */
prep_dir(startup->ctrl_dir, root_dir, sizeof(root_dir));
prep_dir(root_dir, error_dir, sizeof(error_dir));
/* Trim off trailing slash/backslash */
if(IS_PATH_DELIM(*(p=lastchar(root_dir)))) *p=0;
uptime=0;
served=0;
startup->recycle_now=FALSE;
terminate_server=FALSE;
do {
thread_up(FALSE /* setuid */);
status("Initializing");
memset(&scfg, 0, sizeof(scfg));
lprintf(LOG_INFO,"%s Revision %s%s"
,revision
#ifdef _DEBUG
," Debug"
#else
,""
#endif
);
DESCRIBE_COMPILER(compiler);
lprintf(LOG_INFO,"Compiled %s %s with %s", __DATE__, __TIME__, compiler);
srand(time(NULL)); /* Seed random number generator */
sbbs_random(10); /* Throw away first number */
if(!winsock_startup()) {
cleanup(1);
return;
}
t=time(NULL);
lprintf(LOG_INFO,"Initializing on %.24s with options: %lx"
,CTIME_R(&t,logstr),startup->options);
lprintf(LOG_DEBUG,"Root HTML directory: %s", root_dir);
lprintf(LOG_DEBUG,"Error HTML directory: %s", error_dir);
/* Initial configuration and load from CNF files */
SAFECOPY(scfg.ctrl_dir,startup->ctrl_dir);
lprintf(LOG_INFO,"Loading configuration files from %s", scfg.ctrl_dir);
scfg.size=sizeof(scfg);
SAFECOPY(logstr,UNKNOWN_LOAD_ERROR);
if(!load_cfg(&scfg, NULL, TRUE, logstr)) {
lprintf(LOG_ERR,"!ERROR %s",logstr);
lprintf(LOG_ERR,"!FAILED to load configuration files");
cleanup(1);
return;
}
scfg_reloaded=TRUE;
iniFileName(path,sizeof(path),scfg.ctrl_dir,"mime_types.ini");
if(!read_mime_types(path)) {
cleanup(1);
return;
}
if(startup->host_name[0]==0)
SAFECOPY(startup->host_name,scfg.sys_inetaddr);
if(!(scfg.sys_misc&SM_LOCAL_TZ) && !(startup->options&BBS_OPT_LOCAL_TIMEZONE)) {
if(putenv("TZ=UTC0"))
lprintf(LOG_WARNING,"!putenv() FAILED");
tzset();
}
if(uptime==0)
uptime=time(NULL); /* this must be done *after* setting the timezone */
active_clients=0;
update_clients();
/* open a socket and wait for a client */
server_socket = open_socket(SOCK_STREAM);
if(server_socket == INVALID_SOCKET) {
lprintf(LOG_ERR,"!ERROR %d creating HTTP socket", ERROR_VALUE);
cleanup(1);
return;
}
/*
* i=1;
* if(setsockopt(server_socket, IPPROTO_TCP, TCP_NOPUSH, &i, sizeof(i)))
* lprintf("Cannot set TCP_NOPUSH socket option");
*/
lprintf(LOG_INFO,"%04d Web Server socket opened",server_socket);
/*****************************/
/* Listen for incoming calls */
/*****************************/
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_addr.s_addr = htonl(startup->interface_addr);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(startup->port);
if(startup->seteuid!=NULL)
startup->seteuid(FALSE);
result = bind(server_socket,(struct sockaddr *)&server_addr,sizeof(server_addr));
if(startup->seteuid!=NULL)
startup->seteuid(TRUE);
if(result != 0) {
lprintf(LOG_ERR,"%04d !ERROR %d (%d) binding socket to port %d"
,server_socket, result, ERROR_VALUE,startup->port);
lprintf(LOG_NOTICE,"%s",BIND_FAILURE_HELP);
cleanup(1);
return;
}
result = listen(server_socket, 64);
if(result != 0) {
lprintf(LOG_ERR,"%04d !ERROR %d (%d) listening on socket"
,server_socket, result, ERROR_VALUE);
cleanup(1);
return;
}