Skip to content
Snippets Groups Projects
websrvr.c 195 KiB
Newer Older
deuce's avatar
deuce committed
				buf[0] = session->peeked;
				return 1;
			}
			if (HANDLE_CRYPT_CALL_EXCEPT2(cryptPopData(session->tls_sess, &session->peeked, 1, &len), CRYPT_ERROR_TIMEOUT, CRYPT_ERROR_COMPLETE, session)) {
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;
			}
			if (HANDLE_CRYPT_CALL_EXCEPT2(cryptPopData(session->tls_sess, buf, length, &len), CRYPT_ERROR_TIMEOUT, CRYPT_ERROR_COMPLETE, session)) {
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);
deuce's avatar
deuce committed
				if(session->is_tls || ERROR_VALUE!=EAGAIN)
					close_session_socket(session);
deuce's avatar
deuce committed
				close_session_socket(session);
	return(0);
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))) {
			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_prop_writeable(http_session_t * session, char *key, char *value)
{
	JSString*	js_str;

	if(session->js_cx==NULL || session->js_request==NULL)
		return;
	if(key==NULL || value==NULL)
		return;
	if((js_str=JS_NewStringCopyZ(session->js_cx, value))==NULL)
		return;
	JS_DefineProperty(session->js_cx, session->js_request, key, STRING_TO_JSVAL(js_str)
		,NULL,NULL,JSPROP_ENUMERATE);
}

static void js_add_request_prop(http_session_t * session, char *key, char *value)
	if(session->js_cx==NULL || session->js_request==NULL)
		return;
	if(key==NULL || value==NULL)
		return;
	if((js_str=JS_NewStringCopyZ(session->js_cx, value))==NULL)
		return;
	JS_DefineProperty(session->js_cx, session->js_request, key, STRING_TO_JSVAL(js_str)
		,NULL,NULL,JSPROP_ENUMERATE|JSPROP_READONLY);
}

static void js_add_header(http_session_t * session, char *key, char *value)  
{
	JSString*	js_str;
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];
	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 */
								while(*p) {
									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;
				default:
					break;
			}
			sprintf(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 || session->req.dynamic==IS_JS) {
						/*
						 * 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--
						 * --AaB03x--						 
						 */
					}
					break;
					if(session->req.dynamic==IS_SSJS || session->req.dynamic==IS_JS) {
						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;
	else if(stricmp(ext,startup->js_ext)==0)
		i=IS_JS;
	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;
	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])
		SAFECOPY(session->req.orig_request_line,session->req.virtual_path);
	if(strtok_r(session->req.virtual_path,"?",&last))
		query=strtok_r(NULL,"",&last);
	else
		query=NULL;

	/* Must initialize physical_path before calling is_dynamic_req() */
	SAFECOPY(session->req.physical_path,session->req.virtual_path);
	unescape(session->req.physical_path);
	if(!strnicmp(session->req.physical_path,http_scheme,http_scheme_len)) {
deuce's avatar
deuce committed
		/* Remove http:// from start of physical_path */
		memmove(session->req.physical_path, session->req.physical_path+http_scheme_len, strlen(session->req.physical_path+http_scheme_len)+1);

		/* Set HOST value... ignore HOST header */
deuce's avatar
deuce committed
		SAFECOPY(session->req.host,session->req.physical_path);

		/* Remove path if present (everything after the first /) */
		strtok_r(session->req.host,"/",&last);

		/* Lower-case the host */
		strlwr(session->req.host);

deuce's avatar
deuce committed
		/* Set vhost value to host value */
		SAFECOPY(session->req.vhost,session->req.host);
deuce's avatar
deuce committed

		/* Remove port specification from vhost (if present) */
		remove_port_part(session->req.vhost);
		/* 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 "/"
			strcpy(session->req.physical_path, "/");
deuce's avatar
deuce committed
		}
		else {
			offset=p-session->req.physical_path;
			memmove(session->req.physical_path
				,session->req.physical_path+offset
				,strlen(session->req.physical_path+offset)+1	/* move '\0' terminator too */
				);
		SAFECOPY(session->req.query_str,query);
static char *get_method(http_session_t * session, char *req_line)
{
	int i;

	for(i=0;methods[i]!=NULL;i++) {
		if(!strnicmp(req_line,methods[i],strlen(methods[i]))) {
			session->req.method=i;
			if(strlen(req_line)<strlen(methods[i])+2) {
				send_error(session,__LINE__,"400 Bad Request");
				return(NULL);
			}
			return(req_line+strlen(methods[i])+1);
		}
	}
rswindell's avatar
rswindell committed
	if(req_line!=NULL && *req_line>=' ')
		send_error(session,__LINE__,"501 Not Implemented");
static BOOL get_request_headers(http_session_t * session)
{
	char	head_line[MAX_REQUEST_LINE+1];
	char	next_char;
	char	*value;
	int		i;

	while(sockreadline(session,head_line,sizeof(head_line)-1)>0) {
		/* Multi-line headers */
deuce's avatar
deuce committed
		while((i=sess_recv(session,&next_char,1,MSG_PEEK))>0
			&& (next_char=='\t' || next_char==' ')) {
deuce's avatar
deuce committed
			if(i==-1 && (session->is_tls || ERROR_VALUE != EAGAIN))
				close_session_socket(session);
			i=strlen(head_line);
			if(i>sizeof(head_line)-1) {
				lprintf(LOG_ERR,"%04d !ERROR long multi-line header. The web server is broken!", session->socket);
				i=sizeof(head_line)/2;
				break;
			}
			sockreadline(session,head_line+i,sizeof(head_line)-i-1);
		}