httpd_got_request函数主要是用于检测请求的格式是否正确,是请求处理第一个被调用的函数。
httpd_got_request函数
前面的文章讲述过请求行在HTTP 1.1时代之后变为 请求方式+空格+请求路径+空格+协议版本+回车换行。之前是没有协议版本的字段。这个程序的主要任务就是根据这个标准判断请求的格式是否合法。
(1)只要处理的字符的索引值小于当前已经读取的字符的索引值就一直循环执行。
(2)读取一个字节的数据
(3)根据当前的处理状态进行处理,初始化时处于CHST_FIRSTWORD状态
1)CHST_FIRSTWORD状态处理,用于寻找请求方式的结束遇到空格符或者是制表符表示读取完请求方式进入到读取请求方式间隔符阶段,如果遇到回车符或者是换行符表示错误退出此函数,其他字符继续保持此状态。
2)CHST_FIRSTWS状态处理,用于获取请求方式后的间隔符,如果此状态读取到的字符为空格符或者是制表符继续停留在此阶段,如果是回车符或者是换行符表示错误退出此函数,其他字符表示进入到读取请求路劲阶段
3)CHST_SECONDWORD状态处理,此处用于处理请求路径字后的字符,如果是空格符或者是制表符表示此支持的协议为1.1之后的协议进入到读取协议版本的阶段,如果是回车符或者是换行符表示此请求行使用的是0.9版本的协议成功推出此函数,如果是其他字符继续保持在此状态。
4)CHST_SECONDWS状态处理,此部分是对于HTTP1.1以及之后的协议版本进行处理的。如果读取的字符为空格符或者是制表符进入读取协议版本阶段,如果是回车符或者是换行符则表示错误退出此函数,如果是其他字符继续保持在此状态。
5)CHST_THIRDWORD状态处理,此状态用于处理协议的版本,如果读取的字符为空格符或者是制表符则进入读取协议后的间隔符状态,如果是回车符进入到回车符处理状态,如果是换行符进入到换行符处理状态,其他字符继续保持在此状态。
6)CHST_THIRDWS状态处理,此状态用于处理协议版本之后的字符,如果是空格符或者是制表符继续保持在此状态,如果是换行符进入到换行符处理阶段,如果是换行符进入到换行符处理阶段,如果是其他字符表示错误退出此函数。
7)CHST_LINE状态处理,如果接收到回车符进入到回车符阶段,如果接收到换行符进入到换行符阶段,其他字符继续保持在此阶段。
8)CHST_LF状态处理,如果是换行符正确退出,如果是回车符进入到回车符处理阶段,如果是其他字符进入到行阶段
9)CHST_CR状态处理,如果是换行符进入到回车换行阶段,如果是回车符正确退出,如果是其他字符进入到行阶段
10)CHST_CRLF状态处理,如果是换行符正确退出,如果是回车符进入重复回车换行阶段,如果是其他字符进入到行模式
11)CHST_CRLFCR状态处理,如果是回车符或者是换行符正确返回,如果是其他字符进入到行模式
12)CHST_BOGUS状态处理,此状态为错误状态直接返回错误
int httpd_got_request( httpd_conn* hc )
{
char c;
for ( ; hc->checked_idx < hc->read_idx; ++hc->checked_idx )
{
c = hc->read_buf[hc->checked_idx];
switch ( hc->checked_state )
{
case CHST_FIRSTWORD:
switch ( c )
{
case ' ':
case '\t':
hc->checked_state = CHST_FIRSTWS;
break;
case '\012':
case '\015':
hc->checked_state = CHST_BOGUS;
return GR_BAD_REQUEST;
}
break;
case CHST_FIRSTWS:
switch ( c )
{
case ' ':
case '\t':
break;
case '\012':
case '\015':
hc->checked_state = CHST_BOGUS;
return GR_BAD_REQUEST;
default:
hc->checked_state = CHST_SECONDWORD;
break;
}
break;
case CHST_SECONDWORD:
switch ( c )
{
case ' ':
case '\t':
hc->checked_state = CHST_SECONDWS;
break;
case '\012':
case '\015':
/* The first line has only two words - an HTTP/0.9 request. */
return GR_GOT_REQUEST;
}
break;
case CHST_SECONDWS:
switch ( c )
{
case ' ':
case '\t':
break;
case '\012':
case '\015':
hc->checked_state = CHST_BOGUS;
return GR_BAD_REQUEST;
default:
hc->checked_state = CHST_THIRDWORD;
break;
}
break;
case CHST_THIRDWORD:
switch ( c )
{
case ' ':
case '\t':
hc->checked_state = CHST_THIRDWS;
break;
case '\012':
hc->checked_state = CHST_LF;
break;
case '\015':
hc->checked_state = CHST_CR;
break;
}
break;
case CHST_THIRDWS:
switch ( c )
{
case ' ':
case '\t':
break;
case '\012':
hc->checked_state = CHST_LF;
break;
case '\015':
hc->checked_state = CHST_CR;
break;
default:
hc->checked_state = CHST_BOGUS;
return GR_BAD_REQUEST;
}
break;
case CHST_LINE:
switch ( c )
{
case '\012':
hc->checked_state = CHST_LF;
break;
case '\015':
hc->checked_state = CHST_CR;
break;
}
break;
case CHST_LF:
switch ( c )
{
case '\012':
/* Two newlines in a row - a blank line - end of request. */
return GR_GOT_REQUEST;
case '\015':
hc->checked_state = CHST_CR;
break;
default:
hc->checked_state = CHST_LINE;
break;
}
break;
case CHST_CR:
switch ( c )
{
case '\012':
hc->checked_state = CHST_CRLF;
break;
case '\015':
/* Two returns in a row - end of request. */
return GR_GOT_REQUEST;
default:
hc->checked_state = CHST_LINE;
break;
}
break;
case CHST_CRLF:
switch ( c )
{
case '\012':
/* Two newlines in a row - end of request. */
return GR_GOT_REQUEST;
case '\015':
hc->checked_state = CHST_CRLFCR;
break;
default:
hc->checked_state = CHST_LINE;
break;
}
break;
case CHST_CRLFCR:
switch ( c )
{
case '\012':
case '\015':
/* Two CRLFs or two CRs in a row - end of request. */
return GR_GOT_REQUEST;
default:
hc->checked_state = CHST_LINE;
break;
}
break;
case CHST_BOGUS:
return GR_BAD_REQUEST;
}
}
return GR_NO_REQUEST;
}