Cowboy 源码分析(十五)

  大家好,无意间发现 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.

  地址:http://codemirror.net/

  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工具看下第一次调用这个函数接受到的参数的值:

  Cowboy 源码分析(十五)_第1张图片

  从上面,我们可以看到 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);

  大家还记得这个函数吗?估计都忘了,因为我也有点忘了,大家翻看我以前的文章吧,我也看看去:

  Cowboy 源码分析(十二)

  Cowboy 源码分析(十三)

  下一篇,我们将继续讲解这个函数,从 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).

  好了,夜已深,大家早点休息,最后,谢谢大家支持。

你可能感兴趣的:(源码分析)