面试小抄本之网络协议篇

    Web 与 HTTP

    HTTP 协议的出现主要是为了解决文本传输的难题,目前已经超出 Web 应用场景;被广泛应用的主流版本是 HTTP/1.1,参考 RFC 2616

    URI(Uniform Resource Identifier)

    统一资源标识符,即由某个协议方案表示的资源的定位标识符

    http://user:pass@www.example.com:80/dir/index.html?uid=1#part1
    
    • 协议方案名:http
    • 认证信息:user:pass(可选)
    • 服务器地址:www.example.com(域名或IP)
    • 服务器端口号:80(可选)
    • 带层次的文件路径:/dir/index.html
    • 查询字符串:uid=1(可选)
    • 锚点:part1(可选)

    HTTP 报文

    报文(message) 是 HTTP 通信中的基本单位,由8位组字节流(octet sequence)组成

    message = start-line
              *(message-header CRLF)
              CRLF
              [message-body]
    

    其中

    start-line = Request-Line | Response-Line
    message-header = field-name ":" [ field-value ]
    

    报文主体(message-body) 用于传输请求或响应的 实体主体(entity-body),通常两者是相等的,仅当传输时进行编码操作时、实体主体内容变化

    message-body = entity-body
                 | <entity-body encoded as per Transfer-Encoding>
    

    HTTP 请求报文

    请求行(包含请求方法请求 URI协议版本),可选的首部字段内容实体构成

    POST /form/submit.cgi HTTP/1.1                      请求行
    Host: example.com                               } ### 实体(Entity)开始行
    Connection: keep-alive                          }
    Content-Type: application/x-www-form-urlencoded }   首部字段
    Content-Length: 16                              }
    ...                                             }
                                                        空行(CR+LF)
    name=a&age=20                                       内容实体
    

    HTTP 响应报文

    响应行协议版本状态码原因短语),可选的首部字段内容实体构成

    HTTP/1.1 200 OK                                     响应行
    Date: Tue, 10 Jul 2012 06:50:15 GMT             } ### 实体(Entity)开始行
    Content-Length: 362                             }
    Content-Type: text/html                         }   首部字段
    ...                                             }
                                                        空行(CR+LF)
    <html>                                          }   内容实体
    ...                                             }
    

    HTTP 报文传输

    发送邮件时,可以在邮件中写入文字并添加多份附件,这是因为采用了 MIME(Multipurpose Internet Mail Extension, 多用途因特网邮件扩展)机制,允许邮件处理文本、图片、视频等多个类型的数据。例如,图片等二进制数据以 ASCII 码字符串编码的方式指明,就是利用 MIME 来描述标记数据类型。而在 MIME 扩展中会使用一种称为多部分对象集合(Multipart)的方法,来容纳多份不同类型的数据。

    HTTP 协议中也采纳了 Multipart,发送的一份报文主体内可能含有多类型实体;通常在图片或文本文件等上传时使用。

    使用 Multipart 时,首部字段需定义 Content-Type,字段值为 multipart/form-data(表单文件上传)或 multipart/byteranges(状态码 206 响应报文);同时要定义 boundary 字符串以划分各类实体。注:Multipart 中每个部分类型也可以含有首部字段。

    multipart/form-data

    Content-Type: multipart/form-data; boundary=AaB03x
     
    --AaB03x
    Content-Disposition: form-data; name="field1"
     
    Joe Blow
    --AaB03x
    Content-Disposition: form-data; name="pics"; filename="file1.txt"
    Content-Type: text/plain
     
    ...(file1.txt的数据)...
    --AaB03x--
    

    multipart/byteranges

    HTTP/1.1 206 Partial Content
    Date: Fri, 13 Jul 2012 02:45:26 GMT
    Last-Modified: Fri, 31 Aug 2007 02:02:20 GMT
    Content-Type: multipart/byteranges; boundary=THIS_STRING_SEPARATES
    
    --THIS_STRING_SEPARATES
    Content-Type: application/pdf
    Content-Range: bytes 500-999/8000
    
    ...(范围指定的数据)...
    --THIS_STRING_SEPARATES
    Content-Type: application/pdf
    Content-Range: bytes 7000-7999/8000
    
    ...(范围指定的数据)...
    --THIS_STRING_SEPARATES--
    

    HTTP 方法

    • GET:获取资源
    • POST:传输实体主体
    • PUT:传输文件
    • DELETE:删除文件
    • HEAD:仅获取报文首部,curl -I example.com
    • OPTIONS:查询支持的方法,curl -X OPTIONS example.com
    • TRACE:回显服务器收到的请求,主要用于测试

    HTTP 状态码

    • 1XX 请求已接收,继续处理
    • 2XX 成功:200 OK / 204 No Content / 206 Partial Content
    • 3XX 重定向:301 Moved Permanently / 302 Not Found / 303 See Other / 304 Not Modified / 307 Temporary Redirect
    • 4XX 客户端错误:400 Bad Request / 401 Unauthorized / 403 Forbidden / 404 Not Found
    • 5XX 服务端错误:500 Internal Server Error / 503 Service Unavailable

    206 Partial Content: 表示客户端进行了范围请求,而服务器成功执行了这部分的 GET 请求;响应报文中包含由 Content-Range 指定范围的实体内容

    301 Moved Permanently: 表示请求的资源已经分配了新的 URI(Location 首部字段)

    $ curl -I google.com
    HTTP/1.1 301 Moved Permanently
    Location: http://www.google.com/
    

    302 Not Found: 表示资源临时移动,下例中 Google 会重定向至 com.hk 域(根据请求IP的地理位置返回相应 ccTLD 的 URI)。访问 http://www.google.com/ncr 避免基于地理位置的重定向,ncr 即 No Country Redirection

    $ curl -I www.google.com
    HTTP/1.1 302 Found
    Location: http://www.google.com.hk/url?sa=p&hl=zh-CN&...
    

    304 Not Modified: 表示客户端发送了附带条件请求(If-XXX);304 状态码返回时,不包含响应的主体部分

    401 Unauthorized: 表示发送的请求需带有 HTTP 认证信息(基本认证、摘要认证);若之前已进行过1次请求,则表示认证失败


    HTTP 首部字段

    请求和响应都会使用首部字段,主要传递如报文主体大小、认证信息等内容。首部字段由冒号分割的字段名和字段值构成,如:Content-Type: text/html

    一个字段可能包含复合指令,如:Keep-Alive: timeout=15, max=100

    1. 通用首部

    • Cache-Control: 缓存指令
    • Connection: 连接管理指令
    • Date: 创建报文的时间
    • Trailer: 报文末端首部一览
    • Transfer-Encoding: 报文主体的传输编码方式
    • Upgrade: 升级为其他协议
    • Via: 代理服务器响应信息,记录了报文传输路径(类似 traceroute)
    • Warning: 错误通知
    • Pragma: 旧版本遗留字段

    Connection

    • 控制不再转发给代理的首部字段

    • 管理持久连接,即服务端想明确断开连接时,指定 Connection: close

    Transfer-Encoding

    分块传输编码(Chunked Transfer Coding)将实体主体分成多个块,每一块用十六进制标记块大小。Transfer-Encoding: chunked 即指定使用分块传输。

    HTTP/1.1 200 OK
    Transfer-Encoding: chunked
    ...
    
    cf0    ←16进制(10进制为3312)
    
    ...3312字节分块数据...
    
    392    ←16进制(10进制为914)
    
    ...914字节分块数据...
    
    0
    

    2. 请求首部

    • Authorization: 认证信息
    • Host: 被请求资源的主机和端口号(必须
    • Max-Forwards: 最大传输逐跳数
    • Proxy-Authorization: 代理服务器要求客户端的认证信息
    • Range: 实体的字节范围请求。如 Range: bytes=5001-10000,服务端返回 206 Partial Content,当无法处理范围请求时、返回 200 OK 及全部资源。通过范围请求可以实现断续下载和多线程下载
    • Referer: 请求的 URI 是从哪里发起的,出于安全考虑、客户端可以选择不发送该字段(一些工业级防火墙会把出口包的 referer 清除,以保护局域网隐私)
    • User-Agent: 客户端程序信息

    同缓存控制相关的条件请求字段:

    • If-Match / If-None-Match: 比较 ETag
    • If-Modified-Since / If-Unmodified-Since: 比较资源更新时间

    内容协商机制(Content Negotiation),即客户端和服务端就响应的资源内容进行协商、以返回最合适的资源,比如 Web 站点的语言版本等。Accept-XXX 首部字段即用来实现协商:

    • Accept: 可处理的媒体类型及权重
    • Accept-Charset: 优先的字符集
    • Accept-Encoding: 优先的内容编码,gzip / compress / deflate / identity
    • Accept-Language: 优先的自然语言

    附注:利用HTTP host头攻击的技术

    3. 响应首部

    • Accept-Ranges: 告知客户端能否处理范围请求,bytes / none
    • Age: 推算资源创建了多久,单位为秒;代理创建响应时必须加上该字段
    • ETag: 资源信息
    • Location: 指示客户端重定向 URI,一般配合 3XX Redirection 使用
    • Retry-After: 对再次发起请求的时间要求
    • Server: 服务端程序信息
    • Vary: 对缓存进行控制,如 Vary: Accept-Language 指示缓存代理服务器只能返回符合 Accept-Language 字段值的资源,如果没有需重新请求源服务器

    4. 实体首部

    主要是对请求头部的应答,比如 Content-XXX 对应 Accept-XXX 请求

    • Allow: 资源支持的 HTTP 方法
    • Content-Encoding: 实体主体适用的编码方式,gzip / compress / deflate / identity
    • Content-Language: 实体主体的自然语言
    • Content-Length: 实体主体大小(Bytes),如果使用分块传输时、不能使用 Content-Length 字段
    • Content-Location: 替代对应资源的 URI
    • Content-MD5: 对报文主体执行 MD5 算法获得128位二进制数,通过 Base64 编码后写入该字段值;主要用于检查报文主体在传输过程中是否完整
    • Content-Range: 对范围请求的响应,如 Content-Range: bytes 5001-10000/10000,表示当前发送部分及整个实体大小
    • Content-Type: 实体主体的媒体类型,如 Content-Type: text/html; charset=UTF-8
    • Expires: 实体主体的过期日期
    • Last-Modified: 资源的最后修改时间

    5. 非 RFC2616 定义的首部字段

    在 HTTP 等多种协议中,通过给非标准参数加前缀 X- 来区别,但在 RFC 6648 - Depracating the “X-“ Perfix and Similar Constructs in Application Protocals 中提议停止该做法

    X-Frame-Options

    用于控制网站内容在其他站点的 Frame 标签内的显示问题,主要防止点击劫持(clickjacking);字段值为 DENY(拒接加载)、SAMEORIGIN(同源页面匹配时许可)

    X-XSS-Protection

    控制浏览器 XSS 防护机制的开关,字段值为 0(将 XSS 过滤设为无效)、1(有效)

    X-Csrf-Token / X-CSRFToken

    跨站请求伪造(CSRF)防护

    X-Requested-With

    用于识别 Ajax 请求,多数 JavaScript 框架定义字段值为 XMLHttpRequest

    X-Forwarded-For

    是一个事实标准(de facto standard)的扩展字段,用于标识经过了代理(Proxy)及负载均衡(Load Balancer)的客户端IP。通过 Proxy 的连接只会表现出最后一跳代理的IP,XFF 的有效也依赖于代理服务器是否可信。

    XFF 格式:X-Forwarded-For: client1, proxy1, proxy2

    Content-Security-Policy

    内容安全策略,限定浏览器能够加载的内容来源(Content Origins),包括 JS / CSS / 字体 / 图片 / 音视频 / Web Workers / HTML Frames,以及嵌入式对象如 Java Applets / ActiveX 等。

    CSP 指令如 script-src / style-src / img-src 即定义相应资源类型的加载策略;指令值如 none(不允许任何内容)、self(同源内容,相同协议、域名和端口)、a.com / *.a.com(限定域名 / 子域名)等。

    X-Content-Security-Policy, X-Webkit-CSP (Deprecated)

    详细阅读:

    突破 SOP 的限制,有几种策略:

    • 跨域资源共享(Corss-Origin Resource Sharing, CORS):要求被请求域在响应报头添加 Access-Control-Allow-Origin 标签以允许指定域的站点、访问当前域的资源;CROS 实现主要依赖服务端
    • JSONP:客户端无法访问基于 XMLHttpRequest 跨域请求得到的数据(注:SOP 不限制发送请求,仅限制访问得到的数据),但具有 src 属性的标签(如 script, img, iframe)不受 SOP 限制,浏览器可以执行请求得到的 JavaScript 代码。很多访问统计的插件是通过 JSONP 实现;另对于 JSONP 的请求调用是基于对被请求域的信任,因此也有一定的安全隐患
    • HTML5 Web Messaging:当开发者可以修改请求域及被请求域的页面时,可以考虑基于 Web Messaging 实现页面间跨域通信
    • WebSocket:允许跨域通信

    Cookie / Set-Cookie

    HTTP 是无状态协议(stateless),协议本身不对请求和响应做持久化处理(不保留之前一切的报文信息);因此对于服务器而言,无法区分每一个请求是来自同一个客户端还是不同客户端。状态保存通过 Cookie 或者 QueryString(不安全)实现。

    • name: 指定 Cookie 名 / 值
    • expires: 指定 Cookie 有效期,若不指定则截止到浏览器会话关闭
    • path: 指定服务器上的路径作为 Cookie 适用对象
    • domain: 指定域名作为 Cookie 适用对象,若不指定则为创建 Cookie 的服务器域名
    • secure: 仅在 HTTPS 安全通信时才发送
    • HttpOnly: 不能被 javaScript 脚本访问,如设定后 document.cookie 无法读取

    DNT

    拒接信息被收集(Do Not Track),字段值为 0(同意被追踪)、1(拒接被追踪);需要 Web 服务器提供支持

    6. 端到端首部 / 逐跳首部

    HTTP 首部字段将定义成缓存代理和非缓存代理的行为,分成端到端首部(End-to-end Header)及逐跳首部(Hop-by-hop header)

    代理必须转发端到端首部;逐跳首部只对单次转发有效,仅如下字段:

    • Connection
    • Keep-Alive
    • Proxy-Authenticate
    • Proxy-Authorization
    • Trailer
    • TE
    • Transfer-Encoding
    • Upgrade

    HTTP 持久连接

    为了避免每次 HTTP 请求造成无谓的 TCP 连接建立和断开,HTTP/1.1 的 Keep-alive 规定了只要任意一端没有明确提出断开连接,则保持 TCP 连接状态。HTTP/1.1 所有的连接默认为持久连接。

    Client                  Server
        |   ===   SYN   ==>   |
        |   <== SYN/ACK ==>   |     } 建立 TCP 连接
        |   ===   ACK   ==>   |
    
        |   === HTTP Req ==>  |
        |   <== HTTP Res ===  |     } HTTP 持久连接
        |   === HTTP Req ==>  |
        |   <== HTTP Res ===  |
    
        |   <==   FIN   ==>   |
        |   ===   ACK   ==>   |     } 断开 TCP 连接
        |   ===   FIN   ==>   |
        |   <==   ACK   ===   |
    

    基于持久连接,管线化(pipelining)允许不用等待响应即可直接发送下一个请求,即可以同时并行发送多个请求,不需要依次等待响应。

    Client                      Server
        |      建立 TCP 连接      |
    
        |  === HTTP Req (1) ==>  |
        |  === HTTP Req (2) ==>  |
        |  <== HTTP Res (1) ===  |
        |  <== HTTP Res (2) ===  |
    
        |      断开 TCP 连接      |
    

    Pipelining 本质上也仅是一种补丁优化方案,存在线头阻塞问题(Head of line blocking):即客户端还是按照发送请求的顺序来接受响应,如果某个请求阻塞、会导致后续请求都受到影响。

    而且 RFC2616 中定义一个域最多2个连接,现代浏览器如 Chrome 允许同时打开 6个HTTP6个HTTPS 连接(chrome://net-internals#sockets)

    Chrome DevTools Network 面板中同一个 Connection-Id 即表示连接被复用:… a TCP connection was reused instead of handshaking and establishing a new one. RTT cost + TCP slow-start means that established connections send data faster.


    通信数据转发程序

    1. 代理服务器

    代理不改变请求 URI,接收客户端发送的请求,转发送给前方持有资源的目标服务器(源服务器);转发时附加 Via 首部字段以标记出经过的主机信息

    代理的作用:

    • 利用缓存技术减少流量(缓存代理,Caching Proxy)
    • 实现访问控制(ACL)

    根据转发请求/响应时是否对报文进行修改,可以区分为透明代理非透明代理

    2. 网关

    网关的工作机制和代理十分相似,而网关能使通信线路上的服务器提供非 HTTP 协议服务

    3. 隧道

    隧道通常作为加密通信线路使用(使用 SSL 等),隧道本身不会去解析 HTTP 请求


    HTTP 1.x 报文传输的瓶颈

    • 不能在同一个连接上进行并发请求;客户端通常需要开启多个连接来加速请求资源的过程
    • 请求只能从客户端开始;客户端不可接收除响应外的指令
    • 请求 / 响应首部未经压缩;每次互相发送相同的首部造成的浪费较多

    基于 HTTP 1.x 的长连接解决方案:

    1. Ajax 解决方案

      Ajax 的核心技术是名为 XMLHTTPRequest 的 API,通过 JavaScript 的调用就能和服务器进行 HTTP 通信;因此可以从已加载完的 Web 页面上发起请求,只更新局部页面。

      基于 Ajax 可以实现轮询以建立实时通讯。

    2. Comet 解决方案

      Comet 模拟实现了 Server Push 功能,即服务端收到请求后首先将响应置于挂起状态,当服务端有内容更新时、再返回响应。

      Comet 面临的问题:长连接通信的不确定性,即客户端不知道何时服务端能返回数据;服务端需要维持一个连接、且不知道何时能释放该连接(不知道客户端是否已关闭)

      优化手段通常是在 C/S 间保持心跳信息,Server 端同时要建立超时机制。

    3. Flash 解决方案

      Flash 有自己的 Socket 实现,为实时通讯提供了可能,通过 JavaScript 调用 Flash 的 API 与服务端通信;但 Flash 对移动设备支持不佳。

    参考阅读:Comet:基于 HTTP 长连接的“服务器推”技术


    HTTP/2

    2015.5 HTTP/2 以 RFC 7540 正式发布,在与 HTTP 1.x 语义兼容的基础上,优化传输效率、减少网络延迟。

    HTTP/2 enables a more efficient use of network resources and a reduced perception of latency by introducing header field compression and allowing multiple concurrent exchanges on the same connection. It also introduces unsolicited push of representations from servers to clients.

    协议介绍

    • 帧(Frame):HTTP/2 通信的最小单元,是一个二进制结构
    • 消息(Message):代表一次请求 / 响应,包含多个帧组成
    • 连接(Connection):对应的 TCP 连接,可以有多个流
    • 流(Stream):连接上的双向字节流,具备多路复用(Multiplexed)和优先级设定(Prioritized)特性

    同域名下的通信都在单个 Connection 上完成,该连接可以承载多个 Stream,每个流以 Message 形式发送,消息由多个 Frame 组成,帧可以乱序发送(根据 HEADERS 的流标识重组)

    带来的优势:

    • 二进制传输协议:相对文本协议、解析起来更高效(对帧的边界识别更容易)且传输安全
    • 多路复用:通过单一的 HTTP/2 连接发起多重请求
    • 赋予请求优先级
    • 头部压缩
    • 服务端推送

    1. 多路复用

    参考 HTTP 1.1 持久连接,HTTP/2 的多路复用体现在:当页面向同一个域发起多个请求时,会自动合并到一个连接中

    因此以下 HTTP 1.x 的 Web 工程化方案可以不再使用:

    • 资源合并:如 CSS Sprite, JS / CSS 文件拼接,资源合并的目的在于减少 HTTP 请求数,但这会造成冗余加载(耗时增加、且流量浪费)及缓存失效(微小模块的改动都会引起整体资源的更新)
    • 多域分发:由于对同一个域发起的请求数有限,采用多域部署来加快浏览器的资源加载,同时也将 Cookie 分域管理

    2. 头部压缩

    HTTP/2 通过在客户端 / 服务端使用 首部表 存储及更新头部字段(键值对形式),且对于新的请求 / 响应中的头部信息、只做增量传递。

    压缩算法简述:用静态表(Static Table,0~61共62个条目)将 HTTP/2 头部常用字串替换为索引,用动态表(Dynamic Table)保存需要动态修改的内容(如 cookie);使用霍夫曼编码对文本字串进行压缩。

    详细阅读:HTTP/2 头部压缩技术介绍

    3. 服务器推送

    浏览器请求得到的页面 HTML 往往依赖一些 CSS / JS 等资源才能渲染,因此服务器在浏览器发现外链并发起请求前主动推送资源

    对比各个请求模型下的时延:

    4. HTTP/2 协商

    客户端协商 HTTP/2 通过发送带 upgrade 头部的请求:

    GET /page HTTP/1.1
    Host: example.com
    Connection: Upgrade, HTTP2-Settings
    Upgrade: HTTP/2.0
    HTTP2-Settings: (SETTINGS payload)
    

    如果服务器支持则接受升级,切换到新分帧;否则通过 HTTP/1.1 返回响应

    HTTP/1.1 101 Switching Protocols
    Connection: Upgrade
    Upgrade: HTTP/2.0
    (... HTTP 2.0 response ...)
    

    参考阅读:


    WebSocket

    WebSocket 是基于 TCP 连接进行双向通讯的机制,客户端/服务器可以同时发送请求并响应请求。

    WebSocket 握手利用了 HTTP 的 Upgrade,一旦握手完成、后续数据传输直接在 TCP 上完成。

    参考阅读:浏览器中常见网络协议介绍

    HTTPS

    HTTP 协议的安全问题

    • 通信使用明文,内容可能会被窃听
    • 不验证通信方的身份,可能遭遇伪装;无意义的请求也会处理,海量请求导致 DoS 攻击
    • 无法验证报文的完整性,有可能已遭篡改

    窃听:互联网上的任何角落都可能存在;普遍使用加密技术以应对,加密的对象主要有:

    • 通信加密:SSL(Secure Socket Layer,安全套接层)或 TLS(Transport Layer Security,传输层安全协议),加密 HTTP 的通信内容
    • 内容加密:对报文主体加密,这要求 C/S 两端同时具备加密和解密机制;仍存在保存篡改风险

    身份伪装:HTTP 无法确定通信方;SSL 提供证书可以确定服务器和客户端是实际存在

    篡改:请求 / 响应在传输途中,是否遭遇拦截并篡改(MITM,中间人攻击);应对手段主要有:

    • 首部字段的 Content-MD5 等验证方法,但该首部字段也可能遭篡改
    • 文件下载站点会提供以 PGP 创建的数字签名及文件 MD5,但需要用户额外下载并检查;同样该校验文件本身也可能遭篡改
    • 基于 SSL 提供认证和加密处理及摘要功能

    加密技术

    • 对称密钥加密:即加密、解密使用同一个密钥;如果密钥被窃取、则密文会被破解
    • 非对称密钥加密:通信两端均有一对公钥 / 私钥,发送方使用对方的公钥加密、用自己私钥对收到的密文解密;参考阅读 RSA 加密算法

    HTTPS 使用混合加密,即使用非对称加密交换共享密钥,后续基于该共享密钥进行对称加密通信。

    获取对方的公钥的环节,同样存在篡改风险。因此不使用通信方式获取证书,而是使用浏览器预先植入的数字证书认证机构(CA, Certificate Authority)颁发的公钥证书来解决。

    如果服务端向验证客户端的身份(比如网银交易),也会采用验证客户端证书的方式,但代价价高。

    服务端也可以使用自签发证书,但这会被浏览器告警。

    SSL / TLS

    Transport Layer Security (TLS) and its predecessor, Secure Sockets Layer (SSL), both of which are frequently referred to as ‘SSL’.

    SSL 主要解决上述三大问题:内容加密、身份认证、数据完整性。SSL 的优势在于它与应用层协议独立无关,HTTP / FTP / SMTP 等可以透明地创建于 SSL 协议之上,SSL 在应用层协议通信前即完成了加密算法、通信密钥的协商以及服务器认证工作。

    SSL Handshake:

    $ curl -v -I https://github.com
     Rebuilt URL to: https://github.com/
    *   Trying 192.30.252.122...
    * Connected to github.com (192.30.252.122) port 443 (#0)
    * ALPN, offering h2
    * ALPN, offering http/1.1
    * Cipher selection: ...
    * successfully set certificate verify locations:
    *   CAfile: /usr/local/etc/openssl/cert.pem
      CApath: none
    * TLSv1.2 (OUT), TLS header, Certificate Status (22):
    * TLSv1.2 (OUT), TLS handshake, Client hello (1):
    * TLSv1.2 (IN), TLS handshake, Server hello (2):
    * TLSv1.2 (IN), TLS handshake, Certificate (11):
    * TLSv1.2 (IN), TLS handshake, Server key exchange (12):
    * TLSv1.2 (IN), TLS handshake, Server finished (14):
    * TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
    * TLSv1.2 (OUT), TLS change cipher, Client hello (1):
    * TLSv1.2 (OUT), TLS handshake, Finished (20):
    * TLSv1.2 (IN), TLS change cipher, Client hello (1):
    * TLSv1.2 (IN), TLS handshake, Finished (20):
    * SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
    * ALPN, server accepted to use http/1.1
    * Server certificate:
    *  subject: businessCategory=Private Organization; jurisdictionC=US; jurisdictionST=Delaware; serialNumber=5157550; street=88 Colin P Kelly, Jr Street; postalCode=94107; C=US; ST=California; L=San Francisco; O=GitHub, Inc.; CN=github.com
    *  start date: Mar 10 00:00:00 2016 GMT
    *  expire date: May 17 12:00:00 2018 GMT
    *  subjectAltName: host "github.com" matched cert's "github.com"
    *  issuer: C=US; O=DigiCert Inc; OU=www.digicert.com; CN=DigiCert SHA2 Extended Validation Server CA
    *  SSL certificate verify ok.
    > HEAD / HTTP/1.1
    > Host: github.com
    ...