大家好,这几天在忙游戏的端午节活动,在这里也提前跟大家说一声端午节快乐,如果你们的公司遵守国家规定,应该是放假三天,那么,大家想吃粽子吃粽子,想划龙舟划龙舟(不知道有没地方),不知道大家老家的粽子都是什么味道,映像最深刻的是小时候,端午节会有新的衣服穿,但是换之前需要用艾叶洗澡,好像我在北京都很少见过,还有就是老家的肉粽还是蛮让人怀念的。
好了,回到正题,上一篇,我们在文章最后,提到了在cowboy_http_req:response/5函数的最后给这个处理请求的进程发送了一个消息 {?MODULE, resp_sent}, 今天,我们来看下,这个进程收到这条消息,又会怎么做呢?
我们通过搜索关键字,能发现一共有两个地方处理了 resp_sent 这个消息:
其中一个:
-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), %% Flush the resp_sent message before moving on. receive {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代码,还是比较整齐规范的。这里是当处理完当前请求,处理下一个请求时调用,之后,我们会详细介绍。
另一个函数:
%% Only send an error reply if there is no resp_sent message. -spec error_terminate(cowboy_http:status(), #state{}) -> ok. error_terminate(Code, State=#state{socket=Socket, transport=Transport, onresponse=OnResponse}) -> receive {cowboy_http_req, resp_sent} -> ok after 0 -> _ = cowboy_http_req:reply(Code, #http_req{ socket=Socket, transport=Transport, onresponse=OnResponse, connection=close, pid=self(), resp_state=waiting}), ok end, terminate(State).
这个函数不陌生,之前在 Cowboy 源码分析(十八) 我们已经详细讲了,这里就不重复讲了。
好了,关于 {?MODULE, resp_sent} 我们就先讲到这,之后,我们再讲到处理下一个请求时,还会讲到这个消息。
接下来,我们来看 Cowboy 源码分析(十七) 提到的cowboy_http_protocol:onrequest/2 函数,不知道大家还记得吗,如果忘了,翻看下之前的文章吧,这篇文章提到的cowboy_http_protocol:header/3 函数其中一个分支,调用了cowboy_http_protocol:onrequest/2 函数:
header(http_eoh, Req, State=#state{buffer=Buffer}) ->
onrequest(Req#http_req{buffer=Buffer}, State#state{buffer= <<>>});
不知道大家还记不记得什么情况下,该分支会被调用,如果你忘了,看下图就能回忆起来了:
这里需要注意下,{ok, Header, Rest} -> header(Header, Req, State#state{buffer=Rest}); 这里buffer的值被修改成 Rest = <<>>。
当调用 header(http_eoh, Req, State=#state{buffer=Buffer}) 这个分支时,参数的值分别为:
< Req = {http_req,#Port<0.3000>,cowboy_tcp_transport,keepalive,<0.515.0>,
'GET',
{1,1},
undefined,
[<<"localhost">>],
undefined,<<"localhost">>,8080,[],undefined,<<"/">>,
undefined,<<>>,undefined,
[{'Cache-Control',<<"max-age=0">>},
{'Connection',<<"keep-alive">>},
{'Accept-Encoding',<<"gzip, deflate">>},
{'Accept-Language',<<"en-us,en;q=0.5">>},
{'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">>}],
[{'Connection',[<<"keep-alive">>]}],
undefined,[],waiting,<<>>,waiting,[],<<>>,undefined,
{#Fun<cowboy_http.urldecode.2>,crash}}
< State = {state,<0.270.0>,#Port<0.3000>,cowboy_tcp_transport,
[{'_',[{[<<"websocket">>],websocket_handler,[]},
{[<<"eventsource">>],eventsource_handler,[]},
{[<<"eventsource">>,<<"live">>],
eventsource_emitter,[]},
{'_',default_handler,[]}]}],
undefined,undefined,undefined,
{#Fun<cowboy_http.urldecode.2>,crash},
0,5,1,infinity,4096,5000,<<>>,false,infinity,undefined}
< Buffer = <<>>
这里onrequest(Req#http_req{buffer=Buffer}, State#state{buffer= <<>>}); 分别修改了2个记录的buffer的值。
好了,梳理完这些,今天就到这,下一篇,我们就可以看 cowboy_http_protocol:onrequest/2 函数的具体逻辑了。
最后,感谢大家的支持,大家早点休息,晚安。