Newer
Older
free(p);
JSVALUE_TO_MSTRING(cx, argv[1], p, NULL);
HANDLE_PENDING(cx);
if(!p)
return(JS_FALSE);
header+=sprintf(header,"%s",p);
if(!JS_ValueToInt32(cx,argv[2],&i))
return JS_FALSE;
header += strftime(header,50,"; expires=%a, %d-%b-%Y %H:%M:%S GMT",&tm);
}
if(argc>3) {
JSVALUE_TO_MSTRING(cx, argv[3], p, NULL);
if(p!=NULL && *p) {
JSVALUE_TO_MSTRING(cx, argv[4], p, NULL);
if(p!=NULL && *p) {
header += sprintf(header,"; secure");
}
strListPush(&session->req.dynamic_heads,header_buf);
return(JS_TRUE);
}
static JSBool
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;
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);
strcat(str," ");
}
rc=JS_SUSPENDREQUEST(cx);
lprintf(level,"%04d %s",session->socket,str);
JS_RESUMEREQUEST(cx, rc);
JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(JS_NewStringCopyZ(cx, str)));
return(JS_TRUE);
}
static JSBool
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;
JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(JS_FALSE));
if((session=(http_session_t*)JS_GetContextPrivate(cx))==NULL)
return(JS_FALSE);
/* User name */
JSVALUE_TO_ASTRING(cx, argv[0], p, (LEN_ALIAS > LEN_NAME) ? LEN_ALIAS+2 : LEN_NAME+2, NULL);
return(JS_FALSE);
rc=JS_SUSPENDREQUEST(cx);
memset(&user,0,sizeof(user));
if(isdigit((uchar)*p))
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);
JS_RESUMEREQUEST(cx, rc);
return(JS_TRUE);
}
if(user.misc&(DELETED|INACTIVE)) {
lprintf(LOG_WARNING,"%04d !DELETED OR INACTIVE USER #%d: %s"
,session->socket,user.number,p);
JS_RESUMEREQUEST(cx, rc);
return(JS_TRUE);
}
JS_RESUMEREQUEST(cx, rc);
/* Password */
if(user.pass[0]) {
JSVALUE_TO_ASTRING(cx, argv[1], p, LEN_PASS+2, NULL);
return(JS_FALSE);
if(stricmp(user.pass,p)) { /* Wrong password */
rc=JS_SUSPENDREQUEST(cx);

rswindell
committed
lprintf(LOG_WARNING,"%04d !INVALID PASSWORD ATTEMPT FOR USER: '%s'"
,session->socket,user.alias);
JS_RESUMEREQUEST(cx, rc);
return(JS_TRUE);
}
}
if(argc>2)
JS_ValueToBoolean(cx,argv[2],&inc_logons);
rc=JS_SUSPENDREQUEST(cx);
if(inc_logons) {
user.logons++;
user.ltoday++;
}
http_logon(session, &user);
JS_RESUMEREQUEST(cx, rc);
/* user-specific objects */
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");
return(FALSE);
}
JS_SET_RVAL(cx, arglist,BOOLEAN_TO_JSVAL(JS_TRUE));
return(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;
5172
5173
5174
5175
5176
5177
5178
5179
5180
5181
5182
5183
5184
5185
5186
5187
5188
5189
5190
5191
5192
5193
5194
5195
5196
5197
5198
5199
5200
5201
5202
5203
5204
5205
5206
5207
5208
5209
5210
5211
5212
5213
5214
5215
5216
5217
5218
5219
5220
5221
5222
5223
5224
5225
5226
5227
5228
5229
5230
5231
5232
5233
5234
5235
5236
5237
5238
5239
5240
5241
5242
5243
5244
5245
5246
5247
5248
5249
5250
5251
5252
5253
5254
5255
5256
5257
5258
5259
5260
5261
5262
5263
5264
5265
5266
5267
5268
5269
5270
5271
5272
5273
5274
5275
5276
5277
5278
5279
5280
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);
JSVALUE_TO_MSTRING(cx, argv[0], filename, NULL);
return(JS_FALSE);
if(!fexist(filename)) {
JS_ReportError(cx, "Template file %s does not exist.", filename);
return(JS_FALSE);
}
len=flength(filename);
if((tfile=fopen(filename,"r"))==NULL) {
JS_ReportError(cx, "Unable to open template %s for read.", filename);
return(JS_FALSE);
}
JS_ReportError(cx, "Unable to allocate %u bytes for template.", len);
return(JS_FALSE);
}
if(fread(template, 1, len, tfile) != len) {
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) {
if(!ssjs_send_headers(session,TRUE)) {
free(template);
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,FALSE)) {
free(template);
return(JS_FALSE);
}
}
}
session->req.prev_write=TRUE;
js_write_template_part(cx, obj, template, len, NULL);
return(JS_TRUE);
}
#endif
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 */
{"set_cookie", js_set_cookie, 2}, /* Set a cookie */
{0}
};
static JSBool
js_OperationCallback(JSContext *cx)
JSBool ret;
http_session_t* session;
JS_SetOperationCallback(cx, NULL);
if((session=(http_session_t*)JS_GetContextPrivate(cx))==NULL) {
JS_SetOperationCallback(cx, js_OperationCallback);
return(JS_FALSE);
ret=js_CommonOperationCallback(cx,&session->js_callback);
JS_SetOperationCallback(cx, js_OperationCallback);
static JSContext*
js_initcx(http_session_t *session)
{
JSContext* js_cx;
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)
return(NULL);
JS_BEGINREQUEST(js_cx);
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 */
,&session->js_callback /* js */
,&session->client /* client */
,session->socket /* client */
,&js_server_props /* server */
,&session->js_glob
)
|| !JS_DefineFunctions(js_cx, session->js_glob, js_global_functions)) {
JS_RemoveObjectRoot(js_cx, &session->js_glob);
JS_ENDREQUEST(js_cx);
JS_DestroyContext(js_cx);
return(NULL);
}
if (session->is_tls) {
JS_GetProperty(js_cx, session->js_glob, "client", &val);
obj=JSVAL_TO_OBJECT(val);
JS_GetProperty(js_cx, obj, "socket", &val);
obj=JSVAL_TO_OBJECT(val);
p=(js_socket_private_t*)JS_GetPrivate(js_cx,obj);
p->session=session->tls_sess;
}
return(js_cx);
}
static BOOL js_setup(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);
return(FALSE);
}
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_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);
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);
JS_SetContextPrivate(session->js_cx, session);
JS_ENDREQUEST(session->js_cx);
return(TRUE);
}
static BOOL ssjs_send_headers(http_session_t* session,int chunked)
jsval val;
JSObject* reply;
JSIdArray* heads;
JSObject* headers;
int i;
char str[MAX_REQUEST_LINE+1];
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);
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);
if(heads != NULL) {
for(i=0;i<heads->length;i++) {
JS_IdToValue(session->js_cx,heads->vector[i],&val);
JSVALUE_TO_RASTRING(session->js_cx, val, p, &p_sz, NULL);
if(p==NULL) {
if(p)
free(p);
if(p2)
free(p2);
return FALSE;
}
JS_GetProperty(session->js_cx,headers,p,&val);
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;
}
safe_snprintf(str,sizeof(str),"%s: %s",p,p2);
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) {
JSObject* js_script;
jsval rval;
char path[MAX_PATH+1];
BOOL retval=TRUE;
long double start;
/* 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);
}
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);
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_prop(session,"post_data",session->req.post_data);
js_parse_query(session,session->req.post_data);
}
do {
/* RUN SCRIPT */
JS_ClearPendingException(session->js_cx);
session->js_callback.counter=0;
lprintf(LOG_DEBUG,"%04d JavaScript: Compiling script: %s",session->socket,script);
if((js_script=JS_CompileFile(session->js_cx, session->js_glob
,script))==NULL) {
lprintf(LOG_ERR,"%04d !JavaScript FAILED to compile script (%s)"
,session->socket,script);
JS_RemoveObjectRoot(session->js_cx, &session->js_glob);
JS_ENDREQUEST(session->js_cx);
return(FALSE);
}
lprintf(LOG_DEBUG,"%04d JavaScript: Executing script: %s",session->socket,script);
start=xp_timer();
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);
} while(0);
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);
return(retval);
}
static void respond(http_session_t * session)
{
BOOL send_file=TRUE;
if(session->req.method==HTTP_OPTIONS) {
send_headers(session,session->req.status,FALSE);
}
else {
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_file=send_headers(session,session->req.status,FALSE);
if(session->req.method==HTTP_HEAD || session->req.method==HTTP_OPTIONS)
if(send_file) {
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;) {
bytes_read=recvbufsocket(session,buf,(ch_len-k)>sizeof(buf)?sizeof(buf):(ch_len-k));
if(!bytes_read) {
send_error(session,__LINE__,error_500);
fclose(fp);
return(FALSE);
}
if(fwrite(buf, bytes_read, 1, fp)!=1) {
send_error(session,__LINE__,error_500);
5718
5719
5720
5721
5722
5723
5724
5725
5726
5727
5728
5729
5730
5731
5732
5733
5734
5735
5736
5737
5738
5739
5740
5741
5742
5743
5744
5745
5746
5747
5748
5749
5750
5751
5752
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.
sprintf(path,"%sSBBS_POST.%u.%u.html",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(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);
return fp;
}
int read_post_data(http_session_t * session)
{
FILE *fp=NULL;
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);
if(fp) fclose(fp);
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);
}
if(!post_to_file(session, fp, ch_len))
return(FALSE);
else {
/* realloc() to new size */
/* FREE()d in close_request */
p=realloc(session->req.post_data, s);
if(p==NULL) {
lprintf(LOG_CRIT,"%04d !ERROR Allocating %d bytes of memory",session->socket,session->req.post_len);
send_error(session,__LINE__,"413 Request entity too large");
if(fp) fclose(fp);
return(FALSE);
}
session->req.post_data=p;
/* read new data */
bytes_read=recvbufsocket(session,session->req.post_data+session->req.post_len,ch_len);
if(!bytes_read) {
send_error(session,__LINE__,error_500);
if(fp) fclose(fp);
return(FALSE);
}
session->req.post_len+=bytes_read;
/* Read chunk terminator */
if(sockreadline(session,ch_lstr,sizeof(ch_lstr)-1)>0)
send_error(session,__LINE__,error_500);
}
if(fp) {
fclose(fp);
FREE_AND_NULL(session->req.post_data);
session->req.post_map=xpmap(session->req.cleanup_file[CLEANUP_POST_DATA], XPMAP_READ);
if(!session->req.post_map)
return(FALSE);
session->req.post_data=session->req.post_map->addr;
/* Read more headers! */
if(!get_request_headers(session))
return(FALSE);
if (!is_legal_hostname(session->req.vhost, FALSE)) {
send_error(session,__LINE__,"400 Bad Request");
return FALSE;
}
if(!parse_headers(session))
return(FALSE);
else {
s = session->req.post_len;
if(s > MAX_POST_LEN) {
fp=open_post_file(session);
if(fp==NULL)
return(FALSE);
if(!post_to_file(session, fp, s))
return(FALSE);
fclose(fp);
session->req.post_map=xpmap(session->req.cleanup_file[CLEANUP_POST_DATA], XPMAP_READ);
if(!session->req.post_map)
return(FALSE);
session->req.post_data=session->req.post_map->addr;
}
else {
/* FREE()d in close_request() */
if(s < (MAX_POST_LEN+1) && (session->req.post_data=malloc((size_t)(s+1))) != NULL)
session->req.post_len=recvbufsocket(session,session->req.post_data,s);
else {
lprintf(LOG_CRIT,"%04d !ERROR Allocating %d bytes of memory",session->socket,s);
send_error(session,__LINE__,"413 Request entity too large");
return(FALSE);
}
}
}
if(session->req.post_len != s)
lprintf(LOG_DEBUG,"%04d !ERROR Browser said they sent %d bytes, but I got %d",session->socket,s,session->req.post_len);
if(session->req.post_len > s)
session->req.post_len = s;
session->req.post_data[session->req.post_len]=0;
}
return(TRUE);
}
void http_output_thread(void *arg)
{
http_session_t *session=(http_session_t *)arg;
RingBuf *obuf;
char buf[OUTBUF_LEN+12]; /* *MUST* be large enough to hold the buffer,
the size of the buffer in hex, and four extra bytes. */
char *bufdata;
int failed=0;
int len;
unsigned avail;
int chunked;
int i;
unsigned mss=OUTBUF_LEN;
SetThreadName("HTTP Output");
thread_up(TRUE /* setuid */);
obuf=&(session->outbuf);
if((i=pthread_mutex_init(&session->outbuf_write,NULL))!=0) {
lprintf(LOG_DEBUG,"Error %d initializing outbuf mutex",i);
thread_down();
session->outbuf_write_initialized=1;
#ifdef TCP_MAXSEG
/*
* Auto-tune the highwater mark to be the negotiated MSS for the
* socket (when possible)
*/
if(!obuf->highwater_mark) {
socklen_t sl;
sl=sizeof(i);
if(!getsockopt(session->socket, IPPROTO_TCP, TCP_MAXSEG, (char*)&i, &sl)) {
/* Check for sanity... */
if(i>100) {
lprintf(LOG_DEBUG,"%04d Autotuning outbuf highwater mark to %d based on MSS"
,session->socket,i);
mss=obuf->highwater_mark;
if(mss>OUTBUF_LEN) {
mss=OUTBUF_LEN;
lprintf(LOG_DEBUG,"%04d MSS (%d) is higher than OUTBUF_LEN (%d)"
,session->socket,i,OUTBUF_LEN);
}
}
}
}
#endif
/*
* Do *not* exit on terminate_server... wait for session thread
* to close the socket and set it to INVALID_SOCKET
*/
while(session->socket!=INVALID_SOCKET) {
/* Wait for something to output in the RingBuffer */
if((avail=RingBufFull(obuf))==0) { /* empty */
if(sem_trywait_block(&obuf->sem,1000))
continue;
/* Check for spurious sem post... */
if((avail=RingBufFull(obuf))==0)
continue;
}
else
sem_trywait(&obuf->sem);
/* Wait for full buffer or drain timeout */
if(obuf->highwater_mark) {
if(avail<obuf->highwater_mark) {
sem_trywait_block(&obuf->highwater_sem,startup->outbuf_drain_timeout);
/* We (potentially) blocked, so get fill level again */
avail=RingBufFull(obuf);
} else
sem_trywait(&obuf->highwater_sem);
/*
* At this point, there's something to send and,
* if the highwater mark is set, the timeout has
* passed or we've hit highwater. Read ring buffer
* into linear buffer.
*/
/*
* Read the current value of write_chunked... since we wait until the
* ring buffer is empty before fiddling with it.
*/
chunked=session->req.write_chunked;
bufdata=buf;
if(chunked) {
i=sprintf(buf, "%X\r\n", avail);
bufdata+=i;
len+=i;
}
pthread_mutex_lock(&session->outbuf_write);
RingBufRead(obuf, (uchar*)bufdata, avail);
if(chunked) {
bufdata+=avail;
*(bufdata++)='\r';
*(bufdata++)='\n';
len+=2;
}
if(!failed)
}
thread_down();
pthread_mutex_lock(&session->outbuf_write);
session->outbuf_write_initialized=0;
pthread_mutex_unlock(&session->outbuf_write);
pthread_mutex_destroy(&session->outbuf_write);
sem_post(&session->output_thread_terminated);
static int close_session_no_rb(http_session_t *session)
{
if (session) {
if (session->is_tls)
HANDLE_CRYPT_CALL(cryptDestroySession(session->tls_sess), session);
return close_socket(&session->socket);