goahead content-length为0时的问题
gohead問題描述
UI將獲取掃描無線列表的接口formWifiApScan,由get換成了POST,此時無法獲取到數(shù)據(jù),通過抓包分析,為webserver未正常及時返回數(shù)據(jù),同時看到content-lengthy為0。
?
分析過程
今天晚上又與李權(quán)跟了一下這個問題,之前良明遇到過,了解了個大概,但還是沒完全弄清楚,借這個機會,一起深挖了一下。結(jié)果為:處理空懸,未調(diào)用注冊的回調(diào)處理,如果沒有超時結(jié)束,那么將一直處于此狀態(tài),而非循環(huán)。
幾個問題:對于goahead協(xié)議狀態(tài)處理還是不深,socketGets 這個函數(shù)返回值沒有弄清楚。
websReadEvent關(guān)鍵狀態(tài)機函數(shù)
wp->state這個值是狀態(tài)處理的核心:
#define WEBS_BEGIN 0x1 /* Beginning state */
此狀態(tài)為新建一個wp時的初始狀態(tài)
#define WEBS_HEADER 0x2 /* Ready to read first line */
讀到第一行http協(xié)議時,進入到websParseFirst函數(shù),然后轉(zhuǎn)為此狀態(tài) ,此狀態(tài)會調(diào)用socketGets 來讀取全部的http頭部。
?
#define WEBS_POST 0x4 /* POST without content */
注釋不準,應(yīng)該為POST without content-length,
此狀態(tài)不會明確調(diào)用 websUrlHandlerRequest處理,但會在讀取完上傳數(shù)據(jù)后再進行回調(diào),因此需要瀏覽器先主動關(guān)閉發(fā)送數(shù)據(jù)端,然后觸發(fā)到eof,即沒有數(shù)據(jù)了,goahead會進行處理,然后把需要的數(shù)據(jù)再回傳瀏覽器, 估計這種用法較少。
#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 */
此狀態(tài)標識為處理中,websUrlHandlerRequest 中用到,但很少有請求分2次處理,因此較少用此狀態(tài)。
?
關(guān)鍵函數(shù):socketGets
此函數(shù)為一行一行的解析http頭,>0時,表示解析成功, == 0 時表示頭部解析完成,
<0時,表示未完整解析 或 未讀到數(shù)據(jù),這個函數(shù)也雜,狀態(tài)多,問題也多(正如之前 ITB A6 goahead那篇日志分析)。
一般http協(xié)議頭都有很多行,那么此函數(shù)會多次在狀態(tài)機中被調(diào)用 ,處理于WEBS_HEADER狀態(tài)。
當協(xié)議頭讀完時,也就是\r\nr\n時,會返回0,進一步調(diào)用處理
?
?
經(jīng)過這里時,wp-state基本會切換 (處理cgi時不會切換,前面的WEBS_POST狀態(tài))。
?
?
好了,本次的問題也就在這里了,經(jīng)過上面這么長鋪墊,這就好理解了。
websParseRequest函數(shù)會把http協(xié)議會中的數(shù)據(jù)(除了第一行,見上面解析),一次性的處理,
對于content-length的處理如下,如果clen==0時,就不設(shè)置 WEBS_CLEN標識,但實際上,協(xié)議中未說 為0時代碼長度不確定,而是就是沒有數(shù)據(jù),如注釋中描述,為了避免攻擊,則將clen=0,
但是關(guān)鍵在于,不設(shè)置 WEBS_CLEN狀態(tài),則無法進入到 WEBS_POST_CLEN狀態(tài)機,于是產(chǎn)生了問題。
websGetInput 返回 0 Return 0 to get more data, 如注釋所述。 再次調(diào)用 websGetInput 函數(shù)時,由于本來就是沒有數(shù)據(jù),又是非阻塞的,所以socketGets返回-1,同時web瀏覽器又沒有關(guān)閉發(fā)送連接,所以進不了eof,如下else就什么 也沒做 (HP_FIX還是這么有緣),最后return -1(不會調(diào)處理函數(shù))
?
再回到websReadEvent函數(shù) wp->state = WEBS_POST;這個狀態(tài)處理不了(前面提到它依賴于瀏覽器關(guān)閉發(fā)送連接,才能進入處理,設(shè)置eof)。
到了這里,只有等著瀏覽器超時了,今天用谷歌瀏覽器測,應(yīng)該10秒左右會發(fā)送FIN(不確定是否為js中設(shè)置的),然后收到后 select觸發(fā)處理,進入到websUrlHandlerRequest 函數(shù)回調(diào),最后在websDone中寫socket出錯...
數(shù)據(jù)無法發(fā)出去。 或發(fā)出去一截,應(yīng)該是時間差,因為會收到對方的reset。
?
修改方案
建議同良明,在websParseRequest函數(shù)中,將conten-length的處理:對于<=0時,也設(shè)置
wp->flags |= WEBS_CLEN;
以保證狀態(tài)切換為WEBS_POST_CLEN
補充
對于如上Crash這種情況,又是一個坑,因為當conten-length為0時,再次進入狀態(tài)機時,text是為空的,在goahead 2.5上已經(jīng)fix了這個問題,對text有判空處理,但是在AC18(從AC6上移植的,應(yīng)該與2.5這個版本接近)卻沒有,
昨天晚上驗證時,UI對于POST請求,沒有跟?random,數(shù)據(jù),因此query[0] 是‘\0’,不會進入到對text的處理, 所以驗證很happy,
但是今天UI應(yīng)加了?random,結(jié)果query是有值的,而text沒有判空處理,所以大面積Http Crash,
雖然是一起坑,但是還是 goahead本身對協(xié)議處理弱...
總結(jié)
以上是生活随笔為你收集整理的goahead content-length为0时的问题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: openssl 证书管理
- 下一篇: ecos无线驱动掉线问题解决方案分析