Skip to content
Snippets Groups Projects
websrvr.c 197 KiB
Newer Older
deuce's avatar
deuce committed
	else
		session->js_query = JS_DefineObject(cx, session->js_request, "query", NULL
									, NULL, JSPROP_ENUMERATE|JSPROP_READONLY);
	/* Return existing object if it's already been created */
	if(JS_GetProperty(cx,session->js_request,"header",&val) && val!=JSVAL_VOID)  {
		session->js_header = JSVAL_TO_OBJECT(val);
		JS_ClearScope(cx,session->js_header);
		session->js_header = JS_DefineObject(cx, session->js_request, "header", NULL
									, NULL, JSPROP_ENUMERATE|JSPROP_READONLY);
	/* Return existing object if it's already been created */
	if(JS_GetProperty(cx,session->js_request,"cookie",&val) && val!=JSVAL_VOID)  {
		session->js_cookie = JSVAL_TO_OBJECT(val);
		JS_ClearScope(cx,session->js_cookie);
	}
	else
		session->js_cookie = JS_DefineObject(cx, session->js_request, "cookie", NULL
									, NULL, JSPROP_ENUMERATE|JSPROP_READONLY);


	return(session->js_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;
		lprintf(LOG_ERR,"%04d !JavaScript: %s", session->socket, message);
		if(session->req.fp!=NULL)
			fprintf(session->req.fp,"!JavaScript: %s", message);
		return;
    }

	if(report->filename)
		SAFEPRINTF(file," %s",report->filename);
		SAFEPRINTF(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";
		log_level=LOG_WARNING;
	} else {
		log_level=LOG_ERR;
	lprintf(log_level,"%04d !JavaScript %s%s%s: %s, Request: %s"
		,session->socket,warning,file,line,message, session->req.request_line);
	if(session->req.fp!=NULL)
		fprintf(session->req.fp,"!JavaScript %s%s%s: %s",warning,file,line,message);
}

static void js_writebuf(http_session_t *session, const char *buf, size_t buflen)
		if(session->req.send_content)
			writebuf(session,buf,buflen);
	}
	else
		fwrite(buf,1,buflen,session->req.fp);
}

deuce's avatar
deuce committed
js_writefunc(JSContext *cx, uintN argc, jsval *arglist, BOOL writeln)
deuce's avatar
deuce committed
	jsval *argv=JS_ARGV(cx, arglist);
deuce's avatar
deuce committed
	jsrefcount	rc;
deuce's avatar
deuce committed
	char		*cstr=NULL;
	size_t		cstr_sz=0;
