2016年05月24日

Http2


本文介绍http2协议

一. 码流分析

1. 场景

 client                                                 server
    |                                                      |
    |                                                      |
 |--+------------------------------------------------------+--|
 |  |                                                      |  |
 |  |<-------------------SETTINGS frame--------------------|  |
 |  |          <length=6, flags=0x00, stream_id=0>         |  |
 |  |     [SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]      |  |
 |  |                                                      |  |
 |--+------------------------------------------------------+--|
    |                                                      |
    |                                                      |
 |--+------------------------------------------------------+--|
 |  |                                                      |  |
 |  |--------------------SETTINGS frame------------------->|  |
 |  |          <length=12, flags=0x00, stream_id=0>        |  |
 |  |     [SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]      |  |
 |  |     [SETTINGS_INITIAL_WINDOW_SIZE(0x04):65535]       |  |
 |  |                                                      |  |
 |  |--------------------PRIORITY frame------------------->|  |
 |  |          <length=5, flags=0x00, stream_id=3>         |  |
 |  |      (dep_stream_id=0, weight=201, exclusive=0)      |  |
 |  |                                                      |  |
 |  |--------------------PRIORITY frame------------------->|  |
 |  |          <length=5, flags=0x00, stream_id=5>         |  |
 |  |      (dep_stream_id=0, weight=101, exclusive=0)      |  |
 |  |                                                      |  |
 |  |--------------------PRIORITY frame------------------->|  |
 |  |          <length=5, flags=0x00, stream_id=7>         |  |
 |  |        (dep_stream_id=0, weight=1, exclusive=0)      |  |
 |  |                                                      |  |
 |  |--------------------PRIORITY frame------------------->|  |
 |  |          <length=5, flags=0x00, stream_id=9>         |  |
 |  |        (dep_stream_id=7, weight=1, exclusive=0)      |  |
 |  |                                                      |  |
 |  |--------------------PRIORITY frame------------------->|  |
 |  |         <length=5, flags=0x00, stream_id=11>         |  |
 |  |       (dep_stream_id=3, weight=1, exclusive=0)       |  |
 |  |                                                      |  |
 |  |--------------------HEADERS frame-------------------->|  |
 |  |         <length=38, flags=0x25, stream_id=13>        |  |
 |  |          END_STREAM | END_HEADERS | PRIORITY         |  |
 |  | (padlen=0, dep_stream_id=11, weight=16, exclusive=0) |  |
 |  |    (stream_id=13) :method: GET                       |  |
 |  |    (stream_id=13) :path: /index.html                 |  |
 |  |    (stream_id=13) :scheme: http                      |  |
 |  |    (stream_id=13) :authority: 127.0.0.1:8443         |  |
 |  |    (stream_id=13) accept: */*                        |  |
 |  |    (stream_id=13) accept-encoding: gzip, deflate     |  |
 |  |    (stream_id=13) user-agent: nghttp2/1.7.1          |  |
 |  |                                                      |  |
 |--+------------------------------------------------------+--|
    |                                                      |
    |                                                      |
 |--+------------------------------------------------------+--|
 |  |                                                      |  |
 |  |------------------SETTINGS frame ack----------------->|  |
 |  |          <length=0, flags=0x01, stream_id=0>         |  |
 |  |                                                      |  |
 |--+------------------------------------------------------+--|
    |                                                      |
    |                                                      |
 |--+------------------------------------------------------+--|
 |  |                                                      |  |
 |  |<-----------------SETTINGS frame ack------------------|  |
 |  |          <length=0, flags=0x01, stream_id=0>         |  |
 |  |                                                      |  |
 |  |<-------------------HEADERS frame---------------------|  |
 |  |         <length=91, flags=0x04, stream_id=13>        |  |
 |  |     ; END_HEADERS                                    |  |
 |  |     (padlen=0)                                       |  |
 |  |     ; First response header                          |  |
 |  |     :status: 200                                     |  |
 |  |     server: nghttpd nghttp2/1.7.1                    |  |
 |  |     cache-control: max-age=3600                      |  | 
 |  |     date: Wed, 25 May 2016 02:08:35 GMT              |  | 
 |  |     content-length: 612                              |  |  
 |  |     last-modified: Fri, 20 May 2016 08:17:35 GMT     |  |  
 |  |     content-type: text/html                          |  | 
 |  |                                                      |  |
 |  |<---------------------DATA frame----------------------|  |
 |  |        <length=612, flags=0x01, stream_id=13>        |  |
 |  |     ; END_STREAM                                     |  |
 |  |                                                      |  |
 |--+------------------------------------------------------+--|
    |                                                      |
    |                                                      |
 |--+------------------------------------------------------+--|
 |  |                                                      |  |
 |  |---------------------GOAWAY frame-------------------->|  |
 |  |          <length=8, flags=0x00, stream_id=0>         |  |
 |  |                                                      |  |
 |  |  (last_stream_id=0, error_code=NO_ERROR(0x00),       |  |
 |  |   opaque_data(0)=[])                                 |  |
 |--+------------------------------------------------------+--|
    |                                                      |
    |                                                      |

2. client http2 req

00000000  50 52 49 20 2a 20 48 54  54 50 2f 32 2e 30 0d 0a  |PRI * HTTP/2.0..|
00000010  0d 0a 53 4d 0d 0a 0d 0a  00 00 0c 04 00 00 00 00  |..SM............|
00000020  00 00 03 00 00 00 64 00  04 00 00 ff ff 00 00 05  |......d.........|
00000030  02 00 00 00 00 03 00 00  00 00 c8 00 00 05 02 00  |................|
00000040  00 00 00 05 00 00 00 00  64 00 00 05 02 00 00 00  |........d.......|
00000050  00 07 00 00 00 00 00 00  00 05 02 00 00 00 00 09  |................|
00000060  00 00 00 07 00 00 00 05  02 00 00 00 00 0b 00 00  |................|
00000070  00 03 00 00 00 26 01 25  00 00 00 0d 00 00 00 0b  |.....&.%........|
00000080  0f 82 85 86 41 8a 08 9d  5c 0b 81 70 dc 79 a6 99  |....A...\..p.y..|
00000090  53 03 2a 2f 2a 90 7a 8a  aa 69 d2 9a c4 c0 57 75  |S.*/*.z..i....Wu|
000000a0  70 ff                                             |p.|
000000a2

