凡科网站建设样品图,站长之家网站流量查询,企业内部网站模板下载,嘉兴港区建设局网站在上一篇中#xff0c;我们整理了下cowboy_http_protocol:header/3函数#xff0c;在文章的末尾留下2个没有讲到的函数#xff0c;今天#xff0c;我们先看下cowboy_http_protocol:error_terminate/2函数#xff0c;另一个函数下一篇#xff0c;我们再看。cowboy_http_pr… 在上一篇中我们整理了下cowboy_http_protocol:header/3函数在文章的末尾留下2个没有讲到的函数今天我们先看下cowboy_http_protocol:error_terminate/2函数另一个函数下一篇我们再看。cowboy_http_protocol:error_terminate/2函数定义如下 %% 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{socketSocket, transportTransport,onresponseOnResponse}) -receive{cowboy_http_req, resp_sent} - okafter 0 -_ cowboy_http_req:reply(Code, #http_req{socketSocket, transportTransport, onresponseOnResponse,connectionclose, pidself(), resp_statewaiting}),okend,terminate(State).-spec terminate(#state{}) - ok.
terminate(#state{socketSocket, transportTransport}) -Transport:close(Socket),ok. 这个函数仅仅是给客户端一个错误答复。Code是代表返回的HTTP状态码具体每个值代表什么意思大家可以参考下维基百科的HTTP状态码 这个需要大家了解下HTTP协议的相关内容。真的很有必要了解底层的一些协议。建议大家买几本相关的书看看。 好了回到逻辑本身这里有个知识点摘自《Erlang程序设计》 109页 超时时间为0的receive 一个超时时间为0的语句会立即触发一个超时但在此之前系统会尝试对邮箱进行模式匹配我们可以利用这个特性来定一个flush_buffer函数它可以完全清空进程邮箱中的所有消息 flush_buffer() -receive_Any -flush_buffer()after 0 -trueend. 好了回到逻辑中这个函数会检查进程的邮箱中是否存在 {cowboy_http_req, resp_sent} 消息如果存在则返回 ok紧接着马上触发一个超时我们来看下超时中的处理代码 _ cowboy_http_req:reply(Code, #http_req{socketSocket, transportTransport, onresponseOnResponse,connectionclose, pidself(), resp_statewaiting}),ok 这里调用 cowboy_http_req:reply/2 函数并且忽略返回值紧接着返回 ok这里我们来重点看下这个函数 %% equiv reply(Status, [], [], Req)
-spec reply(cowboy_http:status(), #http_req{}) - {ok, #http_req{}}.
reply(Status, Req#http_req{resp_bodyBody}) -reply(Status, [], Body, Req).%% equiv reply(Status, Headers, [], Req)
-spec reply(cowboy_http:status(), cowboy_http:headers(), #http_req{})- {ok, #http_req{}}.
reply(Status, Headers, Req#http_req{resp_bodyBody}) -reply(Status, Headers, Body, Req).%% doc Send a reply to the client.
-spec reply(cowboy_http:status(), cowboy_http:headers(), iodata(), #http_req{})- {ok, #http_req{}}.
reply(Status, Headers, Body, Req#http_req{socketSocket, transportTransport,versionVersion, connectionConnection,methodMethod, resp_statewaiting, resp_headersRespHeaders}) -RespConn response_connection(Headers, Connection),ContentLen case Body of {CL, _} - CL; _ - iolist_size(Body) end,HTTP11Headers case Version of{1, 1} - [{Connection, atom_to_connection(Connection)}];_ - []end,{ReplyType, Req2} response(Status, Headers, RespHeaders, [{Content-Length, integer_to_list(ContentLen)},{Date, cowboy_clock:rfc1123()},{Server, Cowboy}|HTTP11Headers], Req),if Method : HEAD - ok;ReplyType : hook - ok; %% Hook replied for us, stop there.true -case Body of{_, StreamFun} - StreamFun();_ - Transport:send(Socket, Body)endend,{ok, Req2#http_req{connectionRespConn, resp_statedone,resp_headers[], resp_body }}. 不管是 reply/2还是reply/3最后都是调用reply/4函数这个函数是给客户端发一个回复代码量相对多些我们来详细看下 我们看下函数参数参数Status就是Code也就是HTTP状态码Headers为空列表 []Req#http_req{resp_bodyBody}这里的Body为默认值 resp_body Sokcet的值为连接到服务器的连接Transport 为cowboy_tcp_transportVersion 值为 {1,1}其他Connection keepaliveMethod GETRespHeaders []有些值是默认值大家可以看下记录的定义。 来看具体逻辑 RespConn response_connection(Headers, Connection), 这里调用cowboy_http_req:response_connection/2函数函数代码如下 -spec response_connection(cowboy_http:headers(), keepalive | close)- keepalive | close.
response_connection([], Connection) -Connection;
response_connection([{Name, Value}|Tail], Connection) -case Name ofConnection - response_connection_parse(Value);Name when is_atom(Name) - response_connection(Tail, Connection);Name -Name2 cowboy_bstr:to_lower(Name),case Name2 ofconnection - response_connection_parse(Value);_Any - response_connection(Tail, Connection)endend. 这里Headers为空列表 []所以这里只返回了Connection状态也就是keepalive当参数Headers不为空列表时会走下面的分支这里判断Name的值如果为Connection则调用cowboy_http_req:response_connection_parse/1函数代码如下 -spec response_connection_parse(binary()) - keepalive | close.
response_connection_parse(ReplyConn) -Tokens cowboy_http:nonempty_list(ReplyConn, fun cowboy_http:token/2),cowboy_http:connection_to_atom(Tokens). 我在Cowboy 源码分析(十三)和Cowboy 源码分析(十四) 很详细的看了cowboy_http:nonempty_list/2和cowboy_http:token/2这两个函数同样的我们在Cowboy 源码分析(十六) 也讲过ConnAtom cowboy_http:connection_to_atom(ConnTokens)这个函数这里就不重复看了大家如果忘了可以点链接回忆下温故而知新还有个函数cowboy_bstr:to_lower/1更简单也不打算讲。 我们接着看 ContentLen case Body of {CL, _} - CL; _ - iolist_size(Body) end, 这里如果Body的值为{CL, _}格式则ContentLen的值为CL否则为iolist_size(Body)。这个函数我们第一次遇到看下 erlang doc地址http://www.erlang.org/doc/man/erlang.html#iolist_size-1。比较简单大家也可以看下这篇文章坚强2002同学很详细的讲解了iolisthttp://www.cnblogs.com/me-sa/archive/2012/01/31/erlang0034.html我自己也做了些简单的练习如图 好了这个函数大家也好好理解下我们接着往下看 HTTP11Headers case Version of{1, 1} - [{Connection, atom_to_connection(Connection)}];_ - []end, 构建HTTP 1.1 Header如果HTTP协议版本为{1, 1}则返回[{Connection, atom_to_connection(Connection)}];这里我们看下cowboy_http_req:atom_to_connection/1函数 -spec atom_to_connection(keepalive) - _:80;(close) - _:40.
atom_to_connection(keepalive) -keep-alive;
atom_to_connection(close) -close. 一看就能明白不解释了HTTP11Headers这个变量值可能为[{Connection, keep-alive}]或者[{Connection, close}]。 由于篇幅太长今天我们就看到这里下一篇我们继续从下面这一行开始 {ReplyType, Req2} response(Status, Headers, RespHeaders, [{Content-Length, integer_to_list(ContentLen)},{Date, cowboy_clock:rfc1123()},{Server, Cowboy}|HTTP11Headers], Req), 最后谢谢大家支持晚安。 2012-06-25补充 在翻看这篇文章和之后的文章时发现漏讲了cowboy_http_req:reply/4 函数部分代码故补充在这里 if Method : HEAD - ok;ReplyType : hook - ok; %% Hook replied for us, stop there.true -case Body of{_, StreamFun} - StreamFun();_ - Transport:send(Socket, Body)endend,{ok, Req2#http_req{connectionRespConn, resp_statedone,resp_headers[], resp_body }}. 这其实也比较简单这里判断Method 是否全等于 HEAD如果是返回 okReplyType 是否全等于hook如果是返回ok否则根据Body情况进行匹配这里如果是返回HTTP状态码也就是Body为[]则都不匹配如果 Body Hello world!则把Body发送给连接到服务器的Socket。 最后修改了connection的值为RespConnresp_state为done其他就不解释了都能看的懂。 很抱歉之前写完并没有很好的检查。