大家好,无意间发现 CodeMirror,挺不错的,在线代码编辑器,支持erlang,go等等语言,官方介绍如下:
CodeMirror is a JavaScript component that provides a code editor in the browser. When a mode is available for the language you are coding in, it will color your code, and optionally help with indentation.
A rich programming API and a CSS theming system are available for customizing CodeMirror to fit your application, and extending it with new functionality.
Erlang版本地址如下:http://codemirror.net/mode/erlang/index.html
看到这个不错的东西,我第一感觉是怎么加到博客上,因为我太喜欢这个样式了。
好了,回到Cowboy,上一篇,我们提到了cowboy_http_req:parse_header/4这个函数,今天我们来详细看下:
%% @todo This doesn't look in the cache. parse_header(Name, Req=#http_req{p_headers=PHeaders}, Default, Fun) -> case header(Name, Req) of {undefined, Req2} -> {Default, Req2#http_req{p_headers=[{Name, Default}|PHeaders]}}; {Value, Req2} -> case Fun(Value) of {error, badarg} -> {error, badarg}; P -> {P, Req2#http_req{p_headers=[{Name, P}|PHeaders]}} end end.
这边我们可以用debugger工具看下第一次调用这个函数接受到的参数的值:
从上面,我们可以看到 p_headers=PHeaders =[],Default = [],Name = 'Connetion',弄清楚了这几个值,我们看下:
case header(Name, Req) of
我们看下这一行,调用了 cowboy_http_req:header/2,这个函数,代码如下:
%% @equiv header(Name, Req, undefined) -spec header(atom() | binary(), #http_req{}) -> {binary() | undefined, #http_req{}}. header(Name, Req) when is_atom(Name) orelse is_binary(Name) -> header(Name, Req, undefined). %% @doc Return the header value for the given key, or a default if missing. -spec header(atom() | binary(), #http_req{}, Default) -> {binary() | Default, #http_req{}} when Default::any(). header(Name, Req, Default) when is_atom(Name) orelse is_binary(Name) -> case lists:keyfind(Name, 1, Req#http_req.headers) of {Name, Value} -> {Value, Req}; false -> {Default, Req} end.
cowboy_http_req:header/2 直接调用了cowboy_http_req:header/3 函数,传递第三个参数为 undefined。这个函数也很简单,如果 Req#http_req.headers列表中,存在Name,则返回 {Name, Value},然后函数返回 {Value, Req},否则,函数返回 {Default, Req} = {undefined, Req}。这里:
Req#http_req.headers = [{'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:12.0) Gecko/20100101 Firefox/12.0">>},
{'Host',<<"localhost">>}]
是存在该key的,所以返回 {<<"keep-alive">>, Req}。
接着我们回到 cowboy_http_req:parse_header/4函数:
{undefined, Req2} ->
{Default, Req2#http_req{p_headers=[{Name, Default}|PHeaders]}};
当返回 {undefined, Req2} 时,函数返回 {[], Req2#http_req{p_headers=[{'Connection', [] } | [] ]}};
当返回 {Value, Req2} = {<<"keep-alive">>, Req2} 时,执行以下代码:
case Fun(Value) of {error, badarg} -> {error, badarg}; P -> {P, Req2#http_req{p_headers=[{Name, P}|PHeaders]}} end
这里调用传递进来的匿名函数,我们回顾下这个匿名函数是如何定义的:
fun (Value) -> cowboy_http:nonempty_list(Value, fun cowboy_http:token_ci/2) end);
如果大家忘了,这2个函数的实现,可以回到 Cowboy 源码分析(十三) Cowboy 源码分析(十四),回忆下,这里 Value = <<"keep-alive">>,那么如果正确,将会返回列表,
P = [<<"keep-alive">>],那么cowboy_http_req:parse_header/4这个函数将返回 {[<<"keep-alive">>], Req2#http_req{p_headers=[{'Connection', [<<"keep-alive">>]} | [] ]}}。
好了,这个函数到现在就可以告一段落了,当这个函数返回时,我们将回到:cowboy_http_protocol:header/3
header({http_header, _I, 'Connection', _R, Connection}, Req=#http_req{headers=Headers}, State=#state{ req_keepalive=Keepalive, max_keepalive=MaxKeepalive}) when Keepalive < MaxKeepalive -> Req2 = Req#http_req{headers=[{'Connection', Connection}|Headers]}, {ConnTokens, Req3} = cowboy_http_req:parse_header('Connection', Req2), ConnAtom = cowboy_http:connection_to_atom(ConnTokens), parse_header(Req3#http_req{connection=ConnAtom}, State);
大家还记得这个函数吗?估计都忘了,因为我也有点忘了,大家翻看我以前的文章吧,我也看看去:
下一篇,我们将继续讲解这个函数,从 ConnAtom = cowboy_http:connection_to_atom(ConnTokens), 继续往下看吧。
%% @doc Walk through a tokens list and return whether %% the connection is keepalive or closed. %% %% The connection token is expected to be lower-case. -spec connection_to_atom([binary()]) -> keepalive | close. connection_to_atom([]) -> keepalive; connection_to_atom([<<"keep-alive">>|_Tail]) -> keepalive; connection_to_atom([<<"close">>|_Tail]) -> close; connection_to_atom([_Any|Tail]) -> connection_to_atom(Tail).
好了,夜已深,大家早点休息,最后,谢谢大家支持。