2.1 client connection preface

50 52 49 20 2a 20 48 54  54 50 2f 32 2e 30 0d 0a 0d 0a 53 4d 0d 0a 0d 0a
-------------------------------
PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n

2.2 client frames

00
00 0c            length=12
04               type: SETTINGS frame
00               flags=0x00
00 00 00 00      stream_id=0
00
03 00 00 00 64   SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100
00
04 00 00 ff ff   SETTINGS_INITIAL_WINDOW_SIZE(0x04):65535
00
00 05            length=5
02               type: PRIORITY frame
00               flags=0x00
00 00 00 03      stream_id=3
00 00 00 00      dep_stream_id=0
c8               weight=201
00
00 05            length=5
02               type: PRIORITY frame
00               flags=0x00
00 00 00 05      stream_id=5
00 00 00 00      dep_stream_id=0
64               weight=101
00
00 05            length=5
02               type: PRIORITY frame
00               flags=0x00
00 00 00 07      stream_id=7
00 00 00 00      dep_stream_id=0
00               weight=1
00
00 05            length=5
02               type: PRIORITY frame
00               flags=0x00
00 00 00 09      stream_id=9
00 00 00 07      dep_stream_id=7
00               weight=1
00
00 05            length=5
02               type: PRIORITY frame
00               flags=0x00
00 00 00 0b      stream_id=11
00 00 00 03      dep_stream_id=3
00               weight=1
00
00 26            length=38
01               type: HEADERS frame
25               flags=0x25(00100101)(END_STREAM | END_HEADERS | PRIORITY)
00 00 00 0d      stream_id=13
00 00 00 0b      dep_stream_id=11
0f               weight=16
828586418a089d5c0b8170dc79a69953032a2f2a907a8aaa69d29ac4c0577570ff
                 压缩过的http headers(可以使用nghttp2中的inflatehd命令解包)

3. server http2 rsp