deuce's avatar
deuce committed
	size_t		len;

	if((session=(http_session_t*)JS_GetContextPrivate(cx))==NULL)
		return(JS_FALSE);

	if((!session->req.prev_write) && (!session->req.sent_headers)) {
		if(session->http_ver>=HTTP_1_1 && session->req.keep_alive) {
deuce's avatar
deuce committed
			if(!ssjs_send_headers(session,TRUE)) {
		else {
			/* "Fast Mode" requested? */
			jsval		val;
			JSObject*	reply;
			JS_GetProperty(cx, session->js_glob, "http_reply", &val);
			reply=JSVAL_TO_OBJECT(val);
			JS_GetProperty(cx, reply, "fast", &val);
			if(JSVAL_IS_BOOLEAN(val) && JSVAL_TO_BOOLEAN(val)) {
				session->req.keep_alive=FALSE;
deuce's avatar
deuce committed
				if(!ssjs_send_headers(session,FALSE)) {
		if((str=JS_ValueToString(cx, argv[i]))==NULL)
			continue;
deuce's avatar
deuce committed
		JSSTRING_TO_RASTRING(cx, str, cstr, &cstr_sz, &len);
		HANDLE_PENDING(cx, cstr);
deuce's avatar
deuce committed
		js_writebuf(session, cstr, len);
		if(writeln)
			js_writebuf(session, newline, 2);
deuce's avatar
deuce committed
	if(cstr)
		free(cstr);
deuce's avatar
deuce committed
		JS_SET_RVAL(cx,arglist,JSVAL_VOID);
deuce's avatar
deuce committed
		JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(str));
js_write(JSContext *cx, uintN argc, jsval *arglist)
deuce's avatar
deuce committed
	js_writefunc(cx, argc, arglist, FALSE);
js_writeln(JSContext *cx, uintN argc, jsval *arglist)
deuce's avatar
deuce committed
	js_writefunc(cx, argc, arglist,TRUE);
deuce's avatar
deuce committed
static JSBool
js_set_cookie(JSContext *cx, uintN argc, jsval *arglist)
	jsval *argv=JS_ARGV(cx, arglist);
deuce's avatar
deuce committed
	char	header_buf[8192];
	char	*header;
deuce's avatar
deuce committed
	int32	i;
rswindell's avatar
rswindell committed
	JSBool	b;
deuce's avatar
deuce committed
	struct tm tm;
	http_session_t* session;
deuce's avatar
deuce committed
	time_t	tt;
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

deuce's avatar
deuce committed
	if((session=(http_session_t*)JS_GetContextPrivate(cx))==NULL)
		return(JS_FALSE);

	if(argc<2)
		return(JS_FALSE);

	header=header_buf;
deuce's avatar
deuce committed
	JSVALUE_TO_MSTRING(cx, argv[0], p, NULL);
deuce's avatar
deuce committed
	if(!p)
		return(JS_FALSE);
	header+=sprintf(header,"Set-Cookie: %s=",p);
deuce's avatar
deuce committed
	JSVALUE_TO_MSTRING(cx, argv[1], p, NULL);
deuce's avatar
deuce committed
	if(!p)
		return(JS_FALSE);
	header+=sprintf(header,"%s",p);
	FREE_AND_NULL(p);
deuce's avatar
deuce committed
	if(argc>2) {
		if(!JS_ValueToInt32(cx,argv[2],&i))
			return JS_FALSE;
deuce's avatar
deuce committed
		tt=i;
		if(i && gmtime_r(&tt,&tm)!=NULL)
deuce's avatar
deuce committed
			header += strftime(header,50,"; expires=%a, %d-%b-%Y %H:%M:%S GMT",&tm);
	}
	if(argc>3) {
deuce's avatar
deuce committed
		JSVALUE_TO_MSTRING(cx, argv[3], p, NULL);
		if(p!=NULL && *p) {
deuce's avatar
deuce committed
			header += sprintf(header,"; domain=%s",p);
		FREE_AND_NULL(p);
deuce's avatar
deuce committed
	}
	if(argc>4) {
deuce's avatar
deuce committed
		JSVALUE_TO_MSTRING(cx, argv[4], p, NULL);
		if(p!=NULL && *p) {
deuce's avatar
deuce committed
			header += sprintf(header,"; path=%s",p);
		FREE_AND_NULL(p);
deuce's avatar
deuce committed
	}
	if(argc>5) {
rswindell's avatar
rswindell committed
		JS_ValueToBoolean(cx, argv[5], &b);
		if(b)
deuce's avatar
deuce committed
			header += sprintf(header,"; secure");
	}
	strListPush(&session->req.dynamic_heads,header_buf);

	return(JS_TRUE);
}

js_log(JSContext *cx, uintN argc, jsval *arglist)
	jsval *argv=JS_ARGV(cx, arglist);
	char		str[512];
    uintN		i=0;
	int32		level=LOG_INFO;
	http_session_t* session;
deuce's avatar
deuce committed
	jsrefcount	rc;
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

	if((session=(http_session_t*)JS_GetContextPrivate(cx))==NULL)
		return(JS_FALSE);

	if(startup==NULL || startup->lputs==NULL)
		return(JS_FALSE);
	if(argc > 1 && JSVAL_IS_NUMBER(argv[i])) {
		if(!JS_ValueToInt32(cx,argv[i++],&level))
			return JS_FALSE;
	}

	str[0]=0;
    for(;i<argc && strlen(str)<(sizeof(str)/2);i++) {
		char* tp=strchr(str, 0);
		JSVALUE_TO_STRBUF(cx, argv[i], tp, sizeof(str)/2, NULL);
	lprintf(level,"%04d %s",session->socket,str);
	JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(JS_NewStringCopyZ(cx, str)));
js_login(JSContext *cx, uintN argc, jsval *arglist)
	jsval *argv=JS_ARGV(cx, arglist);
	char*		p;
	JSBool		inc_logons=JS_FALSE;
	user_t		user;
	http_session_t*	session;
deuce's avatar
deuce committed
	jsrefcount	rc;
	JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(JS_FALSE));

	if((session=(http_session_t*)JS_GetContextPrivate(cx))==NULL)
		return(JS_FALSE);

	/* User name */
deuce's avatar
deuce committed
	JSVALUE_TO_ASTRING(cx, argv[0], p, (LEN_ALIAS > LEN_NAME) ? LEN_ALIAS+2 : LEN_NAME+2, NULL);
		user.number=atoi(p);
	else if(*p)
		user.number=matchuser(&scfg,p,FALSE);

	if(getuserdat(&scfg,&user)!=0) {
		lprintf(LOG_NOTICE,"%04d !USER NOT FOUND: '%s'"
			,session->socket,p);
		return(JS_TRUE);
	}

	if(user.misc&(DELETED|INACTIVE)) {
		lprintf(LOG_WARNING,"%04d !DELETED OR INACTIVE USER #%d: %s"
			,session->socket,user.number,p);
deuce's avatar
deuce committed
		JSVALUE_TO_ASTRING(cx, argv[1], p, LEN_PASS+2, NULL);
			return(JS_FALSE);

		if(stricmp(user.pass,p)) { /* Wrong password */
			lprintf(LOG_WARNING,"%04d !INVALID PASSWORD ATTEMPT FOR USER: '%s'"
			return(JS_TRUE);
		}
	}

	if(argc>2)
		JS_ValueToBoolean(cx,argv[2],&inc_logons);

	if(inc_logons) {
		user.logons++;
		user.ltoday++;
	}

	http_logon(session, &user);

rswindell's avatar
rswindell committed
	if(!js_CreateUserObjects(session->js_cx, session->js_glob, &scfg, &session->user, &session->client
		,NULL /* ftp index file */, session->subscan /* subscan */)) {
		lprintf(LOG_ERR,"%04d !JavaScript ERROR creating user objects",session->socket);
		send_error(session,__LINE__,"500 Error initializing JavaScript User Objects");
	JS_SET_RVAL(cx, arglist,BOOLEAN_TO_JSVAL(JS_TRUE));
#if 0
static char *find_next_pair(char *buffer, size_t buflen, char find)
{
	char	*p;
	char	*search;
	char	*end;
	size_t	buflen2;
	char	chars[5]="@%^<";

	end=buffer+buflen;
	search=buffer;
	buflen2=buflen;

	for(;search<end;) {
		p=memchr(search, chars[i], buflen2);
		/* Can't even find one... there's definatly no pair */
		if(p==NULL)
			return(NULL);

		if(*(p+1)==find)
			return(p);

		/* Next search pos is at the char after the match */
		search=p+1;
		buflen2=end-search;
	}
}

static void js_write_escaped(JSContext *cx, JSObject *obj, char *pos, size_t len, char *name_end, char *repeat_section)
{
	char	*name=pos+2;

}

enum {
	 T_AT
	,T_PERCENT
	,T_CARET
	,T_LT
};

static int js_write_template_part(JSContext *cx, JSObject *obj, char *template, size_t len, char *repeat_section)
{
	size_t		len2;
	char		*pos;
	char		*end;
	char		*p;
	char		*p2;
	char		*send_end;
	int			no_more[4];
	char		*next[4];
	int			i,j;
	char		chars[5]="@%^<";

	end=template+len;
	pos=template;
	memset(&next,0,sizeof(next));
	memset(&no_more,0,sizeof(no_more));

	while(pos<end) {
		send_end=NULL;

		/* Find next seperator */
		for(i=0; i<4; i++) {
			if(!no_more[i]) {
				if(next[i] < pos)
					next[i]=NULL;
				if(next[i] == NULL) {
					if((next[i]=find_next_pair(pos, len, chars[i]))==NULL) {
						no_more[i]=TRUE;
						continue;
					}
				}
				if(!send_end || next[i] < send_end)
					send_end=next[i];
			}
		}
		if(send_end==NULL) {
			/* Nothing else matched... we're good now! */
			js_writebuf(session, pos, len);
			pos=end;
			len=0;
			continue;
		}
		if(send_end > pos) {
			i=send_end-pos;
			js_writebuf(session, pos, i);
			pos+=i;
			len-=i;
		}

		/*
		 * At this point, pos points to a matched introducer.
		 * If it's not a repeat section, we can just output it here.
		 */
		if(*pos != '<') {
			/*
			 * If there is no corresponding terminator to this introdcer,
			 * force it to be output unchanged.
			 */
			if((p=find_next_pair(pos, len, *pos))==NULL) {
				no_more[strchr(chars,*pos)-char]=TRUE;
				continue;
			}
			js_write_escaped(cx, obj, pos, len, p, repeat_section);
			continue;
		}

		/*
		 * Pos is the start of a repeat section now... this is where things
		 * start to get tricky.  Set up RepeatObj object, then call self
		 * once for each repeat.
		 */
	}
}

static JSBool
js_write_template(JSContext *cx, uintN argc, jsval *arglist)
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
	JSString*	js_str;
	char		*filename;
	char		*template;
	FILE		*tfile;
	size_t		len;
	http_session_t* session;

	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

	if((session=(http_session_t*)JS_GetContextPrivate(cx))==NULL)
		return(JS_FALSE);

	if(session->req.fp==NULL)
		return(JS_FALSE);

deuce's avatar
deuce committed
	JSVALUE_TO_MSTRING(cx, argv[0], filename, NULL);
	if(filename==NULL)
		return(JS_FALSE);

	if(!fexist(filename)) {
deuce's avatar
deuce committed
		free(filename);
		JS_ReportError(cx, "Template file %s does not exist.", filename);
		return(JS_FALSE);
	}
	len=flength(filename);

	if((tfile=fopen(filename,"r"))==NULL) {
deuce's avatar
deuce committed
		free(filename);
		JS_ReportError(cx, "Unable to open template %s for read.", filename);
		return(JS_FALSE);
	}
deuce's avatar
deuce committed
	free(filename);
deuce's avatar
deuce committed
	if((template=(char *)malloc(len))==NULL) {
		JS_ReportError(cx, "Unable to allocate %u bytes for template.", len);
		return(JS_FALSE);
	}

	if(fread(template, 1, len, tfile) != len) {
deuce's avatar
deuce committed
		free(template);
		fclose(tfile);
		JS_ReportError(cx, "Unable to read %u bytes from template %s.", len, filename);
		return(JS_FALSE);
	}
	fclose(tfile);

	if((!session->req.prev_write) && (!session->req.sent_headers)) {
		if(session->http_ver>=HTTP_1_1 && session->req.keep_alive) {
deuce's avatar
deuce committed
			if(!ssjs_send_headers(session,TRUE)) {
				free(template);
		}
		else {
			/* "Fast Mode" requested? */
			jsval		val;
			JSObject*	reply;
			JS_GetProperty(cx, session->js_glob, "http_reply", &val);
			reply=JSVAL_TO_OBJECT(val);
			JS_GetProperty(cx, reply, "fast", &val);
			if(JSVAL_IS_BOOLEAN(val) && JSVAL_TO_BOOLEAN(val)) {
				session->req.keep_alive=FALSE;
deuce's avatar
deuce committed
				if(!ssjs_send_headers(session,FALSE)) {
					free(template);
			}
		}
	}

	session->req.prev_write=TRUE;
	js_write_template_part(cx, obj, template, len, NULL);
deuce's avatar
deuce committed
	free(template);
static JSFunctionSpec js_global_functions[] = {
	{"write",           js_write,           1},		/* write to HTML file */
	{"writeln",         js_writeln,         1},		/* write line to HTML file */
	{"print",			js_writeln,			1},		/* write line to HTML file (alias) */
	{"log",				js_log,				0},		/* Log a string */
	{"login",           js_login,           2},		/* log in as a different user */
deuce's avatar
deuce committed
	{"set_cookie",		js_set_cookie,		2},		/* Set a cookie */
js_OperationCallback(JSContext *cx)
	JS_SetOperationCallback(cx, NULL);
	if((session=(http_session_t*)JS_GetContextPrivate(cx))==NULL) {
		JS_SetOperationCallback(cx, js_OperationCallback);
    ret=js_CommonOperationCallback(cx,&session->js_callback);
	JS_SetOperationCallback(cx, js_OperationCallback);
js_initcx(http_session_t *session)
	lprintf(LOG_DEBUG,"%04d JavaScript: Initializing context (stack: %lu bytes)"
		,session->socket,startup->js.cx_stack);
    if((js_cx = JS_NewContext(session->js_runtime, startup->js.cx_stack))==NULL)
	lprintf(LOG_DEBUG,"%04d JavaScript: Context created",session->socket);

    JS_SetErrorReporter(js_cx, js_ErrorReporter);

	JS_SetOperationCallback(js_cx, js_OperationCallback);
	lprintf(LOG_DEBUG,"%04d JavaScript: Creating Global Objects and Classes",session->socket);
	if(!js_CreateCommonObjects(js_cx, &scfg, NULL
									,NULL						/* global */
									,uptime						/* system */
									,startup->host_name			/* system */
									,SOCKLIB_DESC				/* system */
									,&startup->js				/* js */
									,&session->client			/* client */
									,session->socket			/* client */
									,session->tls_sess			/* client */
		|| !JS_DefineFunctions(js_cx, session->js_glob, js_global_functions)) {
		JS_RemoveObjectRoot(js_cx, &session->js_glob);
static BOOL js_setup_cx(http_session_t* session)
	if(session->js_runtime == NULL) {
		lprintf(LOG_DEBUG,"%04d JavaScript: Creating runtime: %lu bytes"
			,session->socket,startup->js.max_bytes);
		if((session->js_runtime=jsrt_GetNew(startup->js.max_bytes, 5000, __FILE__, __LINE__))==NULL) {
			lprintf(LOG_ERR,"%04d !ERROR creating JavaScript runtime",session->socket);
			return(FALSE);
		}
	}

	if(session->js_cx==NULL) {	/* Context not yet created, create it now */
		/* js_initcx() begins a context */
		if(((session->js_cx=js_initcx(session))==NULL)) {
			lprintf(LOG_ERR,"%04d !ERROR initializing JavaScript context",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);

		JS_DefineProperty(session->js_cx, session->js_glob, "web_root_dir",
			STRING_TO_JSVAL(JS_NewStringCopyZ(session->js_cx, root_dir))
			,NULL,NULL,JSPROP_READONLY|JSPROP_ENUMERATE);
		JS_DefineProperty(session->js_cx, session->js_glob, "web_error_dir",
			STRING_TO_JSVAL(JS_NewStringCopyZ(session->js_cx, session->req.error_dir?session->req.error_dir:error_dir))
			,NULL,NULL,JSPROP_READONLY|JSPROP_ENUMERATE);
		JS_ENDREQUEST(session->js_cx);
		JS_BEGINREQUEST(session->js_cx);
	lprintf(LOG_DEBUG,"%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);
		JS_ENDREQUEST(session->js_cx);
	JS_SetContextPrivate(session->js_cx, session);

	return TRUE;
}

static BOOL js_setup(http_session_t* session)
{
	if(!js_setup_cx(session))
		return FALSE;

	lprintf(LOG_DEBUG,"%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);
		JS_ENDREQUEST(session->js_cx);
static BOOL ssjs_send_headers(http_session_t* session,int chunked)
	jsval		val;
	JSObject*	reply;
	JSIdArray*	heads;
	JSObject*	headers;
deuce's avatar
deuce committed
	char		*p=NULL,*p2=NULL;
	size_t		p_sz=0, p2_sz=0;
	JS_BEGINREQUEST(session->js_cx);
	JS_GetProperty(session->js_cx,session->js_glob,"http_reply",&val);
	reply = JSVAL_TO_OBJECT(val);
	JS_GetProperty(session->js_cx,reply,"status",&val);
deuce's avatar
deuce committed
	JSVALUE_TO_STRBUF(session->js_cx, val, session->req.status, sizeof(session->req.status), NULL);
	JS_GetProperty(session->js_cx,reply,"header",&val);
	headers = JSVAL_TO_OBJECT(val);
	heads=JS_Enumerate(session->js_cx,headers);
deuce's avatar
deuce committed
	if(heads != NULL) {
		for(i=0;i<heads->length;i++)  {
			JS_IdToValue(session->js_cx,heads->vector[i],&val);
deuce's avatar
deuce committed
			JSVALUE_TO_RASTRING(session->js_cx, val, p, &p_sz, NULL);
			if(p==NULL) {
				if(p)
					free(p);
				if(p2)
					free(p2);
				return FALSE;
			}
deuce's avatar
deuce committed
			JS_GetProperty(session->js_cx,headers,p,&val);
deuce's avatar
deuce committed
			JSVALUE_TO_RASTRING(session->js_cx, val, p2, &p2_sz, NULL);
			if(JS_IsExceptionPending(session->js_cx)) {
				if(p)
					free(p);
				if(p2)
					free(p2);
				return FALSE;
			}
			h = get_header_type(p);
			switch(h) {
			case HEAD_LOCATION:
				if (*p2 == '/') {
					unescape(p2);
					SAFECOPY(session->req.virtual_path,p2);
					session->req.send_location=MOVED_STAT;
				}
				else {
					SAFECOPY(session->req.virtual_path,p2);
					session->req.send_location=MOVED_TEMP;
				}
				if (atoi(session->req.status) == 200)
					SAFECOPY(session->req.status, error_302);
				break;
			case HEAD_LENGTH:
			case HEAD_TRANSFER_ENCODING:
				/* If either of these are manually set, point
				 * the gun at the script writers foot for them */
				chunked = false;
				session->req.manual_length = TRUE;
			default:
				safe_snprintf(str,sizeof(str),"%s: %s",p,p2);
				strListPush(&session->req.dynamic_heads,str);
			}
deuce's avatar
deuce committed
		}
deuce's avatar
deuce committed
		if(p)
			free(p);
		if(p2)
			free(p2);
		JS_ClearScope(session->js_cx, headers);
	JS_ENDREQUEST(session->js_cx);
	return(send_headers(session,session->req.status,chunked));
static BOOL exec_ssjs(http_session_t* session, char* script)  {
	jsval		rval;
	char		path[MAX_PATH+1];
	BOOL		retval=TRUE;
	/* External JavaScript handler? */
	if(script == session->req.physical_path && session->req.xjs_handler[0])
		script = session->req.xjs_handler;

	sprintf(path,"%sSBBS_SSJS.%u.%u.html",temp_dir,getpid(),session->socket);
	if((session->req.fp=fopen(path,"wb"))==NULL) {
		lprintf(LOG_ERR,"%04d !ERROR %d opening/creating %s", session->socket, errno, path);
		return(FALSE);
	}
deuce's avatar
deuce committed
	if(session->req.cleanup_file[CLEANUP_SSJS_TMP_FILE]) {
		if(!(startup->options&WEB_OPT_DEBUG_SSJS))
			remove(session->req.cleanup_file[CLEANUP_SSJS_TMP_FILE]);
		free(session->req.cleanup_file[CLEANUP_SSJS_TMP_FILE]);
	}
	/* FREE()d in close_request() */
	session->req.cleanup_file[CLEANUP_SSJS_TMP_FILE]=strdup(path);
	JS_BEGINREQUEST(session->js_cx);
	js_add_request_prop(session,"real_path",session->req.physical_path);
	js_add_request_prop(session,"virtual_path",session->req.virtual_path);
	js_add_request_prop(session,"ars",session->req.ars);
	js_add_request_prop(session,"request_string",session->req.request_line);
	js_add_request_prop(session,"host",session->req.host);
	js_add_request_prop(session,"vhost",session->req.vhost);
	js_add_request_prop(session,"http_ver",http_vers[session->http_ver]);
	js_add_request_prop(session,"remote_ip",session->host_ip);
	js_add_request_prop(session,"remote_host",session->host_name);
deuce's avatar
deuce committed
	if(session->req.query_str[0])  {
		js_add_request_prop(session,"query_string",session->req.query_str);
		js_parse_query(session,session->req.query_str);
	}
	if(session->req.post_data && session->req.post_data[0]) {
		if(session->req.post_len <= MAX_POST_LEN) {
			js_add_request_property(session, "post_data", session->req.post_data, session->req.post_len, /* writeable: */false);
			js_parse_query(session,session->req.post_data);
		}
	parse_js_headers(session);

	do {
		/* RUN SCRIPT */
		JS_ClearPendingException(session->js_cx);

		lprintf(LOG_DEBUG,"%04d JavaScript: Compiling script: %s",session->socket,script);
		if((js_script=JS_CompileFile(session->js_cx, session->js_glob
			lprintf(LOG_ERR,"%04d !JavaScript FAILED to compile script (%s)"
			JS_RemoveObjectRoot(session->js_cx, &session->js_glob);
			JS_ENDREQUEST(session->js_cx);
		lprintf(LOG_DEBUG,"%04d JavaScript: Executing script: %s",session->socket,script);
		js_PrepareToExecute(session->js_cx, session->js_glob, script, /* startup_dir */NULL, session->js_glob);
		JS_ExecuteScript(session->js_cx, session->js_glob, js_script, &rval);
		js_EvalOnExit(session->js_cx, session->js_glob, &session->js_callback);
		JS_RemoveObjectRoot(session->js_cx, &session->js_glob);
		lprintf(LOG_DEBUG,"%04d JavaScript: Done executing script: %s (%.2Lf seconds)"
			,session->socket,script,xp_timer()-start);
	SAFECOPY(session->req.physical_path, path);
	if(session->req.fp!=NULL) {
		fclose(session->req.fp);
		session->req.fp=NULL;
	}


	/* Read http_reply object */
	if(!session->req.sent_headers)
		retval=ssjs_send_headers(session,FALSE);

	/* Free up temporary resources here */

	session->req.dynamic=IS_SSJS;
	JS_ENDREQUEST(session->js_cx);
static void respond(http_session_t * session)
{
	if(session->req.method==HTTP_OPTIONS)
		send_headers(session,session->req.status,FALSE);
		if(session->req.dynamic==IS_FASTCGI)  {
			if(!exec_fastcgi(session)) {
				send_error(session,__LINE__,error_500);
				return;
			}
			session->req.finished=TRUE;
			return;
		}

		if(session->req.dynamic==IS_CGI)  {
			if(!exec_cgi(session))  {
				send_error(session,__LINE__,error_500);
				return;
			}
			session->req.finished=TRUE;
		if(session->req.dynamic==IS_SSJS) {	/* Server-Side JavaScript */
			if(!exec_ssjs(session,session->req.physical_path))  {
				send_error(session,__LINE__,error_500);
				return;
			}
			sprintf(session->req.physical_path
				,"%sSBBS_SSJS.%u.%u.html",temp_dir,getpid(),session->socket);
		}
		else {
			session->req.mime_type=get_mime_type(strrchr(session->req.physical_path,'.'));
			send_headers(session,session->req.status,FALSE);
	if(session->req.send_content)  {
		lprintf(LOG_INFO,"%04d Sending file: %s (%"PRIuOFF" bytes)"
			,session->socket, session->req.physical_path, flength(session->req.physical_path));
		snt=sock_sendfile(session,session->req.physical_path,session->req.range_start,session->req.range_end);
		if(session->req.ld!=NULL) {
			if(snt<0)
				snt=0;
			session->req.ld->size=snt;
		}
			lprintf(LOG_INFO,"%04d Sent file: %s (%d bytes)"
				,session->socket, session->req.physical_path, snt);
	session->req.finished=TRUE;
BOOL post_to_file(http_session_t *session, FILE*fp, size_t ch_len)
{
	char		buf[20*1024];
	size_t		k;
	int			bytes_read;

	for(k=0; k<ch_len;) {
deuce's avatar
deuce committed
		bytes_read=recvbufsocket(session,buf,(ch_len-k)>sizeof(buf)?sizeof(buf):(ch_len-k));
			send_error(session,__LINE__,error_500);
			fclose(fp);
			return(FALSE);
		}
		if(fwrite(buf, bytes_read, 1, fp)!=1) {
			send_error(session,__LINE__,error_500);
			fclose(fp);
			return(FALSE);
		}
		k+=bytes_read;
		session->req.post_len+=bytes_read;
	}
	return TRUE;
}

FILE *open_post_file(http_session_t *session)
{
	char	path[MAX_PATH+1];
	FILE	*fp;

	// Create temporary file for post data.
	SAFEPRINTF3(path,"%sSBBS_POST.%u.%u.data",temp_dir,getpid(),session->socket);
	if((fp=fopen(path,"wb"))==NULL) {
		lprintf(LOG_ERR,"%04d !ERROR %d opening/creating %s", session->socket, errno, path);
		return fp;
	}
	if(session->req.cleanup_file[CLEANUP_POST_DATA]) {
		remove(session->req.cleanup_file[CLEANUP_POST_DATA]);
		free(session->req.cleanup_file[CLEANUP_POST_DATA]);
	}
	/* remove()d in close_request() */
	session->req.cleanup_file[CLEANUP_POST_DATA]=strdup(path);
	if(session->req.post_data != NULL) {
		if(fwrite(session->req.post_data, session->req.post_len, 1, fp)!=1) {
			lprintf(LOG_ERR,"%04d !ERROR writeing to %s", session->socket, path);
			fclose(fp);
			return(FALSE);
		}
		FREE_AND_NULL(session->req.post_data);
int read_post_data(http_session_t * session)
{
	if(session->req.dynamic!=IS_CGI && (session->req.post_len || session->req.read_chunked)) {
		if(session->req.read_chunked) {
			char *p;
			size_t	ch_len=0;
			int	bytes_read=0;
			char	ch_lstr[12];
			session->req.post_len=0;

			while(1) {
				/* Read chunk length */
				if(sockreadline(session,ch_lstr,sizeof(ch_lstr)-1)>0) {
					ch_len=strtol(ch_lstr,NULL,16);
				}
				else {
					send_error(session,__LINE__,error_500);
					return(FALSE);
				}
				if(ch_len==0)
					break;
				/* Check size */
				s += ch_len;
				if(s > MAX_POST_LEN) {
					if(s > SIZE_MAX) {
						send_error(session,__LINE__,"413 Request entity too large");
						if(fp) fclose(fp);
						return(FALSE);
					}
					if(fp==NULL) {
						fp=open_post_file(session);
						if(fp==NULL)
							return(FALSE);