Cowboy 源码分析(十四)
2012-06-05 00:58 rhinovirus 阅读(1493) 评论(0) 编辑 收藏 举报大家好,今天接着做几个测试,把上一篇理解并不透彻的几个方法再加强下:
第一个,测试 cowboy_http:whitespace/2 方法的作用,测试代码以及结果如下,左边是测试代码,右边是测试结果:
这样就能很明白的看出这个这个函数的作用了,注意:测试结果第二行,\s 变成空格了。
第二个,测试 cowboy_http:list/3 以及 cowboy_http:token_ci/2 方法,增加打印log,测试代码如下:
-module(main). -export([start/0, stop/0]). start() -> io:format("test 1 ~n"), list(<<>>, fun token_ci/2, []), io:format("test 2 ~n"), list(<<",abc">>, fun token_ci/2, []), ok. %% @doc Skip whitespace. -spec whitespace(binary(), fun()) -> any(). whitespace(<< C, Rest/binary >>, Fun) when C =:= $\s; C =:= $\t -> ip:format("call whitespace 1~n"), whitespace(Rest, Fun); whitespace(Data, Fun) -> io:format("call whitespace 2~n"), Fun(Data). -spec list(binary(), fun(), [binary()]) -> [any()] | {error, badarg}. %% From the RFC: %% <blockquote>Wherever this construct is used, null elements are allowed, %% but do not contribute to the count of elements present. %% That is, "(element), , (element) " is permitted, but counts %% as only two elements. Therefore, where at least one element is required, %% at least one non-null element MUST be present.</blockquote> list(Data, Fun, Acc) -> whitespace(Data, fun (<<>>) -> io:format("1~n"), Acc; (<< $,, Rest/binary >>) -> io:format("2~n"), list(Rest, Fun, Acc); (Rest) -> io:format("3~n"), Fun(Rest, fun (D, I) -> io:format("4~n"), whitespace(D, fun (<<>>) -> io:format("5~n"), [I|Acc]; (<< $,, R/binary >>) -> io:format("6~n"), list(R, Fun, [I|Acc]); (_Any) -> io:format("7~n"), {error, badarg} end) end) end). %% @doc Parse a case-insensitive token. %% %% Changes all characters to lowercase. -spec token_ci(binary(), fun()) -> any(). token_ci(Data, Fun) -> io:format("call token_ci. ~n"), token(Data, Fun, ci, <<>>). -spec token(binary(), fun(), ci | cs, binary()) -> any(). token(<<>>, Fun, _Case, Acc) -> io:format("call token 1. ~n"), Fun(<<>>, Acc); token(Data = << C, _Rest/binary >>, Fun, _Case, Acc) when C =:= $(; C =:= $); C =:= $<; C =:= $>; C =:= $@; C =:= $,; C =:= $;; C =:= $:; C =:= $\\; C =:= $"; C =:= $/; C =:= $[; C =:= $]; C =:= $?; C =:= $=; C =:= ${; C =:= $}; C =:= $\s; C =:= $\t; C < 32; C =:= 127 -> io:format("call token 2. ~n"), Fun(Data, Acc); token(<< C, Rest/binary >>, Fun, Case = ci, Acc) -> io:format("call token 3. ~n"), %%C2 = cowboy_bstr:char_to_lower(C), C2 = char_to_lower(C), token(Rest, Fun, Case, << Acc/binary, C2 >>); token(<< C, Rest/binary >>, Fun, Case, Acc) -> io:format("call token 4. ~n"), token(Rest, Fun, Case, << Acc/binary, C >>). %% @doc Convert [A-Z] characters to lowercase. %% @end %% We gain noticeable speed by matching each value directly. -spec char_to_lower(char()) -> char(). char_to_lower($A) -> $a; char_to_lower($B) -> $b; char_to_lower($C) -> $c; char_to_lower($D) -> $d; char_to_lower($E) -> $e; char_to_lower($F) -> $f; char_to_lower($G) -> $g; char_to_lower($H) -> $h; char_to_lower($I) -> $i; char_to_lower($J) -> $j; char_to_lower($K) -> $k; char_to_lower($L) -> $l; char_to_lower($M) -> $m; char_to_lower($N) -> $n; char_to_lower($O) -> $o; char_to_lower($P) -> $p; char_to_lower($Q) -> $q; char_to_lower($R) -> $r; char_to_lower($S) -> $s; char_to_lower($T) -> $t; char_to_lower($U) -> $u; char_to_lower($V) -> $v; char_to_lower($W) -> $w; char_to_lower($X) -> $x; char_to_lower($Y) -> $y; char_to_lower($Z) -> $z; char_to_lower(Ch) -> Ch. stop() -> ok.
测试结果如下:
现在大家对于上一篇,提到的 cowboy_http:nonempty_list(Value, fun cowboy_http:token_ci/2) 是不是有进一步的理解了,这里之所以会比较复杂,其实主要是作者把匿名函数当作参数传递,怎么说呢,使用这种方式,有它的灵活性在,但是其实这降低了代码的可读性,所以我个人推荐大家不建议用这种复杂的嵌套多层的匿名函数。
还有个知识点差点忘说了,erlang对于二进制数据的处理还是比较强大了,而新手(包括我)理解二进制解析的时候,会吃力一些,这时候大家动手,写几个测试函数,能够加深理解。
cowboy_http:token/4 方法有用到一个方法,大家在上面我贴出来的代码中,也能看到,这个方法很简单,字符的大写转换成小写。
我们理解完上面这些代码的时候,就可以继续往下看了。还记得上一篇提到的cowboy_http_req:parse_header/3 这个函数吗:
parse_header(Name, Req, Default) when Name =:= 'Connection' -> parse_header(Name, Req, Default, fun (Value) -> cowboy_http:nonempty_list(Value, fun cowboy_http:token_ci/2) end);
这里定义了一个匿名函数,作为第四个参数传递到 cowboy_http_req:parse_header/4 这个函数,我们将在下一篇中,继续看下这个函数。
今天就到这里,洗澡睡觉了,谢谢大家支持。
本文基于署名-非商业性使用 3.0许可协议发布,欢迎转载,演绎,但是必须保留本文的署名rhinovirus(包含链接http://www.cnblogs.com/rhinovirus/),且不得用于商业目的。如您有任何疑问或者授权方面的协商,请与我联系。