00000000  00 00 00 04 01 00 00 00  00 00 00 5b 01 04 00 00  |...........[....|
00000010  00 0d 88 76 8f aa 69 d2  9a e4 52 a9 a7 4a 6b 13  |...v..i...R..Jk.|
00000020  01 5d d5 c3 58 89 a4 7e  56 1c c5 81 97 00 0f 61  |.]..X..~V......a|
00000030  96 e4 59 3e 94 13 6a 68  1f a5 04 00 b8 a0 05 70  |..Y>..jh.......p|
00000040  0f 5c 65 b5 31 68 df 0f  0d 82 70 22 6c 96 c3 61  |.\e.1h....p"l..a|
00000050  be 94 10 14 d0 3f 4a 08  01 71 40 3d 70 2e dc 65  |.....?J..q@=p..e|
00000060  b5 31 68 df 5f 87 49 7c  a5 89 d3 4d 1f 00 02 64  |.1h._.I|...M...d|
00000070  00 01 00 00 00 0d 3c 21  44 4f 43 54 59 50 45 20  |......<!DOCTYPE |
00000080  68 74 6d 6c 3e 0a 3c 68  74 6d 6c 3e 0a 3c 68 65  |html>.<html>.<he|
00000090  61 64 3e 0a 3c 74 69 74  6c 65 3e 57 65 6c 63 6f  |ad>.<title>Welco|
000000a0  6d 65 20 74 6f 20 6e 67  69 6e 78 21 3c 2f 74 69  |me to nginx!</ti|
000000b0  74 6c 65 3e 0a 3c 73 74  79 6c 65 3e 0a 20 20 20  |tle>.<style>.   |
000000c0  20 62 6f 64 79 20 7b 0a  20 20 20 20 20 20 20 20  | body {.        |
000000d0  77 69 64 74 68 3a 20 33  35 65 6d 3b 0a 20 20 20  |width: 35em;.   |
000000e0  20 20 20 20 20 6d 61 72  67 69 6e 3a 20 30 20 61  |     margin: 0 a|
000000f0  75 74 6f 3b 0a 20 20 20  20 20 20 20 20 66 6f 6e  |uto;.        fon|
00000100  74 2d 66 61 6d 69 6c 79  3a 20 54 61 68 6f 6d 61  |t-family: Tahoma|
00000110  2c 20 56 65 72 64 61 6e  61 2c 20 41 72 69 61 6c  |, Verdana, Arial|
00000120  2c 20 73 61 6e 73 2d 73  65 72 69 66 3b 0a 20 20  |, sans-serif;.  |
00000130  20 20 7d 0a 3c 2f 73 74  79 6c 65 3e 0a 3c 2f 68  |  }.</style>.</h|
00000140  65 61 64 3e 0a 3c 62 6f  64 79 3e 0a 3c 68 31 3e  |ead>.<body>.<h1>|
00000150  57 65 6c 63 6f 6d 65 20  74 6f 20 6e 67 69 6e 78  |Welcome to nginx|
00000160  21 3c 2f 68 31 3e 0a 3c  70 3e 49 66 20 79 6f 75  |!</h1>.<p>If you|
00000170  20 73 65 65 20 74 68 69  73 20 70 61 67 65 2c 20  | see this page, |
00000180  74 68 65 20 6e 67 69 6e  78 20 77 65 62 20 73 65  |the nginx web se|
00000190  72 76 65 72 20 69 73 20  73 75 63 63 65 73 73 66  |rver is successf|
000001a0  75 6c 6c 79 20 69 6e 73  74 61 6c 6c 65 64 20 61  |ully installed a|
000001b0  6e 64 0a 77 6f 72 6b 69  6e 67 2e 20 46 75 72 74  |nd.working. Furt|
000001c0  68 65 72 20 63 6f 6e 66  69 67 75 72 61 74 69 6f  |her configuratio|
000001d0  6e 20 69 73 20 72 65 71  75 69 72 65 64 2e 3c 2f  |n is required.</|
000001e0  70 3e 0a 0a 3c 70 3e 46  6f 72 20 6f 6e 6c 69 6e  |p>..<p>For onlin|
000001f0  65 20 64 6f 63 75 6d 65  6e 74 61 74 69 6f 6e 20  |e documentation |
00000200  61 6e 64 20 73 75 70 70  6f 72 74 20 70 6c 65 61  |and support plea|
00000210  73 65 20 72 65 66 65 72  20 74 6f 0a 3c 61 20 68  |se refer to.<a h|
00000220  72 65 66 3d 22 68 74 74  70 3a 2f 2f 6e 67 69 6e  |ref="http://ngin|
00000230  78 2e 6f 72 67 2f 22 3e  6e 67 69 6e 78 2e 6f 72  |x.org/">nginx.or|
00000240  67 3c 2f 61 3e 2e 3c 62  72 2f 3e 0a 43 6f 6d 6d  |g</a>.<br/>.Comm|
00000250  65 72 63 69 61 6c 20 73  75 70 70 6f 72 74 20 69  |ercial support i|
00000260  73 20 61 76 61 69 6c 61  62 6c 65 20 61 74 0a 3c  |s available at.<|
00000270  61 20 68 72 65 66 3d 22  68 74 74 70 3a 2f 2f 6e  |a href="http://n|
00000280  67 69 6e 78 2e 63 6f 6d  2f 22 3e 6e 67 69 6e 78  |ginx.com/">nginx|
00000290  2e 63 6f 6d 3c 2f 61 3e  2e 3c 2f 70 3e 0a 0a 3c  |.com</a>.</p>..<|
000002a0  70 3e 3c 65 6d 3e 54 68  61 6e 6b 20 79 6f 75 20  |p><em>Thank you |
000002b0  66 6f 72 20 75 73 69 6e  67 20 6e 67 69 6e 78 2e  |for using nginx.|
000002c0  3c 2f 65 6d 3e 3c 2f 70  3e 0a 3c 2f 62 6f 64 79  |</em></p>.</body|
000002d0  3e 0a 3c 2f 68 74 6d 6c  3e 0a                    |>.</html>.|
000002da

