http2 最速実装 〜入門編〜

42
HTTP2 最最最最 最最最最 ~~ 前前 前 (@mad_p) http2 前前前前前 #1 2014/02/23 前前前前 12 前前前前前前 2014/05/12 1

Upload: kaoru-maeda

Post on 28-Nov-2014

18.054 views

Category:

Technology


1 download

DESCRIPTION

HTTP 2 最速実装(最小限の機能で素早く実装)するために必要最小限の知識を伝えます。 HTTP 2 最速実装法: https://github.com/http2jp/http2jp.github.io/wiki/HTTP2.0-%E6%9C%80%E9%80%9F%E5%AE%9F%E8%A3%85%E6%B3%95 h2-12 (draft-ietf-httpbis-http2-12) 対応の修正をしました。 http://tools.ietf.org/html/draft-ietf-httpbis-http2-12

TRANSCRIPT

Page 1: HTTP2 最速実装 〜入門編〜

HTTP2最速実装~入門編~

前田 薫 (@mad_p)

http2 ハッカソン #1 2014/02/23

ドラフト 12 に合わせ修正 2014/05/12

1

Page 2: HTTP2 最速実装 〜入門編〜

はじめに

• 今日の目標• HTTP2 の処理系を最小限の労力で作れるようになる ( 性能は求めない )

• HTTP2.0 最速実装法が実装できるようになる• https://github.com/http2jp/http2jp.github.io/wiki/HTTP2.0-%

E6%9C%80%E9%80%9F%E5%AE%9F%E8%A3%85%E6%B3%95

• HTTP2, HPACK の概要を理解する• http://tools.ietf.org/html/draft-ietf-httpbis-http2-12 ( このスライドはドラフト 12

ベースです )

• http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-07

2

Page 3: HTTP2 最速実装 〜入門編〜

目次

• HTTP2 Overview

• HTTP2 の開始• Frame 定義• HTTP メッセージの交換• Stream 管理• HPACK( ヘッダ圧縮 )

• まとめ3

Page 4: HTTP2 最速実装 〜入門編〜

おさらい : HTTP 1.1

client server

①Request

②Response

4

connection

Page 5: HTTP2 最速実装 〜入門編〜

HTTP 1.1 REQUEST/RESPONSE

• テキスト形式、行指行

5

