goahead content-length为0时的问题
作者:互联网
gohead问题描述
UI将获取扫描无线列表的接口formWifiApScan,由get换成了POST,此时无法获取到数据,通过抓包分析,为webserver未正常及时返回数据,同时看到content-lengthy为0。
分析过程
今天晚上又与李权跟了一下这个问题,之前良明遇到过,了解了个大概,但还是没完全弄清楚,借这个机会,一起深挖了一下。结果为:处理空悬,未调用注册的回调处理,如果没有超时结束,那么将一直处于此状态,而非循环。
几个问题:对于goahead协议状态处理还是不深,socketGets 这个函数返回值没有弄清楚。
websReadEvent关键状态机函数
wp->state这个值是状态处理的核心:
#define WEBS_BEGIN 0x1 /* Beginning state */
此状态为新建一个wp时的初始状态
#define WEBS_HEADER 0x2 /* Ready to read first line */
读到第一行http协议时,进入到websParseFirst函数,然后转为此状态 ,此状态会调用socketGets 来读取全部的http头部。
#define WEBS_POST 0x4 /* POST without content */
注释不准,应该为POST without content-length,
此状态不会明确调用 websUrlHandlerRequest处理,但会在读取完上传数据后再进行回调,因此需要浏览器先主动关闭发送数据端,然后触发到eof,即没有数据了,goahead会进行处理,然后把需要的数据再回传浏览器, 估计这种用法较少。
#define WEBS_POST_CLEN 0x8 /* Ready to read content for POST */
很常用,有明确的长度
POST request with content specified by a content length
#define WEBS_PROCESSING 0x10 /* Processing request */
此状态标识为处理中,websUrlHandlerRequest 中用到,但很少有请求分2次处理,因此较少用此状态。
关键函数:socketGets
此函数为一行一行的解析http头,>0时,表示解析成功, == 0 时表示头部解析完成,
<0时,表示未完整解析 或 未读到数据,这个函数也杂,状态多,问题也多(正如之前 ITB A6 goahead那篇日志分析)。
一般http协议头都有很多行,那么此函数会多次在状态机中被调用 ,处理于WEBS_HEADER状态。
当协议头读完时,也就是\r\nr\n时,会返回0,进一步调用处理
经过这里时,wp-state基本会切换 (处理cgi时不会切换,前面的WEBS_POST状态)。
好了,本次的问题也就在这里了,经过上面这么长铺垫,这就好理解了。
websParseRequest函数会把http协议会中的数据(除了第一行,见上面解析),一次性的处理,
对于content-length的处理如下,如果clen==0时,就不设置 WEBS_CLEN标识,但实际上,协议中未说 为0时代码长度不确定,而是就是没有数据,如注释中描述,为了避免***,则将clen=0,
但是关键在于,不设置 WEBS_CLEN状态,则无法进入到 WEBS_POST_CLEN状态机,于是产生了问题。
websGetInput 返回 0 Return 0 to get more data, 如注释所述。 再次调用 websGetInput 函数时,由于本来就是没有数据,又是非阻塞的,所以socketGets返回-1,同时web浏览器又没有关闭发送连接,所以进不了eof,如下else就什么 也没做 (HP_FIX还是这么有缘),最后return -1(不会调处理函数)
再回到websReadEvent函数 wp->state = WEBS_POST;这个状态处理不了(前面提到它依赖于浏览器关闭发送连接,才能进入处理,设置eof)。
到了这里,只有等着浏览器超时了,今天用谷歌浏览器测,应该10秒左右会发送FIN(不确定是否为js中设置的),然后收到后 select触发处理,进入到websUrlHandlerRequest 函数回调,最后在websDone中写socket出错...
数据无法发出去。 或发出去一截,应该是时间差,因为会收到对方的reset。
修改方案
建议同良明,在websParseRequest函数中,将conten-length的处理:对于<=0时,也设置
wp->flags |= WEBS_CLEN;
以保证状态切换为WEBS_POST_CLEN
补充
对于如上Crash这种情况,又是一个坑,因为当conten-length为0时,再次进入状态机时,text是为空的,在goahead 2.5上已经fix了这个问题,对text有判空处理,但是在AC18(从AC6上移植的,应该与2.5这个版本接近)却没有,
昨天晚上验证时,UI对于POST请求,没有跟?random,数据,因此query[0] 是‘\0’,不会进入到对text的处理, 所以验证很happy,
但是今天UI应加了?random,结果query是有值的,而text没有判空处理,所以大面积Http Crash,
虽然是一起坑,但是还是 goahead本身对协议处理弱...
标签:状态,函数,处理,content,WEBS,length,POST,goahead 来源: https://blog.51cto.com/u_7777817/2715866