diff --git a/src/sbbs3/websrvr.c b/src/sbbs3/websrvr.c index f991971cab8735a11f7436b04f0f14af3be74ac0..a07fb4760095b3048727889543d6252f90a17b7e 100644 --- a/src/sbbs3/websrvr.c +++ b/src/sbbs3/websrvr.c @@ -42,13 +42,13 @@ * Add in support to pass connections through to a different webserver... * probobly in access.ars... with like a simplified mod_rewrite. * This would allow people to run apache and Synchronet as the same site. - * + * * Add support for multipart/form-data * * Add support for UNIX-domain sockets for FastCGI * * Improved Win32 support for POST data... currently will read past Content-Length - * + * */ /* Headers for CGI stuff */ @@ -96,7 +96,7 @@ static int len_503 = 0; #define TIMEOUT_THREAD_WAIT 60 /* Seconds */ #define MAX_REQUEST_LINE 1024 /* NOT including terminator */ -#define MAX_HEADERS_SIZE 16384 /* Maximum total size of all headers +#define MAX_HEADERS_SIZE 16384 /* Maximum total size of all headers (Including terminator )*/ #define MAX_REDIR_LOOPS 20 /* Max. times to follow internal redirects for a single request */ #define MAX_POST_LEN 1048576 /* Max size of body for POSTS */ @@ -307,7 +307,7 @@ static char* http_vers[] = { ,NULL /* terminator */ }; -enum { +enum { HTTP_HEAD ,HTTP_GET ,HTTP_POST @@ -656,9 +656,9 @@ static int sess_sendbuf(http_session_t *session, const char *buf, size_t len, BO else { result=sendsocket(session->socket,buf+sent,len-sent); if(result==SOCKET_ERROR) { - if(ERROR_VALUE==ECONNRESET) + if(ERROR_VALUE==ECONNRESET) lprintf(LOG_NOTICE,"%04d Connection reset by peer on send",session->socket); - else if(ERROR_VALUE==ECONNABORTED) + else if(ERROR_VALUE==ECONNABORTED) lprintf(LOG_NOTICE,"%04d Connection aborted by peer on send",session->socket); #ifdef EPIPE else if(ERROR_VALUE==EPIPE) @@ -1132,7 +1132,7 @@ static int get_header_type(char *header) } /* Opposite of get_header_type() */ -static char *get_header(int id) +static char *get_header(int id) { int i; if(headers[id].id==id) @@ -1339,6 +1339,10 @@ static BOOL send_headers(http_session_t *session, const char *status, int chunke } /* DO NOT send a content-length for chunked */ + /* TODO: Why aren't we sending a Content-Length header for GET responses? + * Per RFC 2068 (HTTP/1.1): + * "it SHOULD be sent whenever the message's length can be determined prior to being transferred" + */ if(send_entity) { if((session->req.keep_alive || session->req.method == HTTP_HEAD) && session->req.dynamic!=IS_CGI&& session->req.dynamic!=IS_FASTCGI && (!chunked)) { if(ret) { @@ -1809,7 +1813,7 @@ static void badlogin(SOCKET sock, const char* prot, const char* user, const char if(startup->login_attempt.hack_threshold && count>=startup->login_attempt.hack_threshold) { hacklog(&scfg, reason, user, passwd, host, addr); #ifdef _WIN32 - if(startup->hack_sound[0] && !(startup->options&BBS_OPT_MUTE)) + if(startup->hack_sound[0] && !(startup->options&BBS_OPT_MUTE)) PlaySound(startup->hack_sound, NULL, SND_ASYNC|SND_FILENAME); #endif } @@ -1977,7 +1981,7 @@ static BOOL check_ars(http_session_t * session) ,session->socket,session->req.auth.username,session->req.ars); #ifdef _WIN32 - if(startup->hack_sound[0] && !(startup->options&BBS_OPT_MUTE)) + if(startup->hack_sound[0] && !(startup->options&BBS_OPT_MUTE)) PlaySound(startup->hack_sound, NULL, SND_ASYNC|SND_FILENAME); #endif @@ -2222,7 +2226,7 @@ static void unescape(char *p) { char * dst; char code[3]; - + dst=p; for(;*p;p++) { if(*p=='%' && isxdigit((uchar)*(p+1)) && isxdigit((uchar)*(p+2))) { @@ -2332,7 +2336,7 @@ static void js_add_request_prop(http_session_t * session, char *key, char *value ,NULL,NULL,JSPROP_ENUMERATE|JSPROP_READONLY); } -static void js_add_header(http_session_t * session, char *key, char *value) +static void js_add_header(http_session_t * session, char *key, char *value) { JSString* js_str; char *lckey; @@ -2743,29 +2747,29 @@ static BOOL parse_js_headers(http_session_t * session) * * And example reponse looks like this: * Content-type: multipart/form-data, boundary=AaB03x - * + * * --AaB03x * content-disposition: form-data; name="field1" - * + * * Joe Blow * --AaB03x * content-disposition: form-data; name="pics" * Content-type: multipart/mixed, boundary=BbC04y - * + * * --BbC04y * Content-disposition: attachment; filename="file1.txt" - * + * * Content-Type: text/plain - * + * * ... contents of file1.txt ... * --BbC04y * Content-disposition: attachment; filename="file2.gif" * Content-type: image/gif * Content-Transfer-Encoding: binary - * + * * ...contents of file2.gif... * --BbC04y-- - * --AaB03x-- + * --AaB03x-- */ } break; @@ -2948,7 +2952,7 @@ static char *get_request(http_session_t * session, char *req_line) /* Sets p to point to the first character after the first slash */ p=strchr(session->req.physical_path, '/'); - + /* * If we have a slash, make it the first char in the string. * otherwise, set path to "/" @@ -3150,7 +3154,7 @@ static BOOL get_req(http_session_t * session, char *request_line) add_env(session,"QUERY_STRING",session->req.query_str); add_env(session,"REQUEST_METHOD",methods[session->req.method]); - add_env(session,"SERVER_PROTOCOL",session->http_ver ? + add_env(session,"SERVER_PROTOCOL",session->http_ver ? http_vers[session->http_ver] : "HTTP/0.9"); return(TRUE); } @@ -3366,7 +3370,7 @@ static void read_webctrl_section(FILE *file, char *section, http_session_t *sess p = iniReadExistingString(file, section, "AccessRequirements", session->req.ars, str); /* - * If p == NULL, the key doesn't exist, retain default + * If p == NULL, the key doesn't exist, retain default * If p == default, zero-length string present, truncate req.ars * Otherwise, p is new value and is updated */ @@ -3607,7 +3611,7 @@ static BOOL check_request(http_session_t * session) if(!check_ars(session)) { unsigned *auth_list; unsigned auth_list_len; - + /* No authentication provided */ strcpy(str,"401 Unauthorized"); auth_list=parseEnumList(session->req.auth_list?session->req.auth_list:default_auth_list, ",", auth_type_names, &auth_list_len); @@ -4715,7 +4719,7 @@ static BOOL exec_cgi(http_session_t *session) } } - /* Drain STDERR & STDOUT */ + /* Drain STDERR & STDOUT */ tv.tv_sec=1; tv.tv_usec=0; FD_ZERO(&read_set); @@ -4869,7 +4873,7 @@ static BOOL exec_cgi(http_session_t *session) ); strListFreeBlock(env_block); - + if(!success) { lprintf(LOG_ERR,"%04d !ERROR %d running %s",session->socket,GetLastError(),cmdline); return(FALSE); @@ -4894,7 +4898,7 @@ static BOOL exec_cgi(http_session_t *session) lprintf(LOG_WARNING,"%04d Terminating CGI process: %s" ,session->socket,getfname(cmdline)); TerminateProcess(process_info.hProcess, GetLastError()); - } + } if(rdpipe!=INVALID_HANDLE_VALUE) CloseHandle(rdpipe); @@ -4905,7 +4909,7 @@ static BOOL exec_cgi(http_session_t *session) 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)); @@ -4925,7 +4929,7 @@ JSObject* DLLCALL js_CreateHttpReplyObject(JSContext* cx 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); @@ -5017,7 +5021,7 @@ js_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report) if((session=(http_session_t*)JS_GetContextPrivate(cx))==NULL) return; - + if(report==NULL) { lprintf(LOG_ERR,"%04d !JavaScript: %s", session->socket, message); if(session->req.fp!=NULL) @@ -5269,7 +5273,7 @@ js_login(JSContext *cx, uintN argc, jsval *arglist) /* User name */ JSVALUE_TO_ASTRING(cx, argv[0], p, (LEN_ALIAS > LEN_NAME) ? LEN_ALIAS+2 : LEN_NAME+2, NULL); - if(p==NULL) + if(p==NULL) return(JS_FALSE); rc=JS_SUSPENDREQUEST(cx); @@ -5299,7 +5303,7 @@ js_login(JSContext *cx, uintN argc, jsval *arglist) /* Password */ if(user.pass[0]) { JSVALUE_TO_ASTRING(cx, argv[1], p, LEN_PASS+2, NULL); - if(p==NULL) + if(p==NULL) return(JS_FALSE); if(stricmp(user.pass,p)) { /* Wrong password */ @@ -5565,7 +5569,7 @@ js_OperationCallback(JSContext *cx) return ret; } -static JSContext* +static JSContext* js_initcx(http_session_t *session) { JSContext* js_cx; @@ -5644,7 +5648,7 @@ static BOOL js_setup_cx(http_session_t* session) } else 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); @@ -5812,7 +5816,7 @@ static BOOL exec_ssjs(http_session_t* session, char* script) { session->req.dynamic=IS_SSJS; JS_ENDREQUEST(session->js_cx); - + return(retval); } @@ -6131,7 +6135,7 @@ void http_output_thread(void *arg) if(avail>mss) len=(avail=mss); - /* + /* * Read the current value of write_chunked... since we wait until the * ring buffer is empty before fiddling with it. */ @@ -6213,7 +6217,7 @@ void http_session_thread(void* arg) lprintf(LOG_DEBUG,"%04d !!! DANGER WILL ROBINSON, DANGER !!!", session.socket); #ifdef _WIN32 - if(startup->answer_sound[0] && !(startup->options&BBS_OPT_MUTE)) + if(startup->answer_sound[0] && !(startup->options&BBS_OPT_MUTE)) PlaySound(startup->answer_sound, NULL, SND_ASYNC|SND_FILENAME); #endif @@ -6279,7 +6283,7 @@ void http_session_thread(void* arg) lprintf(LOG_INFO,"%04d Hostname: %s", session.socket, session.host_name); #if 0 /* gethostbyaddr() is apparently not (always) thread-safe and getnameinfo() doesn't return alias information */ - for(i=0;host!=NULL && host->h_aliases!=NULL + 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]); #endif @@ -6365,7 +6369,7 @@ void http_session_thread(void* arg) session.req.ld->hostname=strdup(session.host_name); } while((redirp==NULL || session.req.send_location >= MOVED_TEMP) - && !session.finished && !session.req.finished + && !session.finished && !session.req.finished && session.socket!=INVALID_SOCKET) { SAFECOPY(session.req.status,"200 OK"); session.req.send_location=NO_LOCATION; @@ -6441,7 +6445,7 @@ void http_session_thread(void* arg) } #ifdef _WIN32 - if(startup->hangup_sound[0] && !(startup->options&BBS_OPT_MUTE)) + if(startup->hangup_sound[0] && !(startup->options&BBS_OPT_MUTE)) PlaySound(startup->hangup_sound, NULL, SND_ASYNC|SND_FILENAME); #endif @@ -6493,7 +6497,7 @@ static void cleanup(int code) semfile_list_free(&recycle_semfiles); semfile_list_free(&shutdown_semfiles); - + if(!terminated) { /* Can this be changed to a if(ws_set!=NULL) check instead? */ xpms_destroy(ws_set, close_socket_cb, NULL); ws_set=NULL; @@ -6508,7 +6512,7 @@ static void cleanup(int code) protected_uint32_destroy(active_clients); #ifdef _WINSOCKAPI_ - if(WSAInitialized && WSACleanup()!=0) + if(WSAInitialized && WSACleanup()!=0) lprintf(LOG_ERR,"0000 !WSACleanup ERROR %d",ERROR_VALUE); #endif @@ -6837,7 +6841,7 @@ void DLLCALL web_server(void* arg) /* open a socket and wait for a client */ ws_set = xpms_create(startup->bind_retry_count, startup->bind_retry_delay, lprintf); - + if(ws_set == NULL) { lprintf(LOG_CRIT,"!ERROR %d creating HTTP socket set", ERROR_VALUE); cleanup(1); @@ -6922,7 +6926,7 @@ void DLLCALL web_server(void* arg) } break; } - } + } /* Startup next session thread */ if(session==NULL) {