鸿 网 互 联 www.68idc.cn

当前位置 : 服务器租用 > 编程语言开发 > erlang > >

Cowboy 源码分析(二十五)

来源:互联网 作者:佚名 时间:2012-11-15 13:44
大家好,之前想改改熬夜的习惯,无奈熬夜的习惯改不过来啊,毕竟熬了几年了,改起来确实费劲,那就继续学习吧,好几天没跟新这个系列了,今天接着上一篇未讲完的继续跟大家分享。 stream_body(Req=#http_req{body_state=waiting}) - case parse_header('Tran

  大家好,之前想改改熬夜的习惯,无奈熬夜的习惯改不过来啊,毕竟熬了几年了,改起来确实费劲,那就继续学习吧,好几天没跟新这个系列了,今天接着上一篇未讲完的继续跟大家分享。

stream_body(Req=#http_req{body_state=waiting}) -> case parse_header('Transfer-Encoding', Req) of {[<<"chunked">>], Req2} -> stream_body(Req2#http_req{body_state= {stream, fun cowboy_http:te_chunked/2, {0, 0}, fun cowboy_http:ce_identity/1}}); {[<<"identity">>], Req2} -> {Length, Req3} = body_length(Req2), case Length of 0 -> {done, Req3#http_req{body_state=done}}; Length -> stream_body(Req3#http_req{body_state= {stream, fun cowboy_http:te_identity/2, {0, Length}, fun cowboy_http:ce_identity/1}}) end end;

  这是上一篇,我们讲到了 cowboy_http_req:stream_body/1 函数,今天我们从 {Length, Req3} = body_length(Req2), 这一行开始,这里调用函数:

%% @doc Return the request message body length, if known. %% %% The length may not be known if Transfer-Encoding is not identity, %% and the body hasn't been read at the time of the call. -spec body_length(#http_req{}) -> {undefined | non_neg_integer(), #http_req{}}. body_length(Req) -> case lists:keymember('Transfer-Encoding', 1, Req#http_req.headers) of true -> {undefined, Req}; false -> parse_header('Content-Length', Req, 0) end.

  这里:

  Req#http_req.headers = [{'Cache-Control',<<"max-age=0">>},
           {'Connection',<<"keep-alive">>},
           {'Accept-Encoding',<<"gzip, deflate">>},
           {'Accept-Language',<<"zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3">>},
           {'Accept',<<"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8">>},
           {'User-Agent',<<"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:13.0) Gecko/20100101 Firefox/13.0.1">>},
           {'Host',<<"localhost">>}]

  我们可以看到,这个列表中,并不存在第一个元素为 'Transfer-Encoding' 的成员,如果存在,则返回 {undefined, Req}; 否则调用 cowboy_http_req:parse_header/3 函数,我们从传递的参数可以获知调用该函数的第五个分支,代码如下:

parse_header(Name, Req, Default) when Name =:= 'Content-Length' -> parse_header(Name, Req, Default, fun (Value) -> cowboy_http:digits(Value) end);

  cowboy_http_req:parse_header/4 这个函数之前讲过,我们重点看下这个匿名函数:

fun (Value) -> cowboy_http:digits(Value) end

  这个匿名函数只有一行逻辑,调用了 cowboy_http:digits(Value) 我们看下这个函数的具体实现:

%% @doc Parse a list of digits as a non negative integer. -spec digits(binary()) -> non_neg_integer() | {error, badarg}. digits(Data) -> digits(Data, fun (Rest, I) -> whitespace(Rest, fun (<<>>) -> I; (_Rest2) -> {error, badarg} end) end). -spec digits(binary(), fun()) -> any(). digits(<< C, Rest/binary >>, Fun) when C >= $0, C =< $9 -> digits(Rest, Fun, C - $0); digits(_Data, _Fun) -> {error, badarg}. -spec digits(binary(), fun(), non_neg_integer()) -> any(). digits(<< C, Rest/binary >>, Fun, Acc) when C >= $0, C =< $9 -> digits(Rest, Fun, Acc * 10 + (C - $0)); digits(Data, Fun, Acc) -> Fun(Data, Acc).

  这里cowboy_http:whitespace/2 这个函数之前在Cowboy 源码分析(十三) Cowboy 源码分析(十四) 详细介绍过,这里又遇到这种嵌套的匿名函数,可读性实在是太不好了,所以不推荐大家编写这样的代码,下图是这个函数之前的测试例子,香港服务器,我贴过来,大家回忆下:

  

  对于 digits 相关的函数,我写了测试代码如下图:

  

  有了图中的例子,相信大家对下面这两个函数就会加深一定的了解:  

网友评论
<