3.1 server frames

00 00 00 04 01 00 00 00 00
00 
00 5b            length=91
01               type: HEADERS frame
04               flags=0x04(00000100)(END_HEADERS)
00 00 00 0d      stream_id=13
88768faa69d29ae452a9a74a6b13015dd5c35889a47e561cc58197000f6196e4593e94136a681fa50400b8a005700f5c65b53168df0f0d8270226c96c361be941014d03f4a080171403d702edc65b53168df5f87497ca589d34d1f
                 压缩过的http headers(可以使用nghttp2中的inflatehd命令解包)
00 
02 64            length=612
00               type: DATA frame 
01               flags=0x01
00 00 00 0d      stream_id=13
3c 21 ...        response body

4. client http2 goaway

00000000  00 00 08 07 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000010  00                                                |.|
00000011

00
00 08            length=8
07               type: GOAWAY frame
00               flags=0x00
00 00 00 00      stream_id=00
00 00 00 00      last_stream_id=0
00 00 00 00      error_code=NO_ERROR(0x00)

二. stream

1. 状态跃迁图

                       +--------+
                 PP    |        |    PP
              ,--------|  idle  |--------.
             /         |        |         \
            v          +--------+          v
     +----------+          |           +----------+
     |          |          | H         |          |
 ,---| reserved |          |           | reserved |---.
 |   | (local)  |          v           | (remote) |   |
 |   +----------+      +--------+      +----------+   |
 |      |          ES  |        |  ES          |      |
 |      | H    ,-------|  open  |-------.      | H    |
 |      |     /        |        |        \     |      |
 |      v    v         +--------+         v    v      |
 |   +----------+          |           +----------+   |
 |   |   half   |          |           |   half   |   |
 |   |  closed  |          | R         |  closed  |   |
 |   | (remote) |          |           | (local)  |   |
 |   +----------+          |           +----------+   |
 |        |                v                 |        |
 |        |  ES / R    +--------+  ES / R    |        |
 |        `----------->|        |<-----------'        |
 |  R                  | closed |                  R  |
 `-------------------->|        |<--------------------'
                       +--------+

   H:  HEADERS frame (with implied CONTINUATIONs)
   PP: PUSH_PROMISE frame (with implied CONTINUATIONs)
   ES: END_STREAM flag
   R:  RST_STREAM frame

1.1. idle

所有流以“空闲”状态开始。在这种状态下,没有任何帧的交换。

1.2. reserved(local)

端点已经发送PUSH_PROMISE帧的流,进入保留(本地)状态。

1.3. reserved(remote)

端点已经发送PUSH_PROMISE帧的流,进入保留(远端)状态。

1.4. open

处于“打开”状态的流可以被两个对等端来发送任何类型的帧。在这种状态下,发送数据的对等端检查被广播端FlowControl流量控制限制。

在这种状态下每个终端可以发送一个带有END_STREAM结束流标记的帧来使流转换到其中一种“半关闭”状态:一个终端发送一个结束流END_STREAM标记使流变成“半封闭(本地)”状态;一个终端接收一个结束流END_STREAM标记使流变成“半封闭(远端)”状态。带有结束流END_STREAM标记的报头HEADERS帧后面可以跟着延续CONTINUATION帧。

1.5. half closed(local)

“半封闭(本地)”状态下的流只能发送窗口更新(WINDOW_UPDATE)、优先级(PRIORITY)和终止流(RST_STREAM)帧。

