鸿 网 互 联 www.68idc.cn

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

Cowboy 源码分析(二十六)

来源:互联网 作者:佚名 时间:2012-11-15 13:44
大家好,这边给大家推荐一本马上要上市的书《Erlang/OTP并发编程实战》,想要学习Erlang的朋友不要错过,这本书的作者是Martin Logan, Eric Merritt, Richard Carlsson,译者是百度的连城,具体可以看下这里: 好了,广告发完了,回到今天的正题,继续跟大家

  大家好,这边给大家推荐一本马上要上市的书《Erlang/OTP并发编程实战》,想要学习Erlang的朋友不要错过,这本书的作者是Martin Logan, Eric Merritt, Richard Carlsson,香港服务器,译者是百度的连城,美国空间,具体可以看下这里:

  好了,广告发完了,回到今天的正题,网站空间,继续跟大家分享Cowboy源码。上一篇,讲完了 cowboy_http_req:body_length/1 函数,今天继续往下看,如图:

  

  这里返回的 Length = 0,所以这里返回 {done, Req3#http_req{body_state=done}};

  如果返回的不是0,会递归调用 cowboy_http_req:stream_body/1 处理,这里我不打算详细讲,等下次遇到使用时,再详细看。

  接下来,我们回到 cowboy_http_req:skip_body/1 函数:

-spec skip_body(#http_req{}) -> {ok, #http_req{}} | {error, atom()}. skip_body(Req) -> case stream_body(Req) of {ok, _, Req2} -> skip_body(Req2); {done, Req2} -> {ok, Req2}; {error, Reason} -> {error, Reason} end.

  从上面我们知道cowboy_http_req:stream_body/1 返回值,这里返回 {ok, Req2};

  这样,我们又回到cowboy_http_protocol:ensure_body_processed/1 函数:

ensure_body_processed(Req=#http_req{body_state=waiting}) -> case cowboy_http_req:skip_body(Req) of {ok, Req2} -> {ok, Req2#http_req.buffer}; {error, _Reason} -> {close, <<>>} end;

  这里 Req2#http_req.buffer = <<>>,这里返回 {ok, <<>>};

  继续,回到 cowboy_http_protocol:next_request/3 函数:

-spec next_request(#http_req{}, #state{}, any()) -> ok. next_request(Req=#http_req{connection=Conn}, State=#state{ req_keepalive=Keepalive}, HandlerRes) -> RespRes = ensure_response(Req), {BodyRes, Buffer} = ensure_body_processed(Req), {cowboy_http_req, resp_sent} -> ok after 0 -> ok end, case {HandlerRes, BodyRes, RespRes, Conn} of {ok, ok, ok, keepalive} -> ?MODULE:parse_request(State#state{ buffer=Buffer, req_empty_lines=0, req_keepalive=Keepalive + 1}); _Closed -> terminate(State) end.

  我们看下这一行,这里我们稍微修改,增加一些打印日志,来看函数的执行过程:

{cowboy_http_req, resp_sent} -> io:format("Flush the resp_sent message before moving on.~n"), ok after 0 -> io:format("after 0 -> ok end.~n"), ok end,

  不知道大家对 超时时间为0的receive 有没印象,我在文章 Cowboy 源码分析(十八) 提到过,这里我测试的结果,表示我之前的理解是有错误的,我简单描述下,之前我的理解是,如果邮箱中存在 {cowboy_http_req, resp_sent},则会打印 “Flush the resp_sent message before moving on. ”,紧接着立即触发超时,打印 ”after 0 -> ok end.“, 然而这里打印的日志证明我理解错了,正确的测试结果,如果邮箱中存在 {cowboy_http_req, resp_sent},则打印 ”Flush the resp_sent message before moving on.“,如果邮箱中不存在该消息,则立即触发超时,打印 ”after 0 -> ok end.~n“。

  这边感谢网友的帮助 鲁雪林,他的测试例子如下:

-module(main). -compile(export_all). recv()-> receive a -> io:format("a.~n") after 0 -> io:format("b.~n") end.

  测试结果如下:

  

  希望能帮助大家理解 after 0 的情况。

  好了,我们继续往下看:

  < HandlerRes = ok
  < BodyRes = ok
  < RespRes = ok
  < Conn = keepalive

case {HandlerRes, BodyRes, RespRes, Conn} of {ok, ok, ok, keepalive} -> ?MODULE:parse_request(State#state{ buffer=Buffer, req_empty_lines=0, req_keepalive=Keepalive + 1}); _Closed -> terminate(State) end.

  从上面的结果,能够知道匹配第一个分支,也就是调用 cowboy_http_protocol:parse_request/1 函数,这里有个疑问,为什么不用 cowboy_http_protocol 而用?MODULE 呢?如果有朋友知道,麻烦告知,不过不影响,我们继续:

%% @private -spec parse_request(#state{}) -> ok. %% We limit the length of the Request-line to MaxLength to avoid endlessly %% reading from the socket and eventually crashing. parse_request(State=#state{buffer=Buffer, max_line_length=MaxLength}) -> case erlang:decode_packet(http_bin, Buffer, []) of {ok, Request, Rest} -> request(Request, State#state{buffer=Rest}); {more, _Length} when byte_size(Buffer) > MaxLength -> error_terminate(413, State); {more, _Length} -> wait_request(State); {error, _Reason} -> error_terminate(400, State) end.

  我们在 Cowboy 源码分析(九) 提到过这个方法,只不过但是匹配的分支是第一个分支,而这次匹配的分支是第三个分支:

{more, _Length} -> wait_request(State);

  这里就一行代码,调用cowboy_http_protocol:wait_request/1 函数:

网友评论
<