其他分享
首页 > 其他分享> > goahead content-length为0时的问题

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