Skip to content
Snippets Groups Projects
websrvr.c 201 KiB
Newer Older
deuce's avatar
deuce committed
			case AUTHENTICATION_TLS_PSK:
				add_env(session,"AUTH_TYPE","TLS-PSK");
				break;
			case AUTHENTICATION_BASIC:
				add_env(session,"AUTH_TYPE","Basic");
				break;
			case AUTHENTICATION_DIGEST:
				add_env(session,"AUTH_TYPE","Digest");
				break;
deuce's avatar
deuce committed
			default:
				break;
		/* Should use real name if set to do so somewhere ToDo */
		add_env(session,"REMOTE_USER",session->user.alias);
		if(thisuser.pass[0])
			loginSuccess(startup->login_attempt_list, &session->addr);

	lprintf(LOG_WARNING,"%04d !AUTHORIZATION FAILURE for user %s, ARS: %s"
		,session->socket,session->req.auth.username,session->req.ars);
	if(startup->hack_sound[0] && !(startup->options&BBS_OPT_MUTE))
		PlaySound(startup->hack_sound, NULL, SND_ASYNC|SND_FILENAME);
#endif

static named_string_t** read_ini_list(char* path, char* section, char* desc
	if((fp=iniOpenFile(path, /* create? */FALSE))!=NULL) {
		list=iniReadNamedStringList(fp,section);
		iniCloseFile(fp);
		COUNT_LIST_ITEMS(list,i);
			lprintf(LOG_DEBUG,"Read %lu %s from %s section of %s"
				,(ulong)i,desc,section==NULL ? "root":section,path);
	} else
		lprintf(LOG_WARNING, "Error %d opening %s", errno, path);
deuce's avatar
deuce committed
static int sess_recv(http_session_t *session, char *buf, size_t length, int flags)
{
deuce's avatar
deuce committed
	if (session->is_tls) {
		if (flags == MSG_PEEK) {
			if (session->peeked_valid) {
				buf[0] = session->peeked;
				return 1;
			}
deuce's avatar
deuce committed
			if (HANDLE_CRYPT_CALL_EXCEPT2(cryptPopData(session->tls_sess, &session->peeked, 1, &len), session, "popping data", CRYPT_ERROR_TIMEOUT, CRYPT_ERROR_COMPLETE)) {
deuce's avatar
deuce committed
				if (len == 1) {
					session->peeked_valid = TRUE;
					buf[0] = session->peeked;
					return 1;
				}
				return 0;
			}
			return -1;
		}
		else {
			if (session->peeked_valid) {
				buf[0] = session->peeked;
				session->peeked_valid = FALSE;
				return 1;
			}
deuce's avatar
deuce committed
			if (HANDLE_CRYPT_CALL_EXCEPT2(cryptPopData(session->tls_sess, buf, length, &len), session, "popping data", CRYPT_ERROR_TIMEOUT, CRYPT_ERROR_COMPLETE)) {
deuce's avatar
deuce committed
				if (len == 0) {
					session->tls_pending = FALSE;
deuce's avatar
deuce committed
				}
				return len;
			}
			return -1;
		}
	}
	else {
		return recv(session->socket, buf, length, flags);
	}
}

static int sockreadline(http_session_t * session, char *buf, size_t length)
	fd_set	rd_set;
	struct	timeval tv;
	for(i=0;TRUE;) {
		if(session->socket==INVALID_SOCKET)
			return(-1);
deuce's avatar
deuce committed
		if ((!session->is_tls) || (!session->tls_pending)) {
			FD_ZERO(&rd_set);
			FD_SET(session->socket,&rd_set);
			/* Convert timeout from ms to sec/usec */
			tv.tv_sec=startup->max_inactivity;
			tv.tv_usec=0;
			sel=select(session->socket+1,&rd_set,NULL,NULL,&tv);
			switch(sel) {
				case 1:
					if (session->is_tls)
						session->tls_pending=TRUE;
					break;
				case -1:
					close_session_socket(session);
					lprintf(LOG_DEBUG,"%04d !ERROR %d selecting socket for read",session->socket,ERROR_VALUE);
					return(-1);
				default:
					/* Timeout */
					lprintf(LOG_NOTICE,"%04d Session timeout due to inactivity (%d seconds)",session->socket,startup->max_inactivity);
					return(-1);
			}
deuce's avatar
deuce committed
		switch(sess_recv(session, &ch, 1, 0)) {
deuce's avatar
deuce committed
				if(session->is_tls || ERROR_VALUE!=EAGAIN) {
					if(startup->options&WEB_OPT_DEBUG_RX)
						lprintf(LOG_DEBUG,"%04d !ERROR %d receiving on socket",session->socket,ERROR_VALUE);
deuce's avatar
deuce committed
					close_session_socket(session);
				/* Socket has been closed */
deuce's avatar
deuce committed
				close_session_socket(session);
		if(ch=='\n')
			break;

		if(i<length)
			buf[i++]=ch;

	/* Terminate at length if longer */
	if(i>length)
		i=length;
	while(i>0 && buf[i-1]=='\r')
		i--;

	buf[i]=0;
	if(startup->options&WEB_OPT_DEBUG_RX) {
		lprintf(LOG_DEBUG,"%04d RX: %s",session->socket,buf);
			lprintf(LOG_DEBUG,"%04d Long header, chucked %d bytes",session->socket,chucked);
	return(i);
deuce's avatar
deuce committed
static int pipereadline(HANDLE pipe, char *buf, size_t length, char *fullbuf, size_t fullbuf_len)
deuce's avatar
deuce committed
static int pipereadline(int pipe, char *buf, size_t length, char *fullbuf, size_t fullbuf_len)
#ifndef _WIN32
	struct timeval tv={0,0};
	fd_set  read_set;
#endif
deuce's avatar
deuce committed
	/* Terminate buffers */
	if(buf != NULL)
		buf[0]=0;
	if(fullbuf != NULL)
		fullbuf[0]=0;
		ReadFile(pipe, &ch, 1, (DWORD*)&ret, NULL);
		tv.tv_sec=startup->max_cgi_inactivity;
		tv.tv_usec=0;
		FD_ZERO(&read_set);
		FD_SET(pipe, &read_set);
		if(select(pipe+1, &read_set, NULL, NULL, &tv)<1)
			return(-1);
		ret=read(pipe, &ch, 1);
deuce's avatar
deuce committed
			if(fullbuf != NULL && i < (fullbuf_len-1)) {
				fullbuf[i]=ch;
				fullbuf[i+1]=0;
			}

deuce's avatar
deuce committed
			if(buf != NULL && i<length)
				buf[i]=ch;

			i++;
	}

	/* Terminate at length if longer */
	if(i>length)
		i=length;
deuce's avatar
deuce committed
	if(i>0 && buf != NULL && buf[i-1]=='\r')
		buf[--i]=0;
deuce's avatar
deuce committed
	else {
		if(buf != NULL)
			buf[i]=0;
	}
	return(i);
deuce's avatar
deuce committed
static int recvbufsocket(http_session_t *session, char *buf, long count)
deuce's avatar
deuce committed
	while(rd<count && session_check(session,NULL,NULL,startup->max_inactivity*1000))  {
		i=sess_recv(session,buf+rd,count-rd,0);
				if (ERROR_VALUE == EAGAIN && !session->is_tls)
					break;
				// Fall-through...
deuce's avatar
deuce committed
				close_session_socket(session);
	return(0);
static void unescape(char *p)
{
	char *	dst;
	char	code[3];
		if(*p=='%' && isxdigit((uchar)*(p+1)) && isxdigit((uchar)*(p+2))) {
			sprintf(code,"%.2s",p+1);
			*(dst++)=(char)strtol(code,NULL,16);
			p+=2;
		}
		else  {
			if(*p=='+')  {
				*(dst++)=' ';
			}
			else  {
				*(dst++)=*p;
			}
		}
	}
	*(dst)=0;
}

static void js_add_queryval(http_session_t * session, char *key, char *value)
	jsuint		len;
	int			alen;

	/* Return existing object if it's already been created */
	if(JS_GetProperty(session->js_cx,session->js_query,key,&val) && val!=JSVAL_VOID)  {
		keyarray = JSVAL_TO_OBJECT(val);
		alen=-1;
	}
	else {
		keyarray = JS_NewArrayObject(session->js_cx, 0, NULL);
		if(!JS_DefineProperty(session->js_cx, session->js_query, key, OBJECT_TO_JSVAL(keyarray)
			, NULL, NULL, JSPROP_ENUMERATE))
			return;
		alen=0;
	}

	if(alen==-1) {
		if(JS_GetArrayLength(session->js_cx, keyarray, &len)==JS_FALSE)
			return;
deuce's avatar
deuce committed
		alen=len;
deuce's avatar
deuce committed
	lprintf(LOG_DEBUG,"%04d Adding query value %s=%s at pos %d",session->socket,key,value,alen);
	val=STRING_TO_JSVAL(JS_NewStringCopyZ(session->js_cx,value));
	JS_SetElement(session->js_cx, keyarray, alen, &val);
}

static void js_add_cookieval(http_session_t * session, char *key, char *value)
{
	JSObject*	keyarray;
	jsval		val;
	jsuint		len;
	int			alen;

	/* Return existing object if it's already been created */
	if(JS_GetProperty(session->js_cx,session->js_cookie,key,&val) && val!=JSVAL_VOID)  {
		keyarray = JSVAL_TO_OBJECT(val);
		alen=-1;
	}
	else {
		keyarray = JS_NewArrayObject(session->js_cx, 0, NULL);
		if(!JS_DefineProperty(session->js_cx, session->js_cookie, key, OBJECT_TO_JSVAL(keyarray)
			, NULL, NULL, JSPROP_ENUMERATE))
			return;
		alen=0;
	}

	if(alen==-1) {
		if(JS_GetArrayLength(session->js_cx, keyarray, &len)==JS_FALSE)
			return;
		alen=len;
	}

	lprintf(LOG_DEBUG,"%04d Adding cookie value %s=%s at pos %d",session->socket,key,value,alen);
	val=STRING_TO_JSVAL(JS_NewStringCopyZ(session->js_cx,value));
	JS_SetElement(session->js_cx, keyarray, alen, &val);
}

static void js_add_request_property(http_session_t * session, char *key, char *value, size_t len, bool writeable)
{
	JSString*	js_str;

	if(session->js_cx==NULL || session->js_request==NULL)
		return;
	if(key==NULL || value==NULL)
		return;
	if(len)
		js_str=JS_NewStringCopyN(session->js_cx, value, len);
	else
		js_str=JS_NewStringCopyZ(session->js_cx, value);
	
	if(js_str == NULL)

	uintN attrs = JSPROP_ENUMERATE;
	if(!writeable)
		attrs |= JSPROP_READONLY;
	JS_DefineProperty(session->js_cx, session->js_request, key, STRING_TO_JSVAL(js_str)
static void js_add_request_prop_writeable(http_session_t * session, char *key, char *value)
	js_add_request_property(session, key, value, 0, /* writeable: */true);
}
static void js_add_request_prop(http_session_t * session, char *key, char *value)
{
	js_add_request_property(session, key, value, 0, /* writeable: */false);
static void js_add_header(http_session_t * session, char *key, char *value)
deuce's avatar
deuce committed
	if((lckey=strdup(key))==NULL)
	strlwr(lckey);
	if((js_str=JS_NewStringCopyZ(session->js_cx, value))==NULL) {
		free(lckey);
		return;
	}
	JS_DefineProperty(session->js_cx, session->js_header, lckey, STRING_TO_JSVAL(js_str)
		,NULL,NULL,JSPROP_ENUMERATE|JSPROP_READONLY);
deuce's avatar
deuce committed
	free(lckey);
#if 0
static void js_parse_multipart(http_session_t * session, char *p)  {
	size_t		key_len;
	size_t		value_len;
	char		*lp;
	char		*key;
	char		*value;

	if(p == NULL)
		return;

	lp=p;

	while((key_len=strcspn(lp,"="))!=0)  {
		key=lp;
		lp+=key_len;
		if(*lp) {
			*lp=0;
			lp++;
		}
		value_len=strcspn(lp,"&");
		value=lp;
		lp+=value_len;
		if(*lp) {
			*lp=0;
			lp++;
		}
		unescape(value);
		unescape(key);
		js_add_queryval(session, key, value);
	}
}
#endif

static void js_parse_query(http_session_t * session, char *p)  {
	size_t		key_len;
	size_t		value_len;
	char		*lp;
	while((key_len=strcspn(lp,"="))!=0)  {
		if(*lp) {
			*lp=0;
			lp++;
		}
		value_len=strcspn(lp,"&");
		value=lp;
deuce's avatar
deuce committed
		lp+=value_len;
		if(*lp) {
			*lp=0;
			lp++;
		}
		js_add_queryval(session, key, value);
static char *get_token_value(char **p)
{
	char	*pos=*p;
	char	*start;
	char	*out;
	BOOL	escaped=FALSE;

	start=pos;
	out=start;
	if(*pos=='"') {
		for(pos++; *pos; pos++) {
			if(escaped && *pos)
				*(out++)=*pos;
			else if(*pos=='"') {
				pos++;
				break;
			}
			else if(*pos=='\\')
				escaped=TRUE;
			else
				*(out++)=*pos;
		}
	}
	else {
		for(; *pos; pos++) {
			if(iscntrl(*pos))
			switch(*pos) {
				case 0:
				case '(':
				case ')':
				case '<':
				case '>':
				case '@':
				case ',':
				case ';':
				case ':':
				case '\\':
				case '"':
				case '/':
				case '[':
				case ']':
				case '?':
				case '=':
				case '{':
				case '}':
				case ' ':
				case '\t':
					goto end_of_text;
			}
			*(out++)=*pos;
		}
	}
end_of_text:
	while(*pos==',' || isspace(*pos))
		pos++;
	*out=0;
static int hexval(unsigned char ch)
{
	ch-='0';
	if(ch<10)
		return(ch);
	ch-=7;
	if(ch<16 && ch>9)
		return(ch);
	if(ch>41) {
		ch-=32;
		if(ch<16 && ch>9)
			return(ch);
	}
	return(0);
}

static BOOL parse_headers(http_session_t * session)
{
	char	*tvalue;
	char	env_name[128];
deuce's avatar
deuce committed
	char	portstr[7]; // ":65535"
	for(idx=0;session->req.headers[idx]!=NULL;idx++) {
		/* TODO: strdup() is possibly too slow here... */
		head_line=strdup(session->req.headers[idx]);
		if((strtok_r(head_line,":",&last))!=NULL && (value=strtok_r(NULL,"",&last))!=NULL) {
			i=get_header_type(head_line);
			while(*value && *value<=' ') value++;
			switch(i) {
				case HEAD_AUTH:
deuce's avatar
deuce committed
					/* If you're authenticated via TLS-PSK, you can't use basic or digest */
					if (session->req.auth.type != AUTHENTICATION_TLS_PSK) {
						if((p=strtok_r(value," ",&last))!=NULL) {
							if(stricmp(p, "Basic")==0) {
								p=strtok_r(NULL," ",&last);
								if(p==NULL)
deuce's avatar
deuce committed
								while(*p && *p<' ') p++;
								b64_decode(p,strlen(p),p,strlen(p));
								p=strtok_r(p,":",&last);
deuce's avatar
deuce committed
									if(strlen(p) >= sizeof(session->req.auth.username))
deuce's avatar
deuce committed
									SAFECOPY(session->req.auth.username, p);
									p=strtok_r(NULL,":",&last);
									if(p) {
										if(strlen(p) >= sizeof(session->req.auth.password))
											break;
										SAFECOPY(session->req.auth.password, p);
										session->req.auth.type=AUTHENTICATION_BASIC;
									}
deuce's avatar
deuce committed
							else if(stricmp(p, "Digest")==0) {
								p=strtok_r(NULL, "", &last);
								/* Defaults */
								session->req.auth.algorithm=ALGORITHM_MD5;
								session->req.auth.type=AUTHENTICATION_DIGEST;
								/* Parse out values one at a time and store */
deuce's avatar
deuce committed
									while(isspace(*p))
										p++;
									if(strnicmp(p,"username=",9)==0) {
										p+=9;
										tvalue=get_token_value(&p);
										if(strlen(tvalue) >= sizeof(session->req.auth.username))
											break;
										SAFECOPY(session->req.auth.username, tvalue);
									}
									else if(strnicmp(p,"realm=",6)==0) {
										p+=6;
										session->req.auth.realm=strdup(get_token_value(&p));
									}
									else if(strnicmp(p,"nonce=",6)==0) {
										p+=6;
										session->req.auth.nonce=strdup(get_token_value(&p));
									}
									else if(strnicmp(p,"uri=",4)==0) {
										p+=4;
										session->req.auth.digest_uri=strdup(get_token_value(&p));
									}
									else if(strnicmp(p,"response=",9)==0) {
										p+=9;
										tvalue=get_token_value(&p);
										if(strlen(tvalue)==32) {
											for(i=0; i<16; i++) {
												session->req.auth.digest[i]=hexval(tvalue[i*2])<<4 | hexval(tvalue[i*2+1]);
											}
deuce's avatar
deuce committed
									else if(strnicmp(p,"algorithm=",10)==0) {
										p+=10;
										tvalue=get_token_value(&p);
										if(stricmp(tvalue,"MD5")==0) {
											session->req.auth.algorithm=ALGORITHM_MD5;
										}
										else {
											session->req.auth.algorithm=ALGORITHM_UNKNOWN;
										}
deuce's avatar
deuce committed
									else if(strnicmp(p,"cnonce=",7)==0) {
										p+=7;
										session->req.auth.cnonce=strdup(get_token_value(&p));
deuce's avatar
deuce committed
									else if(strnicmp(p,"qop=",4)==0) {
										p+=4;
										tvalue=get_token_value(&p);
										if(stricmp(tvalue,"auth")==0) {
											session->req.auth.qop_value=QOP_AUTH;
										}
										else if (stricmp(tvalue,"auth-int")==0) {
											session->req.auth.qop_value=QOP_AUTH_INT;
										}
										else {
											session->req.auth.qop_value=QOP_UNKNOWN;
										}
deuce's avatar
deuce committed
									else if(strnicmp(p,"nc=",3)==0) {
										p+=3;
										session->req.auth.nonce_count=strdup(get_token_value(&p));
deuce's avatar
deuce committed
										while(*p && *p != '=')
											p++;
										if(*p == '=')
											get_token_value(&p);
deuce's avatar
deuce committed
								if(session->req.auth.digest_uri==NULL)
									session->req.auth.digest_uri=strdup(session->req.request_line);
								/* Validate that we have the required values... */
								switch(session->req.auth.qop_value) {
									case QOP_NONE:
										if(session->req.auth.realm==NULL
												|| session->req.auth.nonce==NULL
												|| session->req.auth.digest_uri==NULL)
											send_error(session,__LINE__,"400 Bad Request");
deuce's avatar
deuce committed
										break;
									case QOP_AUTH:
									case QOP_AUTH_INT:
										if(session->req.auth.realm==NULL
												|| session->req.auth.nonce==NULL
												|| session->req.auth.nonce_count==NULL
												|| session->req.auth.cnonce==NULL
												|| session->req.auth.digest_uri==NULL)
											send_error(session,__LINE__,"400 Bad Request");
deuce's avatar
deuce committed
										break;
									default:
										send_error(session,__LINE__,"400 Bad Request");
deuce's avatar
deuce committed
										break;
								}
					add_env(session,"CONTENT_LENGTH",value);
deuce's avatar
deuce committed
					content_len=strtol(value,NULL,10);
					break;
				case HEAD_IFMODIFIED:
					session->req.if_modified_since=decode_date(value);
					break;
				case HEAD_CONNECTION:
					if(!stricmp(value,"Keep-Alive")) {
						session->req.keep_alive=TRUE;
					}
					if(!stricmp(value,"Close")) {
						session->req.keep_alive=FALSE;
					}
					if(session->req.ld!=NULL) {
						FREE_AND_NULL(session->req.ld->referrer);
						/* FREE()d in http_logging_thread() */
						session->req.ld->referrer=strdup(value);
					if(session->req.ld!=NULL) {
						FREE_AND_NULL(session->req.ld->agent);
						/* FREE()d in http_logging_thread() */
						session->req.ld->agent=strdup(value);
				case HEAD_TRANSFER_ENCODING:
					if(!stricmp(value,"chunked"))
						session->req.read_chunked=TRUE;
					else
						send_error(session,__LINE__,"501 Not Implemented");
				case HEAD_RANGE:
						send_error(session,__LINE__,error_416);
						break;
					}
					value+=6;
					if(strchr(value,',')!=NULL) {	/* We don't do multiple ranges yet - TODO */
						send_error(session,__LINE__,error_416);
						break;
					}
					/* Check for offset from end. */
					if(*value=='-') {
						session->req.range_start=strtol(value,NULL,10);
						session->req.range_end=-1;
						break;
					}
					if((p=strtok_r(value,"-",&last))!=NULL) {
						session->req.range_start=strtol(p,NULL,10);
						if((p=strtok_r(NULL,"-",&last))!=NULL)
							session->req.range_end=strtol(p,NULL,10);
						else
							session->req.range_end=-1;
						send_error(session,__LINE__,error_416);
deuce's avatar
deuce committed
				case HEAD_IFRANGE:
					session->req.if_range=decode_date(value);
					break;
				case HEAD_TYPE:
					add_env(session,"CONTENT_TYPE",value);
					break;
deuce's avatar
deuce committed
				case HEAD_UPGRADEINSECURE:
					if (startup->options & WEB_OPT_HSTS_SAFE) {
						if (strcmp(value, "1") == 0) {
							if (!session->is_tls) {
								portstr[0] = 0;
								if (startup->tls_port != 443)
									sprintf(portstr, ":%hu", startup->tls_port);
								p = realloc(session->req.vary_list, (session->req.vary_list ? strlen(session->req.vary_list) + 2 : 0) + strlen(get_header(HEAD_UPGRADEINSECURE)) + 1);
								if (p == NULL)
									send_error(session, __LINE__, error_500);
								else {
									if (session->req.vary_list)
										strcat(p, ", ");
									strcat(p, get_header(HEAD_UPGRADEINSECURE));
									session->req.vary_list = p;

									session->req.send_location = MOVED_TEMPREDIR;
									session->req.upgrading = TRUE;
									session->req.keep_alive = FALSE;
									FREE_AND_NULL(session->req.location_to_send);
									if (asprintf(&session->req.location_to_send, "https://%s%s%s", session->req.vhost, portstr, session->req.virtual_path) < 0)
										send_error(session, __LINE__, error_500);
								}
							}
						}
					}
					break;
			SAFEPRINTF(env_name,"HTTP_%s",head_line);
			add_env(session,env_name,value);
		}
		free(head_line);
	}
	if(content_len)
		session->req.post_len = content_len;
	add_env(session,"SERVER_NAME",session->req.host[0] ? session->req.host : startup->host_name );
	return TRUE;
}

static BOOL parse_js_headers(http_session_t * session)
{
	char	*head_line;
	char	*value;
	char	*last;
	char	*p;
	int		i;
	size_t	idx;

	for(idx=0;session->req.headers[idx]!=NULL;idx++) {
		head_line=session->req.headers[idx];
		if((strtok_r(head_line,":",&last))!=NULL && (value=strtok_r(NULL,"",&last))!=NULL) {
			i=get_header_type(head_line);
			while(*value && *value<=' ') value++;
			js_add_header(session,head_line,value);
			switch(i) {
				case HEAD_TYPE:
					if(session->req.dynamic==IS_SSJS) {
						/*
						 * We need to parse out the files based on RFC1867
						 *
						 * 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--
					if(session->req.dynamic==IS_SSJS) {
						while((key=strtok_r(p,"=",&last))!=NULL) {
							while(isspace(*key))
								key++;
							if((val=strtok_r(p,";\t\n\v\f\r ",&last))!=NULL) {	/* Whitespace */
				default:
					break;
			}
		}
	}
	return TRUE;
}

static int get_version(char *p)
{
	int		i;
	if(p==NULL)
		return(0);
	while(*p && *p<' ') p++;
	if(*p==0)
		return(0);
	for(i=1;http_vers[i]!=NULL;i++) {
		if(!stricmp(p,http_vers[i])) {
			return(i);
		}
	}
	return(i-1);
}

static int is_dynamic_req(http_session_t* session)
{
	char	fname[MAX_PATH+1];
	char	ext[MAX_PATH+1];
	check_extra_path(session);
	_splitpath(session->req.physical_path, drive, dir, fname, ext);
	if(!(startup->options&WEB_OPT_NO_CGI)) {
		if (session->req.fastcgi_socket) {
			init_enviro(session);
			return IS_FASTCGI;
		}
	}

	if(stricmp(ext,startup->ssjs_ext)==0)
		i=IS_SSJS;
	else if(get_xjs_handler(ext,session))
		i=IS_SSJS;
	if(!(startup->options&BBS_OPT_NO_JAVASCRIPT) && i)  {
rswindell's avatar
rswindell committed
		lprintf(LOG_DEBUG,"%04d Setting up JavaScript support", session->socket);
			lprintf(LOG_ERR,"%04d !ERROR setting up JavaScript support", session->socket);
			send_error(session,__LINE__,error_500);
	if(!(startup->options&WEB_OPT_NO_CGI)) {
		for(i=0; startup->cgi_ext!=NULL && startup->cgi_ext[i]!=NULL; i++)  {
			if(stricmp(ext,startup->cgi_ext[i])==0)  {
				init_enviro(session);
		_splitpath(session->req.cgi_dir?session->req.cgi_dir:cgi_dir, cgidrive, cgidir, fname, ext);
		if(stricmp(dir,cgidir)==0 && stricmp(drive,cgidrive)==0)  {
			init_enviro(session);
			return(IS_CGI);
static char * split_port_part(char *host)
deuce's avatar
deuce committed
	char *p=strchr(host, 0)-1;
	if (isdigit(*p)) {
		/*
		 * If the first and last : are not the same, and it doesn't
		 * start with '[', there's no port part.
		 */
		if (host[0] != '[') {
			if (strchr(host, ':') != strrchr(host, ':'))
				return NULL;
		}
		for(; p >= host; p--) {
			if (*p == ':') {
				*p = 0;
				ret = p+1;
				break;
			}
			if (!isdigit(*p))
				break;
	// Now, remove []s...
	if (host[0] == '[') {
		memmove(host, host+1, strlen(host));
		p=strchr(host, ']');
		if (p)
			*p = 0;
	}
	return ret;
}

static void remove_port_part(char *host)
{
	split_port_part(host);
static char *get_request(http_session_t * session, char *req_line)
	char*	query;
deuce's avatar
deuce committed
	const char*	scheme = NULL;
	size_t	scheme_len;
	SAFECOPY(session->req.virtual_path,req_line);
	if(strtok_r(session->req.virtual_path," \t",&last))
		retval=strtok_r(NULL," \t",&last);
	else
		retval=NULL;
	SAFECOPY(session->req.request_line,session->req.virtual_path);
	if (!session->req.orig_request_line[0])