Newer
Older
if(session->req.finished)
return(FALSE);
SAFECOPY(path,session->req.physical_path);
lprintf(LOG_DEBUG,"%04d Path is: %s",session->socket,path);
if(isdir(path)) {
last_ch=*lastchar(path);
if(!IS_PATH_DELIM(last_ch)) {
last_ch=*lastchar(session->req.virtual_path);
if(!IS_PATH_DELIM(last_ch)) {
strcat(session->req.virtual_path,"/");
}
last_slash=find_last_slash(path);
send_error(session,error_500);
last_slash++;
for(i=0; startup->index_file_name!=NULL && startup->index_file_name[i]!=NULL ;i++) {
*last_slash=0;
strcat(path,startup->index_file_name[i]);
lprintf(LOG_DEBUG,"%04d Checking for %s",session->socket,path);
/* Don't send 404 unless authourized... prevent info leak */
if(startup->index_file_name[i] == NULL)
send404=1;
else {
strcat(session->req.virtual_path,startup->index_file_name[i]);
if(session->req.send_location != MOVED_PERM)
session->req.send_location=MOVED_STAT;
if(strnicmp(path,root_dir,strlen(root_dir))) {
session->req.keep_alive=FALSE;
send_error(session,"400 Bad Request");
lprintf(LOG_NOTICE,"%04d !ERROR Request for %s is outside of web root %s"
,session->socket,path,root_dir);
return(FALSE);
}
/* Set default ARS to a 0-length string */
session->req.ars[0]=0;
/* Walk up from root_dir checking for access.ars */
SAFECOPY(str,path);
last_slash=str+strlen(root_dir)-1;
/* Loop while there's more /s in path*/
while((last_slash=find_first_slash(p+1))!=NULL) {
/* Terminate the path after the slash */
*(last_slash+1)=0;
strcat(str,"access.ars");
if(!strcmp(path,str)) {
send_error(session,"403 Forbidden");
return(FALSE);
}
/* Read access.ars file */
if((file=fopen(str,"r"))!=NULL) {
fgets(session->req.ars,sizeof(session->req.ars),file);
fclose(file);
}
else {
/* If cannot open access.ars, only allow sysop access */
SAFECOPY(session->req.ars,"LEVEL 90");
break;
}
/* Truncate at \r or \n - can use last_slash since I'm done with it.*/
truncsp(session->req.ars);
}
SAFECOPY(str,path);
}
if(!check_ars(session)) {
/* No authentication provided */
sprintf(str,"401 Unauthorized%s%s: Basic realm=\"%s\""
,newline,get_header(HEAD_WWWAUTH),scfg.sys_name);
send_error(session,str);
return(FALSE);
if(stat(path,&sb) || IS_PATH_DELIM(*(lastchar(path))) || send404) {
/* OPTIONS requests never return 404 errors (ala Apache) */
if(session->req.method!=HTTP_OPTIONS) {
if(startup->options&WEB_OPT_DEBUG_TX)
lprintf(LOG_DEBUG,"%04d 404 - %s does not exist",session->socket,path);
send_error(session,error_404);
return(FALSE);
}
}
SAFECOPY(session->req.physical_path,path);
add_env(session,"SCRIPT_NAME",session->req.virtual_path);
add_env(session,"SCRIPT_FILENAME",session->req.physical_path);
SAFECOPY(str,session->req.virtual_path);
last_slash=find_last_slash(str);
if(last_slash!=NULL)
*(last_slash+1)=0;
if(*(session->req.extra_path_info))
{
sprintf(str,"%s%s",startup->root_dir,session->req.extra_path_info);
add_env(session,"PATH_TRANSLATED",str);
add_env(session,"PATH_INFO",session->req.extra_path_info);
}
return(TRUE);
}
static str_list_t get_cgi_env(http_session_t *session)
{
char path[MAX_PATH+1];
char value[INI_MAX_VALUE_LEN+1];
char* deflt;
char defltbuf[INI_MAX_VALUE_LEN+1];
char append[INI_MAX_VALUE_LEN+1];
char prepend[INI_MAX_VALUE_LEN+1];
char env_str[(INI_MAX_VALUE_LEN*4)+2];
FILE* fp;
size_t i;
str_list_t env_list;
str_list_t add_list;
if((env_list=strListInit())==NULL)
return(NULL);
strListAppendList(&env_list, session->req.cgi_env);
strListPush(&env_list,"REDIRECT_STATUS=200"); /* Kludge for php-cgi */
if((fp=iniOpenFile(iniFileName(path,sizeof(path),scfg.ctrl_dir,"cgi_env.ini"),/* create? */FALSE))==NULL)
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
return(env_list);
if((add_list=iniReadSectionList(fp,NULL))!=NULL) {
for(i=0; add_list[i]!=NULL; i++) {
if((deflt=getenv(add_list[i]))==NULL)
deflt=iniReadString(fp,add_list[i],"default",NULL,defltbuf);
if(iniReadString(fp,add_list[i],"value",deflt,value)==NULL)
continue;
iniReadString(fp,add_list[i],"append","",append);
iniReadString(fp,add_list[i],"prepend","",prepend);
safe_snprintf(env_str,sizeof(env_str),"%s=%s%s%s"
,add_list[i], prepend, value, append);
strListPush(&env_list,env_str);
}
strListFree(&add_list);
}
fclose(fp);
return(env_list);
}
static BOOL exec_cgi(http_session_t *session)
char cmdline[MAX_PATH+256];
/* ToDo: Damn, that's WAY too many variables */
int i=0;
int status=0;
pid_t child=0;
int out_pipe[2];
int err_pipe[2];
fd_set read_set;
fd_set write_set;
BOOL done_parsing_headers=FALSE;
BOOL done_reading=FALSE;
char cgi_status[MAX_REQUEST_LINE+1];
char header[MAX_REQUEST_LINE+1];
char *directive=NULL;
char *value=NULL;
BOOL done_wait=FALSE;
BOOL got_valid_headers=FALSE;
time_t start;
char cgipath[MAX_PATH+1];
char *p;
size_t idx;
SAFECOPY(cmdline,session->req.physical_path);
lprintf(LOG_INFO,"%04d Executing CGI: %s",session->socket,cmdline);
orig_keep=session->req.keep_alive;
/* Set up I/O pipes */
if(pipe(out_pipe)!=0) {
lprintf(LOG_ERR,"%04d Can't create out_pipe",session->socket);
return(FALSE);
}
if(pipe(err_pipe)!=0) {
lprintf(LOG_ERR,"%04d Can't create err_pipe",session->socket);
return(FALSE);
}
if((child=fork())==0) {
/* Do a full suid thing. */
if(startup->setuid!=NULL)
startup->setuid(TRUE);
/* Set up STDIO */
dup2(session->socket,0); /* redirect stdin */
close(out_pipe[0]); /* close read-end of pipe */
dup2(out_pipe[1],1); /* stdout */
close(out_pipe[1]); /* close excess file descriptor */
close(err_pipe[0]); /* close read-end of pipe */
dup2(err_pipe[1],2); /* stderr */
close(err_pipe[1]); /* close excess file descriptor */
SAFECOPY(cgipath,cmdline);
if((p=strrchr(cgipath,'/'))!=NULL)
{
*p=0;
chdir(cgipath);
}
/* Execute command */
if(get_cgi_handler(cgipath, sizeof(cgipath))) {
char *comspec;
comspec=getenv("SHELL");
if(comspec==NULL)
#ifdef _PATH_BSHELL
comspec=_PATH_BSHELL;
#else
comspec="/bin/sh";
#endif
lprintf(LOG_INFO,"%04d Using handler %s to execute %s",session->socket,cgipath,cmdline);
execle(comspec,comspec,"-c",cgipath,NULL,env_list);
}
else {
execle(cmdline,cmdline,NULL,env_list);
}
lprintf(LOG_ERR,"%04d !FAILED! execle() (%d)",session->socket,errno);
exit(EXIT_FAILURE); /* Should never happen */
}
if(child==-1) {
lprintf(LOG_ERR,"%04d !FAILED! fork() errno=%d",session->socket,errno);
close(out_pipe[0]); /* close read-end of pipe */
close(err_pipe[0]); /* close read-end of pipe */
}
close(out_pipe[1]); /* close excess file descriptor */
close(err_pipe[1]); /* close excess file descriptor */
high_fd=out_pipe[0];
if(err_pipe[0]>high_fd)
high_fd=err_pipe[0];
/* ToDo: Magically set done_parsing_headers for nph-* scripts */
cgi_status[0]=0;
while(!done_reading) {
tv.tv_sec=startup->max_cgi_inactivity;
tv.tv_usec=0;
FD_ZERO(&read_set);
FD_SET(out_pipe[0],&read_set);
FD_SET(err_pipe[0],&read_set);
FD_ZERO(&write_set);
if(select(high_fd+1,&read_set,&write_set,NULL,&tv)>0) {
if(FD_ISSET(out_pipe[0],&read_set)) {
if(done_parsing_headers && got_valid_headers) {
if(i>0) {
int snt=0;
start=time(NULL);
if(session->req.method!=HTTP_HEAD) {
if(session->req.write_chunked) {
sprintf(header,"%X\r\n",i);
write(session->socket,header,strlen(header));
}
snt=write(session->socket,buf,i);
if(session->req.ld!=NULL && snt>0) {
session->req.ld->size+=snt;
if(session->req.write_chunked)
write(session->socket,newline,2);
done_reading=TRUE;
}
else {
/* This is the tricky part */
i=pipereadline(out_pipe[0],buf,sizeof(buf), fbuf, sizeof(fbuf));
if(i<0) {
done_reading=TRUE;
got_valid_headers=FALSE;
}
start=time(NULL);
if(!done_parsing_headers && *buf) {
SAFECOPY(header,buf);
directive=strtok(header,":");
if(directive != NULL) {
value=strtok(NULL,"");
i=get_header_type(directive);
switch (i) {
case HEAD_LOCATION:
got_valid_headers=TRUE;
if(*value=='/') {
unescape(value);
SAFECOPY(session->req.virtual_path,value);
session->req.send_location=MOVED_STAT;
if(cgi_status[0]==0)
SAFECOPY(cgi_status,error_302);
} else {
SAFECOPY(session->req.virtual_path,value);
session->req.send_location=MOVED_STAT;
if(cgi_status[0]==0)
SAFECOPY(cgi_status,error_302);
}
break;
case HEAD_STATUS:
SAFECOPY(cgi_status,value);
break;
case HEAD_LENGTH:
session->req.keep_alive=orig_keep;
strListPush(&session->req.dynamic_heads,buf);
break;
case HEAD_TYPE:
got_valid_headers=TRUE;
strListPush(&session->req.dynamic_heads,buf);
break;
case HEAD_TRANSFER_ENCODING:
no_chunked=TRUE;
break;
default:
strListPush(&session->req.dynamic_heads,buf);
}
}
/* Invalid header line */
done_parsing_headers=TRUE;
}
}
else {
if(!no_chunked && session->http_ver>=HTTP_1_1) {
session->req.keep_alive=orig_keep;
session->req.write_chunked=TRUE;
}
if(got_valid_headers) {
session->req.dynamic=IS_CGI;
if(cgi_status[0]==0)
SAFECOPY(cgi_status,session->req.status);
send_headers(session,cgi_status);
}
else {
/* Invalid headers... send 'er all as plain-text */
lprintf(LOG_DEBUG,"%04d Recieved invalid CGI headers, sending result as plain-text",session->socket);
/* free() the non-headers so they don't get sent, then recreate the list */
strListFreeStrings(session->req.dynamic_heads);
/* Copy current status */
SAFECOPY(cgi_status,session->req.status);
/* Add the content-type header (REQUIRED) */
SAFEPRINTF2(content_type,"%s: %s",get_header(HEAD_TYPE),startup->default_cgi_content);
strListPush(&session->req.dynamic_heads,content_type);
send_headers(session,cgi_status);
/* Now send the tmpbuf */
for(i=0; tmpbuf != NULL && tmpbuf[i] != NULL; i++) {
if(strlen(tmpbuf[i])>0) {
if(session->req.write_chunked) {
sprintf(header,"%X\r\n",strlen(tmpbuf[i]));
write(session->socket,header,strlen(header));
}
snt=write(session->socket,tmpbuf[i],strlen(tmpbuf[i]));
if(session->req.write_chunked)
write(session->socket,newline,2);
if(session->req.ld!=NULL && snt>0) {
session->req.ld->size+=snt;
}
}
}
if(strlen(fbuf)>0) {
if(session->req.write_chunked) {
sprintf(header,"%X\r\n",strlen(fbuf));
write(session->socket,header,strlen(header));
}
snt=write(session->socket,fbuf,strlen(fbuf));
if(session->req.ld!=NULL && snt>0) {
session->req.ld->size+=snt;
}
if(session->req.write_chunked)
write(session->socket,newline,2);
done_parsing_headers=TRUE;
}
}
}
if(FD_ISSET(err_pipe[0],&read_set)) {
i=read(err_pipe[0],buf,sizeof(buf)-1);
if(i>0) {
buf[i]=0;
lprintf(LOG_ERR,"%04d CGI Error: %s",session->socket,buf);
start=time(NULL);
if(!done_wait)
done_wait = (waitpid(child,&status,WNOHANG)==child);
if(!FD_ISSET(err_pipe[0],&read_set) && !FD_ISSET(out_pipe[0],&read_set) && done_wait)
done_reading=TRUE;
}
else {
if((time(NULL)-start) >= startup->max_cgi_inactivity) {
lprintf(LOG_ERR,"%04d CGI Process %s Timed out",session->socket,getfname(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);
while(select(high_fd+1,&read_set,NULL,NULL,&tv)>0) {
if(FD_ISSET(err_pipe[0],&read_set)) {
i=read(err_pipe[0],buf,sizeof(buf)-1);
if(i>0) {
buf[i]=0;
lprintf(LOG_ERR,"%04d CGI Error: %s",session->socket,buf);
start=time(NULL);
}
else
break;
}
tv.tv_sec=1;
tv.tv_usec=0;
FD_ZERO(&read_set);
FD_SET(err_pipe[0],&read_set);
if(!done_wait)
done_wait = (waitpid(child,&status,WNOHANG)==child);
if(!done_wait) {
if(start)
lprintf(LOG_NOTICE,"%04d CGI Process %s still alive on client exit"
,session->socket,getfname(cmdline));
kill(child,SIGTERM);
mswait(1000);
done_wait = (waitpid(child,&status,WNOHANG)==child);
kill(child,SIGKILL);
done_wait = (waitpid(child,&status,0)==child);
}
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 Process %s did not generate valid headers"
,session->socket,getfname(cmdline));
return(FALSE);
}
if(!done_parsing_headers) {
lprintf(LOG_ERR,"%04d CGI Process %s did not send data header termination"
,session->socket,getfname(cmdline));
return(FALSE);
return(TRUE);
/* Win32 exec_cgi() */
/* These are (more or less) copied from the Unix version */
char* p;
char cmdline[MAX_PATH+256];
char buf[4096];
int i;
BOOL orig_keep;
BOOL done_parsing_headers=FALSE;
BOOL got_valid_headers=FALSE;
char cgi_status[MAX_REQUEST_LINE+1];
char content_type[MAX_REQUEST_LINE+1];
char header[MAX_REQUEST_LINE+1];
char *directive=NULL;
char *value=NULL;
time_t start;
/* Win32-specific */
char startup_dir[MAX_PATH+1];
int wr;
HANDLE rdpipe=INVALID_HANDLE_VALUE;
HANDLE wrpipe=INVALID_HANDLE_VALUE;
HANDLE rdoutpipe;
HANDLE wrinpipe;
DWORD waiting;
DWORD msglen;
DWORD retval;
BOOL process_terminated=FALSE;
PROCESS_INFORMATION process_info;
SECURITY_ATTRIBUTES sa;
STARTUPINFO startup_info={0};
str_list_t env_list;
startup_info.cb=sizeof(startup_info);
startup_info.dwFlags|=STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
startup_info.wShowWindow=SW_HIDE;
SAFECOPY(cmdline,session->req.physical_path);
SAFECOPY(startup_dir,cmdline);
if((p=strrchr(startup_dir,'/'))!=NULL || (p=strrchr(startup_dir,'\\'))!=NULL)
*p=0;
else
SAFECOPY(startup_dir,cgi_dir);
lprintf(LOG_DEBUG,"%04d CGI startup dir: %s", session->socket, startup_dir);
get_cgi_handler(cmdline, sizeof(cmdline));
lprintf(LOG_INFO,"%04d Executing CGI: %s",session->socket,cmdline);
orig_keep=session->req.keep_alive;
session->req.keep_alive=FALSE;
memset(&sa,0,sizeof(sa));
sa.nLength= sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
/* Create the child output pipe (override default 4K buffer size) */
if(!CreatePipe(&rdoutpipe,&startup_info.hStdOutput,&sa,sizeof(buf))) {
lprintf(LOG_ERR,"%04d !ERROR %d creating stdout pipe",session->socket,GetLastError());
return(FALSE);
}
startup_info.hStdError=startup_info.hStdOutput;
if(!CreatePipe(&startup_info.hStdInput,&wrinpipe,&sa,0 /* default buffer size */)) {
lprintf(LOG_ERR,"%04d !ERROR %d creating stdin pipe",session->socket,GetLastError());
return(FALSE);
}
DuplicateHandle(
GetCurrentProcess(), rdoutpipe,
GetCurrentProcess(), &rdpipe, 0, FALSE, DUPLICATE_SAME_ACCESS);
DuplicateHandle(
GetCurrentProcess(), wrinpipe,
GetCurrentProcess(), &wrpipe, 0, FALSE, DUPLICATE_SAME_ACCESS);
CloseHandle(rdoutpipe);
CloseHandle(wrinpipe);
env_list=get_cgi_env(session);
env_block = strListCreateBlock(env_list);
strListFree(&env_list);
NULL, /* pointer to name of executable module */
cmdline, /* pointer to command line string */
NULL, /* process security attributes */
NULL, /* thread security attributes */
TRUE, /* handle inheritance flag */
CREATE_NEW_CONSOLE, /* creation flags */
env_block, /* pointer to new environment block */
startup_dir, /* pointer to current directory name */
&startup_info, /* pointer to STARTUPINFO */
&process_info /* pointer to PROCESS_INFORMATION */
);
strListFreeBlock(env_block);
if(!success) {
lprintf(LOG_ERR,"%04d !ERROR %d running %s",session->socket,GetLastError(),cmdline);
return(FALSE);
}
start=time(NULL);
SAFECOPY(cgi_status,session->req.status);
SAFEPRINTF2(content_type,"%s: %s",get_header(HEAD_TYPE),startup->default_cgi_content);
while(server_socket!=INVALID_SOCKET) {
if(WaitForSingleObject(process_info.hProcess,0)==WAIT_OBJECT_0)
process_terminated=TRUE; /* handle remaining data in pipe before breaking */
if((time(NULL)-start) >= startup->max_cgi_inactivity) {
lprintf(LOG_WARNING,"%04d CGI Process %s timed out after %u seconds of inactivity"
,session->socket,getfname(cmdline),startup->max_cgi_inactivity);
break;
}
waiting = 0;
PeekNamedPipe(
rdpipe, /* handle to pipe to copy from */
NULL, /* pointer to data buffer */
0, /* size, in bytes, of data buffer */
NULL, /* pointer to number of bytes read */
&waiting, /* pointer to total number of bytes available */
NULL /* pointer to unread bytes in this message */
);
if(!waiting) {
if(process_terminated)
break;
Sleep(1);
continue;
}
/* reset inactivity timer */
start=time(NULL);
msglen=0;
if(done_parsing_headers) {
if(ReadFile(rdpipe,buf,sizeof(buf),&msglen,NULL)==FALSE) {
lprintf(LOG_ERR,"%04d !ERROR %d reading from pipe"
,session->socket,GetLastError());
break;
}
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
}
else {
/* This is the tricky part */
buf[0]=0;
i=pipereadline(rdpipe,buf,sizeof(buf),NULL,0);
if(i<0) {
lprintf(LOG_WARNING,"%04d CGI pipereadline returned %d",session->socket,i);
got_valid_headers=FALSE;
break;
}
lprintf(LOG_DEBUG,"%04d CGI header line: %s"
,session->socket, buf);
SAFECOPY(header,buf);
if(strchr(header,':')!=NULL) {
directive=strtok(header,":");
value=strtok(NULL,"");
i=get_header_type(directive);
switch (i) {
case HEAD_LOCATION:
got_valid_headers=TRUE;
if(*value=='/') {
unescape(value);
SAFECOPY(session->req.virtual_path,value);
session->req.send_location=MOVED_STAT;
if(cgi_status[0]==0)
SAFECOPY(cgi_status,error_302);
} else {
SAFECOPY(session->req.virtual_path,value);
session->req.send_location=MOVED_STAT;
if(cgi_status[0]==0)
SAFECOPY(cgi_status,error_302);
}
break;
case HEAD_STATUS:
SAFECOPY(cgi_status,value);
break;
case HEAD_LENGTH:
session->req.keep_alive=orig_keep;
strListPush(&session->req.dynamic_heads,buf);
break;
case HEAD_TYPE:
got_valid_headers=TRUE;
SAFECOPY(content_type,buf);
break;
case HEAD_TRANSFER_ENCODING:
no_chunked=TRUE;
break;
default:
strListPush(&session->req.dynamic_heads,buf);
}
continue;
}
if(i) {
strcat(buf,"\r\n"); /* Add back the missing line terminator */
msglen=strlen(buf); /* we will send this text later */
}
done_parsing_headers = TRUE; /* invalid header */
session->req.dynamic=IS_CGI;
if(!no_chunked && session->http_ver>=HTTP_1_1) {
session->req.keep_alive=orig_keep;
session->req.write_chunked=TRUE;
}
strListPush(&session->req.dynamic_heads,content_type);
send_headers(session,cgi_status);
}
if(msglen) {
if(session->req.write_chunked) {
sprintf(header,"%X\r\n",msglen);
sendsocket(session->socket,header,strlen(header));
}
lprintf(LOG_DEBUG,"%04d Sending %d bytes: %.*s"
,session->socket,msglen,msglen,buf);
wr=sendsocket(session->socket,buf,msglen);
/* log actual bytes sent */
if(session->req.ld!=NULL && wr>0)
session->req.ld->size+=wr;
if(session->req.write_chunked)
sendsocket(session->socket,newline,2);
}
}
if(GetExitCodeProcess(process_info.hProcess, &retval)==FALSE)
lprintf(LOG_ERR,"%04d !ERROR GetExitCodeProcess(%s) returned %d"
,session->socket,getfname(cmdline),GetLastError());
if(retval==STILL_ACTIVE) {
lprintf(LOG_WARNING,"%04d Terminating CGI process: %s"
,session->socket,getfname(cmdline));
TerminateProcess(process_info.hProcess, GetLastError());
}
if(rdpipe!=INVALID_HANDLE_VALUE)
CloseHandle(rdpipe);
if(wrpipe!=INVALID_HANDLE_VALUE)
CloseHandle(wrpipe);
CloseHandle(process_info.hProcess);
if(!got_valid_headers)
lprintf(LOG_WARNING,"%04d !CGI Process %s did not generate valid headers"
,session->socket,getfname(cmdline));
if(!done_parsing_headers)
lprintf(LOG_WARNING,"%04d !CGI Process %s did not send data header termination"
,session->socket,getfname(cmdline));
return(TRUE);
/********************/
/* 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, session->req.status))==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)
jsval val;
/* Return existing object if it's already been created */
if(JS_GetProperty(cx,parent,"http_request",&val) && val!=JSVAL_VOID) {
session->js_request=JSVAL_TO_OBJECT(val);
session->js_request = JS_DefineObject(cx, parent, "http_request", NULL
, NULL, JSPROP_ENUMERATE|JSPROP_READONLY);
js_add_request_prop(session,"path_info",session->req.extra_path_info);
js_add_request_prop(session,"method",methods[session->req.method]);
js_add_request_prop(session,"virtual_path",session->req.virtual_path);
/* Return existing object if it's already been created */
if(JS_GetProperty(cx,session->js_request,"query",&val) && val!=JSVAL_VOID) {
session->js_query = JSVAL_TO_OBJECT(val);
JS_ClearScope(cx,session->js_query);
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);
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);
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
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);
if(session->req.fp!=NULL)
fprintf(session->req.fp,"!JavaScript %s%s%s: %s",warning,file,line,message);
}
static JSBool
js_writefunc(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval, BOOL writeln)
{
uintN i;
JSString* str=NULL;
http_session_t* session;
if((session=(http_session_t*)JS_GetContextPrivate(cx))==NULL)
return(JS_FALSE);
if(session->req.fp==NULL)
return(JS_FALSE);
if((!session->req.prev_write) && (!session->req.sent_headers)) {
if(session->http_ver>=HTTP_1_1 && session->req.keep_alive) {
session->req.write_chunked=TRUE;
if(!ssjs_send_headers(session))
return(JS_FALSE);
}
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;
if(!ssjs_send_headers(session))
return(JS_FALSE);
}
}
}
session->req.prev_write=TRUE;
for(i=0; i<argc; i++) {
if((str=JS_ValueToString(cx, argv[i]))==NULL)
continue;
if(JS_GetStringLength(str)<1 && !writeln)
continue;
if(session->req.method!=HTTP_HEAD && session->req.method!=HTTP_OPTIONS) {
if(session->req.write_chunked) {
char chstr[12];
sprintf(chstr,"%X\r\n", JS_GetStringLength(str)+(writeln?2:0));
sendsocket(session->socket, chstr, strlen(chstr));
}
sendsocket(session->socket, JS_GetStringBytes(str), JS_GetStringLength(str));
if(writeln)
sendsocket(session->socket, newline, 2);
if(session->req.write_chunked)
sendsocket(session->socket, newline, 2);
}
else {
fwrite(JS_GetStringBytes(str),1,JS_GetStringLength(str),session->req.fp);
if(writeln)
fwrite(newline,1,2,session->req.fp);
}
}
if(str==NULL)
*rval = JSVAL_VOID;
else
*rval = STRING_TO_JSVAL(str);
return(JS_TRUE);
}
static JSBool
js_write(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
http_session_t* session;
if((session=(http_session_t*)JS_GetContextPrivate(cx))==NULL)
return(JS_FALSE);
js_writefunc(cx, obj, argc, argv, rval,FALSE);
return(JS_TRUE);
}
static JSBool
js_writeln(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
http_session_t* session;
if((session=(http_session_t*)JS_GetContextPrivate(cx))==NULL)
return(JS_FALSE);
js_writefunc(cx, obj, argc, argv, rval,TRUE);
return(JS_TRUE);
}