热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Cowboy源码分析(十一)

上一篇,我们使用debugger和HttpFox很方便了,查看了方法中的变量,不得不说,debugger断点调试还是比较好用的。这一篇,我们仍将使用这些工具来帮助我们了解代码,好了

  上一篇,我们使用debugger和HttpFox很方便了,查看了方法中的变量,不得不说,debugger 断点调试还是比较好用的。这一篇,我们仍将使用这些工具来帮助我们了解代码,好了,接着上一篇继续来看 cowboy_http_protocol:request/2 方法:

  Cowboy 源码分析(十一)

  Cowboy 源码分析(十一)

  上面两张图,是我们上一篇文章,我们看到的函数,以及变量的值,这一篇,我们继续来看下这个函数:

  URLDecode = fun(Bin) -> URLDecFun(Bin, URLDecArg) end,定义了一个匿名函数,Bin是匿名函数定义的变量,我们看下 URLDecFun 这个变量,

  urldecode={URLDecFun, URLDecArg}=URLDec

  还记得 #state{} 在 cowboy_http_protocol:init/4 方法中,urldecode 的定义吗?我截了个图,方便大家回忆,从下面图,我们可以很清楚看到 urldecode 的值:

  那么 urldecode={URLDecFun, URLDecArg}=URLDec 自然就是 urldecode={fun cowboy_http:urldecode/2, crash}=URLDec。

  Cowboy 源码分析(十一)

  弄明白了这几个参数,我们继续往下看:

  {Path, RawPath, Qs} = cowboy_dispatcher:split_path(AbsPath, URLDecode),  看下 cowboy_dispatcher:split_path/2 这个函数:

%% @doc Split a path into a list of path segments.
%%
%% Following RFC2396, this function may return path segments containing any
%% character, including / if, and only if, a / was escaped
%% and part of a path segment.
-spec split_path(binary(), fun((binary()) -> binary())) ->
        {tokens(), binary(), binary()}.
split_path(Path, URLDec) ->
    case binary:split(Path, <<"?">>) of
        [Path] -> {do_split_path(Path, <<"/">>, URLDec), Path, <<>>};
        [<<>>, Qs] -> {[], <<>>, Qs};
        [Path2, Qs] -> {do_split_path(Path2, <<"/">>, URLDec), Path2, Qs}
    end.

-spec do_split_path(binary(), <<_:8>>, fun((binary()) -> binary())) -> tokens().
do_split_path(RawPath, Separator, URLDec) ->
    EncodedPath = case binary:split(RawPath, Separator, [global, trim]) of
        [<<>>|Path] -> Path;
        Path -> Path
    end,
    [URLDec(Token) || Token <- EncodedPath].

  函数的注释意思为:分割路径中的参数成为一个列表。我们看下  case binary:split(Path, <<"?">>) of 这行,这个函数第一次遇到,同样查下erlang doc:http://www.erlang.org/doc/man/binary.html#split-2 比较简单,就是按照第二个参数,分割第一个参数,返回分割后的列表。在这里 Path = <<"/">> ,那么分割后为 [<<"/">>]。

  往下看 cowboy_dispatcher:do_split_path/3 这个函数,同样用到了 binary:split/3 函数,只不过这次是三个参数,如果你认真看了上面我给出的 erlang doc 链接,你应该能知道 binary:split/2 其实调用了 binary:split/3,只不过最后一个参数是 []。那么我们看下这次出现的第三个参数是什么意思呢?下面是erlang doc 给出的说明:

trim

Removes trailing empty parts of the result (as does trim in re:split/3)

移除结果中尾部为空的部分。

global

Repeats the split until the Subject is exhausted. Conceptually the global option makes split work on the positions returned by matches/3, while it normally works on the position returned by match/3.

重复分隔直到不能按Pattern项分割Subject

  好了,弄清楚这2个参数的意思,我们就知道结果:

  EncodedPath = case binary:split(RawPath, Separator, [global, trim]) of

  EncodedPath = case binary:split(<<"/">>, <<"/">>, [global, trim]) of

  EncodedPath =  []

  接下来看下:[URLDec(Token) || Token <- EncodedPath]. 这里是一个列表解析,URLDec = URLDecode = fun(Bin) -> URLDecFun(Bin, URLDecArg) end.

  这里依次对 EncodedPath列表中的元素,依次调用 URLDec(Token),然后返回每个调用后的结果组成的列表。

  这边我把 cowboy_http:urldecode/2 方法贴下下面,我并不打算去解释这个方法,大家详细看下,其实这个方法很简单,就是对 URL 中的参数解码:

%% @doc Decode a URL encoded binary.
%% @equiv urldecode(Bin, crash)
-spec urldecode(binary()) -> binary().
urldecode(Bin) when is_binary(Bin) ->
    urldecode(Bin, <<>>, crash).

%% @doc Decode a URL encoded binary.
%% The second argument specifies how to handle percent characters that are not
%% followed by two valid hex characters. Use `skip' to ignore such errors,
%% if `crash' is used the function will fail with the reason `badarg'.
-spec urldecode(binary(), crash | skip) -> binary().
urldecode(Bin, OnError) when is_binary(Bin) ->
    urldecode(Bin, <<>>, OnError).

-spec urldecode(binary(), binary(), crash | skip) -> binary().
urldecode(<<$%, H, L, Rest/binary>>, Acc, OnError) ->
    G = unhex(H),
    M = unhex(L),
    if    G =:= error; M =:= error ->
        case OnError of skip -> ok; crash -> erlang:error(badarg) end,
        urldecode(<>, <>, OnError);
        true ->
        urldecode(Rest, <bsl 4 bor M)>>, OnError)
    end;