GET / HTTP/1.1User-Agent: curl/7.30.0Host: localhostAccept: */*

HTTP/1.1 200 OKContent-Length: 44Content-Type: text/html

<html><body><h1>It works!</h1></body></html>

CR+LF

Header StatusRequestHeader

Body

CR+LF

Page 6: HTTP2 最速実装 〜入門編〜

HTTP2 OVERVIEW

6

Page 7: HTTP2 最速実装 〜入門編〜

HTTP2 OVERVIEW

7

client server

connection

①Request

②Response

stream

③Server-Push

Page 8: HTTP2 最速実装 〜入門編〜

CONNECTIONと STREAM

• Connection の中に stream がある• Stream は双方向• Stream は複数同時に存在してもよい• Stream は interleave して送信される• Stream には番号がついている

• Client からスタートしたら奇数、• Server からだと偶数• Stream 0 番を全体の制御に使う

• Request, Response は stream の中を通る 8

Stream 1

Stream 2

Stream 3

Page 9: HTTP2 最速実装 〜入門編〜

STREAMと FRAME

• Stream は Frame という単位で送信される

9

client server

Page 10: HTTP2 最速実装 〜入門編〜

FRAME

• バイナリ形式

• 1 オクテット = 8 ビット• 左から右、上から下の順で送出 10

0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| R | Length (14) | Type (8) | Flags (8) |+-+-+-----------+---------------+-------------------------------+|R| Stream Identifier (31) |+-+-------------------------------------------------------------+| Frame Payload (0...) ...+---------------------------------------------------------------+

Page 11: HTTP2 最速実装 〜入門編〜

HTTPメッセージの FRAME表現

• HTTP 1.1 Request• Request 行• Header 部• Body 部 (POST, PUT など )

• HTTP 2• HEADERS frame(s)

• Request 行、 Status 行とヘッダ部を含む• DATA frames

11

HTTP/1.1 200 OKContent-Length: 44Content-Type: text/html

<html><body><h1>It works!</h1></body></html>

:status: 200content-length: 44content-type: text/html

<html><body><h1>It works!</h1></body></html>

HEADERS

DATA

Page 12: HTTP2 最速実装 〜入門編〜

HTTP2の開始

12

Page 13: HTTP2 最速実装 〜入門編〜

HTTP2の開始

• HTTP2 でフレームを送りあって通信するまでに、接続を確立する手順• HTTP 1.1

• 1. TCP 接続を確立• 2. (https スキームの場合 ) TLS の確立• 3. リスエスト送信• 4. レスポンス受信

• HTTP 2• 1. Connection の確立 ( 最初のフレームの送出 ) → 詳細は次ページ• 2. その後のフレーム送受信 13

Page 14: HTTP2 最速実装 〜入門編〜

CONNECTION確立の方法

• TLS ALPN (Application Layer Protocol Negotiation extension)

• TLS の拡張 • http://d.hatena.ne.jp/ASnoKaze/20130207/1360249692

• http://tools.ietf.org/html/draft-ietf-tls-applayerprotoneg-05

• クライアントが ClientHello で使いたいプロトコルのリストを送る• サーバーがその中から使うものを決めて ServerHello で知らせる

• TLS NPN (Next Protocol Negotiation extention) ALPN までのつなぎ• https://technotes.googlecode.com/git/nextprotoneg.html

• HTTP 1.1 からの Upgrade

• HTTP 1.1 形式のリクエスト内に「 Upgrade ヘッダ」を書く、 SETTINGS をヘッダとして送る

• 事前知識によって TCP 接続後にいきなり HTTP2 ← 最速実装ではこれを使います 14

Page 15: HTTP2 最速実装 〜入門編〜

HTTP2 CONNECTION PREFACE

• クライアント → サーバー• 24 オクテットのナゾの文字列を送る (HTTP 1.1 からの Upgrade 時も )

• 505249202a20485454502f322e300d0a0d0a534d0d0a0d0a

• アスキーの内容は「 PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n 」 (PRISM が入ってるのは洒落 )

• その後ろに SETTINGS フレーム ( 後述 ) を送る

• サーバー → クライアント• SETTINGS フレームを送る

• SETTINGS フレーム : フロー制御、ヘッダ圧縮、同時接続ストリーム数などパラメータを通知

15

Page 16: HTTP2 最速実装 〜入門編〜

FRAME定義

16

Page 17: HTTP2 最速実装 〜入門編〜

フレームについて

• HTTP ストリームの内容をフレームに分解して送る• ひとつのフレームで送れるペイロードは 16383 オクテットまで• バイナリ形式

17

00 40 01 05 00 00 00 0100 07 3a 6d 65 74 68 6f64 03 47 45 54 00 07 3a73 63 68 65 6d 65 04 6874 74 70 00 0a 3a 61 7574 68 6f 72 69 74 79 0f31 30 36 2e 31 38 36 2e31 31 32 2e 31 31 36 0005 3a 70 61 74 68 01 2f

Page 18: HTTP2 最速実装 〜入門編〜

FRAME FORMAT

• フレームヘッダ 8 オクテット• Length: ペイロードのオクテット数• Type HEADERS, DATA などフレームの種類を表わす整数• Flags: タイプごとに定められた付加情報を持つ。特に END_STREAM,END_HEADERS フラグが重要• Stream Identifier: 31bit のストリーム ID

• フレームペイロード : タイプごとに定められたデータ内容18

0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| R | Length (14) | Type (8) | Flags (8) |+-+-+-----------+---------------+-------------------------------+|R| Stream Identifier (31) |+-+-------------------------------------------------------------+| Frame Payload (0...) ...+---------------------------------------------------------------+

Page 19: HTTP2 最速実装 〜入門編〜

FRAME TYPESType 意味 Type番号 (draft

12)

DATA データ 0x0

HEADERS ヘッダ 0x1

PRIORITY ストリームの優先度 0x2

RST_STREAM ストリームの異常終了 0x3

SETTINGS コネクションのパラメータ 0x4

PUSH_PROMISE サーバープッシュ 0x5

PING 死活監視 + 遅延測定 0x6

GOAWAY コネクション終了 0x7

WINDOW_UPDATE フロー制御パラメータ 0x8

CONTINUATION HEADERS, PUSH_PROMISE の続き 0x9

ALTSVC プロトコル切り換えの可能性を示す 0xa

BLOCKED フロー制御デバッグ情報 (draft-12 のみ ) 0xb

19

Page 20: HTTP2 最速実装 〜入門編〜

DATA FRAME(TYPE 0X0)

• Data:

• データ自体を運ぶ。 HTTP Body に相当• 長さはペイロードの残り全部

• Pad High, Pad Low: パディングの長さ

• Padding: パディング

• DATA フレームのフラグ : フレームヘッダの中の Flags フィールドに置く• END_STREAM(0x1): ストリームの終了を示す• END_SEGMENT(0x2): 中継時に合体させてはいけない範囲を示す• PAD_LOW(0x8), PAD_HIGH(0x10): パディング長フィールドを使うかどうか示す• COMPRESSED(0x20): Data がフレーム単位で gzip 圧縮されているかを示す

20

0 1 2 30 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| Pad High? (8) | Pad Low? (8) |+---------------+---------------+-------------------------------+| Data (*) ...+---------------------------------------------------------------+| Padding (*) ...+---------------------------------------------------------------+

Page 21: HTTP2 最速実装 〜入門編〜

HEADERS FRAME(TYPE 0X1)• Header Block Segment

• Key-value ペアの列を運ぶ• HTTP Header に相当• HPACK 形式で圧縮したもの

• E, Stream Dependency, Weight:

• ストリームの優先度情報

• Pad High, Pad Low, Padding: DATA フレームと同様

• HEADER フレームのフラグ• END_STREAM(0x1),END_SEGMENT(0x2), PAD_LOW(0x8), PAD_HIGH(0x10): DATA と

同じ• END_HEADERS(0x4): ヘッダブロックがこのフレームで完結することを示す• PRIORITY(0x20): 優先度情報フィールド 3 つを使うかどうかを示す

21

0 1 2 30 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| Pad High? (8) | Pad Low? (8) |+-+-------------+---------------+-------------------------------+|E| Stream Dependency? (31) |+-+-------------+-----------------------------------------------+| Weight? (8) |+-+-------------+-----------------------------------------------+| Header Block Fragment (*) ...+---------------------------------------------------------------+| Padding (*) ...+---------------------------------------------------------------+

Page 22: HTTP2 最速実装 〜入門編〜

SETTINGS FRAME(TYPE 0X4)

• 5 オクテットを 1 組として、ペイロード長ぶんの設定が入っている• 接続確立時におたがいに送り合う• 接続中に送ってもよい

• SETTINGS フレームのストリーム ID は必ず 0

• SETTINGS フレームのフラグ• ACK(0x1): 相手から送信された SETTING に対する ACK を示す。このときペイロードは空

• SETTINGS を受け取ったら必す ACK を返す ( 接続時の最初も )

• Identifier: 設定の種類を表わす識別子 Value: 設定値

22

0 1 2 30 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| Identifier (8)|+---------------+-----------------------------------------------+| Value (32) |+---------------------------------------------------------------+

Page 23: HTTP2 最速実装 〜入門編〜

SETTINGで定義されている設定

• 以下の設定のすべてを実装しないといけない ( 最速実装では無視します )

• SETTINGS_HEADER_TABLE_SIZE (1): ヘッダ圧縮に使うテーブルサイズ ( 初期値 :4096)

• SETTINGS_ENABLE_PUSH (2):

• サーバーからの push を許すかどうか ( 初期値 1: 許可 ) 。クライアント側からの指定のみ意味がある

• SETTINGS_MAX_CONCURRENT_STREAMS (3):

• 同時に active 状態になってよいストリーム数。 100 以上を推奨 ( 初期値 : 制限なし )

• SETTINGS_INITIAL_WINDOW_SIZE (4):

• 受信バッファサイズの初期値。フロー制御で使う。 2^31 – 1 まで ( 初期値 :65535)

• SETTINGS_COMPRESS_DATA (5):

• DATA フレームの gzip 圧縮を使ってよいかどうか ( 初期値 0: 禁止 ) 23

Page 24: HTTP2 最速実装 〜入門編〜

GOAWAY FRAME(0X7)

• これ以上ストリームを作るの禁止

• コネクションの終了を意図している( でも送出側は作ってもいいことになっている )

• GOAWAY フレームのストリーム ID は必ず 0

• Last-Stream-ID: 処理中の最終ストリーム ID

• 相手が直前に送ったものがアプリ層に届いたかわかる

• Error Code: エラー情報24

0 1 2 30 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|R| Last-Stream-ID (31) |+-+-------------------------------------------------------------+| Error Code (32) |+---------------------------------------------------------------+| Additional Debug Data (*) |+---------------------------------------------------------------+

Page 25: HTTP2 最速実装 〜入門編〜

これ以外の FRAME TYPES

• 以下のフレームタイプは最速実装では使いません• PRIORITY

• RST_STREAM

• PUSH_PROMISE

• PING

• WINDOW_UPDATE

• CONTINUATION

• ALTSVC

• BLOCKED25

Page 26: HTTP2 最速実装 〜入門編〜

HTTPメッセージの交換

26

Page 27: HTTP2 最速実装 〜入門編〜

HTTPリクエスト /レスポンスの表現

• リクエスト行、レスポンス行、ヘッダ部の情報を HEADERS フレームで表現• フレーム長制限を超える場合は CONTINUATION を使う ( 最速実装では使いませ

ん )

• おさまり切る場合は END_HEADERS フラグをつける

• ボディ部を DATA フレームで表現• ボディ部が存在しない場合は DATA フレームを生成せず、 HEADERS に

END_STREAM フラグをつける• DATA フレームは複数になってもよい。最後のものには END_STREAM フラグをつ

ける

• HEADERS, DATA フレームを順に送出

27

Page 28: HTTP2 最速実装 〜入門編〜

HEADERSの作り方

• リクエストには以下のヘッダ名を使う。リクエスト行の要素はコロンつきのヘッダ名を使う• :method HTTP メソッド。 GET, POST など• :scheme http または https のどちらか• :authority リクエスト URI の authority 部分 www.example.com:8080など

• :path パス

• レスポンスではステータスを :status に入れる• この後 HPACK で圧縮し、 Frame header と連結する

28

Page 29: HTTP2 最速実装 〜入門編〜

STREAM管理

29

Page 30: HTTP2 最速実装 〜入門編〜

STREAM IDの割当

• いままでに使った番号より大きな番号を使わないといけない• クライアント発の場合には奇数を使う• サーバー発の場合には偶数を使う ( 最速実装では使いません )

• ストリーム ID 0( ゼロ ) はコネクション全体の制御を使うために予約• SETTINGS の MAX_CONCURRENT_STREAMS より多くのストリーム

を同時に作ってはいけない• Open, half-close のものを数える

• 番号を使いつくしたら ? → 新しいコネクションを作る 30

Page 31: HTTP2 最速実装 〜入門編〜

STREAM STATE DIAGRAM

• ストリームのライフタイム定義• Idle: 未作成• Open: 使用中• Half closed:

• 片側だけ使用中の状態• 片方から END_STREAM を送った場合

• Closed: 終了• Reserved は最速実装では使いませ

ん31

+--------+ 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 |`-------------------->| |<--------------------' +--------+

Page 32: HTTP2 最速実装 〜入門編〜

HPACK(ヘッダ圧縮 )

32

Page 33: HTTP2 最速実装 〜入門編〜

HPACKの必要性

• なにしろでかいんですよ、 HTTP ヘッダーって。同じ情報を何度も送るし• SPDY では zlib で圧縮していましたが、 CRIME/BREACH アタックが出現• 圧縮率観測攻撃 :

• データをつっこんでやって、圧縮されるかどうか見ると、同じペイロード内の情報 ( セッションクッキーなど ) を調べることができてしまう

• 今日この後で勉強しましょう

• HPACK: 圧縮率観測攻撃に耐える圧縮形式として設計

33

Page 34: HTTP2 最速実装 〜入門編〜

HPACKの圧縮手段

• Huffman Encoding• よく使う文字を少ないビット数で表現する

• Static Table Indexing• よく使うヘッダをあらかじめ定義しておき、番号で指定する

• Header Table Indexing• 最近送信したヘッダと同一だったら番号で指定する

• Reference Set Difference• 最後に送出したヘッダとの差分だけを送る

34

Page 35: HTTP2 最速実装 〜入門編〜

HPACK最速実装

• 必ずリテラルで、 Huffman なしで、 Without Index モードで送る• 各ヘッダを以下の形式でエンコード

• H: 0 にする• Length は

• 126 (2^7 – 2) 以下はそのまま入れる• 127 以上は最初に 127

• 127 を引いた残りを 128 進数で、最後のもの以外は MSB を立てる

35

0 1 2 3 4 5 6 7+---+---+---+---+---+---+---+---+| 0 | 0 | 0 | 0 | 0 |+---+---+-----------------------+| H | Name Length (7+) |+---+---------------------------+| Name String (Length octets) |+---+---------------------------+| H | Value Length (7+) |+---+---------------------------+| Value String (Length octets) |+-------------------------------+

Page 36: HTTP2 最速実装 〜入門編〜

ヘッダの最速実装の例

36

:method: GET:scheme: http:path: /:authority: www.example.com

00 07 3a 6d 65 74 68 6f 4403 47 45 5400 07 3a 73 63 68 65 6d 6504 68 74 74 70 :

00 に続いて長さ 7そしてヘッダ名 :method

長さ 3そしてヘッダ値 GET

00 :scheme

httpこれをくり返し、全体の長さを数えて、

先頭にフレームヘッダをつける長さ 64 オクテット

(0x40) 、 stream_id = 1, 、 END_STREAM 、 END_HEADER

S の場合

00 40 01 05 00 00 00 01

Page 37: HTTP2 最速実装 〜入門編〜

最速実装のリクエスト・レスポンス

37

Page 38: HTTP2 最速実装 〜入門編〜

38

client server

CONNECTION PREFACE

SETTINGS

SETTINGS

HEADERS

HEADERS

DATA

GOAWAY

:method GET:

Stream ID = 1END_HEADERS, END_STREAM

Stream ID = 1END_HEADERS,

Stream ID = 1END_STREAM

SETTINGS ACKSETTINGS ACK

server から END_STREAMが来たら GOAWAY を送り、

TCP 接続を切断

Page 39: HTTP2 最速実装 〜入門編〜

39

client server

50 52 49 20 2a 20 48 5454 50 2f 32 2e 30 0d 0a0d 0a 53 4d 0d 0a 0d 0a

00 40 01 05 00 00 00 0100 07 3a 6d 65 74 68 6f64 03 47 45 54 00 07 3a73 63 68 65 6d 65 04 6874 74 70 00 0a 3a 61 7574 68 6f 72 69 74 79 0f31 30 36 2e 31 38 36 2e31 31 32 2e 31 31 36 0005 3a 70 61 74 68 01 2f

CONNECTION PREFACE

00 00 04 00 00 00 00 00SETTINGS

HEADERS

00 0f 04 00 00 00 00 0003 00 00 00 6404 00 00 ff ff02 00 00 00 00

SETTINGS

以下略

00 00 04 01 00 00 00 00SETTINGS ACK

00 00 04 01 00 00 00 00SETTINGS ACK

Page 40: HTTP2 最速実装 〜入門編〜

まとめ

40

Page 41: HTTP2 最速実装 〜入門編〜

HTTP2最速実装に向けて

• HTTP2 の概要• コネクション、ストリーム、フレーム

• HTTP Request / Response の表現形式• HEADERS フレーム、 DATA フレーム

• HTTP2 の開始シーケンス• HPACK で楽をする実装方法

41

Page 42: HTTP2 最速実装 〜入門編〜

今日やらなかったこと

• その他の開始ハンドシェイク• TLS からの ALPN, HTTP からの Upgrade

• フロー制御、優先度制御• エラー処理

42