大家好,无意间发现 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版本地址如下:
看到这个不错的东西,我第一感觉是怎么加到博客上,因为我太喜欢这个样式了。
好了,回到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">>,那么如果正确,将会返回列表,