urldecode(<<$%, Rest/binary>>, Acc, OnError) ->
    case OnError of skip -> ok; crash -> erlang:error(badarg) end,
    urldecode(Rest, <>, OnError);
urldecode(<<$+, Rest/binary>>, Acc, OnError) ->
    urldecode(Rest, <>, OnError);
urldecode(<>, Acc, OnError) ->
    urldecode(Rest, <>, OnError);
urldecode(<<>>, Acc, _OnError) ->
    Acc.

  又跑了老远,回到 cowboy_dispatcher:split_path/2,最后返回 {[], <<"/">>, <<>>};

  接着,我们回到 cowboy_http_protocol:request/2 方法,看下这一行:

  {Path, RawPath, Qs} = cowboy_dispatcher:split_path(AbsPath, URLDecode), 可以得到下面几个参数的值为:

  Qs = <<>>
  Path = []
  RawPath = <<"/">>

  继续往下:

  COnnAtom=

    if Keepalive

      version_to_connection(Version);
      true -> close
    end,

  下面是 cowboy_http_protocol:version_to_connection/1 函数:

-spec version_to_connection(cowboy_http:version()) -> keepalive | close.
version_to_connection({1, 1}) -> keepalive;
version_to_connection(_Any) -> close.

  这段代码主要是判断 同时和服务器保持连接。而我们看下 HTTP 关于Keep-Alive的介绍:使客户端到服务器端的连接持续有效,当出现对服务器的后继请求时,Keep-Alive功能避免了建立或者重新建立连接。如果暂时不理解,没关系,先跳过,以后我还会回过头来整体介绍。

  再往下:

  parse_header(#http_req{socket=Socket, transport=Transport, cOnnection=ConnAtom, pid=self(), method=Method, version=Version, path='*', raw_path= <<"*">>, raw_qs= <<>>, Onresponse=OnResponse, urldecode=URLDec}, State);

   这行是解析 HTTP 头部,我们将在下一篇继续和大家分享接下来的代码,谢谢大家支持。


推荐阅读
  • 可空类型可空类型主要用于参数类型声明和函数返回值声明。主要的两种形式如下: ... [详细]
  • PHP图片截取方法及应用实例
    本文介绍了使用PHP动态切割JPEG图片的方法,并提供了应用实例,包括截取视频图、提取文章内容中的图片地址、裁切图片等问题。详细介绍了相关的PHP函数和参数的使用,以及图片切割的具体步骤。同时,还提供了一些注意事项和优化建议。通过本文的学习,读者可以掌握PHP图片截取的技巧,实现自己的需求。 ... [详细]
  • 本文介绍了使用PHP实现断点续传乱序合并文件的方法和源码。由于网络原因,文件需要分割成多个部分发送,因此无法按顺序接收。文章中提供了merge2.php的源码,通过使用shuffle函数打乱文件读取顺序,实现了乱序合并文件的功能。同时,还介绍了filesize、glob、unlink、fopen等相关函数的使用。阅读本文可以了解如何使用PHP实现断点续传乱序合并文件的具体步骤。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • 简述在某个项目中需要分析PHP代码,分离出对应的函数调用(以及源代码对应的位置)。虽然这使用正则也可以实现,但无论从效率还是代码复杂度方面考虑ÿ ... [详细]
  • R语言拼接字符串_paste的用法说明
    这篇文章主要介绍了R语言拼接字符串_paste的用法说明,具有很好的参考价值,希望对大家有所帮助。一 ... [详细]
  • 工作经验谈之-让百度地图API调用数据库内容 及详解
    这段时间,所在项目中要用到的一个模块,就是让数据库中的内容在百度地图上展现出来,如经纬度。主要实现以下几点功能:1.读取数据库中的经纬度值在百度上标注出来。2.点击标注弹出对应信息。3 ... [详细]
  • 获取时间的函数js代码,js获取时区代码
    本文目录一览:1、js获取服务器时间(动态)2 ... [详细]
  • Nginx使用(server参数配置)
    本文介绍了Nginx的使用,重点讲解了server参数配置,包括端口号、主机名、根目录等内容。同时,还介绍了Nginx的反向代理功能。 ... [详细]
  • 本文介绍了一个Python函数same_set,用于判断两个相等长度的数组是否包含相同的元素。函数会忽略元素的顺序和重复次数,如果两个数组包含相同的元素,则返回1,否则返回0。文章还提供了函数的具体实现代码和样例输入输出。 ... [详细]
  • Python的参数解析argparse模块的学习
    本文介绍了Python中参数解析的重要模块argparse的学习内容。包括位置参数和可选参数的定义和使用方式,以及add_argument()函数的详细参数关键字解释。同时还介绍了命令行参数的操作和可接受数量的设置,其中包括整数类型的参数。通过学习本文内容,可以更好地理解和使用argparse模块进行参数解析。 ... [详细]
  • tcpdump 4.5.1 crash 深入分析
    tcpdump 4.5.1 crash 深入分析 ... [详细]
  • 颜色迁移(reinhard VS welsh)
    不要谈什么天分,运气,你需要的是一个截稿日,以及一个不交稿就能打爆你狗头的人,然后你就会被自己的才华吓到。------ ... [详细]
  • 前言:拿到一个案例,去分析:它该是做分类还是做回归,哪部分该做分类,哪部分该做回归,哪部分该做优化,它们的目标值分别是什么。再挑影响因素,哪些和分类有关的影响因素,哪些和回归有关的 ... [详细]
  • mapreduce源码分析总结
    这篇文章总结的非常到位,故而转之一MapReduce概述MapReduce是一个用于大规模数据处理的分布式计算模型,它最初是由Google工程师设计并实现的ÿ ... [详细]
author-avatar
lhpa
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有