这种状态下,当流接收到包含END_STREAM标记的帧或者某个终端发送了RST_STREAM帧,流转换到“关闭”状态。带有结束流END_STREAM标记的报头HEADERS帧后面可以跟着延续CONTINUATION帧。

这种状态下接收端可以忽略窗口更新WINDOW_UPDATE帧。这种类型的帧有可能在结束流END_STREAM标记到达一小段时间后才收到。

优先级(PRIORITY)帧可以在这种状态下接收并用来对依赖当前流的流进行优先级重排序。

1.6. half closed(remote)

"半封闭(远程)"状态下的流不再被对等端用来发送帧。这种状态下,执行流量控制的终端不再承担接收留空控制窗口的工作。

如果终端接收到处于这种状态下的流发送的额外的帧,除非是延续CONTINUATION帧,否则必须返回类型为流关闭STREAM_CLOSED的流错误。

这种状态下,当流发送一个带有终止流END_STREAM标记的帧或者某个终端发送了一个RST_STREAM帧,流将转换到“关闭”状态。

1.7. closed

“关闭”状态是终止状态。

终端绝对不能通过关闭的流发送帧。终端在收到RST_STREAM后接收的任何帧必须作为类型为流关闭STREAM_CLOSED的StreamErrorHandler流错误stream error处理。相似的,终端接收到带有END_STREAM标记设置的数据DATA帧之后的任何帧,或在带有END_STREAM终止流标记且后面没有延续CONTINUATION帧的报头HEADERS帧之后收到任何帧都必须作为类型为流关闭STREAM_CLOSED的连接错误处理。

在这种情况下,在带有END_STREAM标记的DATA或HEADERS帧发送之后一小段时间内可以接收WINDOW_UPDATE或者RST_STREAM帧。在远端对等端接收并处理带有END_STREAM标记的帧之前,可以发送任意这几种帧。在这种状态下终端必须忽略接收到的WINDOW_UPDATE,PRIORITY, 或 RST_STREAM帧,但终端也可以当作类型为PROTOCOL_ERROR的连接错误处理。

关闭的流上可以发送优先级帧用来对依赖当前关闭流的流进行优先级重排序。终端应该处理优先级帧,但当该流已经从依赖树中移除时可以忽略。

如果流在发送RST_STREAM帧后转换到这种状态,接收到RST_STREAM的对等端可能已经发送或者队列中准备发送无法取消的帧。终端必须忽略从已经发送RST_STREAM帧的流接收到的帧。终端可以选择设置忽略帧的超时时间并在超过限制后作为错误处理。

在发送RST_STREAM之后收到的流量受限帧(如数据DATA帧)转向流量控制窗口连接处理。尽管这些帧可以被忽略,因为他们是在发送端接收到RST_STREAM之前发送的,但发送端会认为这些帧与流量控制窗口不符。

终端可能在发送RST_STREAM之后接收PUSH_PROMISE帧。即便相关的流已经被重置,推送承诺帧也能使流变成“保留”状态。因此,需要RST_STREAM来关闭一个不想要的被承诺流。

三. nghttp2

1. nghttpd

2. nghttp

3. nghttpx

4. deflatehd

5. inflatehd

inflatehd是nghttp2中提供的对http头进行解压的工具。

用法如下:


inflatehd
{
"context": "request",
"cases":
[{ "wire" : "88768faa69d29ae452a9a74a6b13015dd5c35889a47e561cc58197000f6196e4593e94136a681fa50400b8a005700f5c65b53168df0f0d8270226c96c361be941014d03f4a080171403d702edc65b53168df5f87497ca589d34d1f" }
]
}
^D(此次输入ctrl-d结束输入)

以下为输出结果:
{
  "cases":
  [
{
  "seq": 0,
  "wire": "88768faa69d29ae452a9a74a6b13015dd5c35889a47e561cc58197000f6196e4593e94136a681fa50400b8a005700f5c65b53168df0f0d8270226c96c361be941014d03f4a080171403d702edc65b53168df5f87497ca589d34d1f",
  "headers": [
    {
      ":status": "200"
    },
    {
      "server": "nghttpd nghttp2/1.7.1"
    },
    {
      "cache-control": "max-age=3600"
    },
    {
      "date": "Wed, 25 May 2016 02:08:35 GMT"
    },
    {
      "content-length": "612"
    },
    {
      "last-modified": "Fri, 20 May 2016 08:17:35 GMT"
    },
    {
      "content-type": "text/html"
    }
  ]
}
  ]
}