第 2 回の目次
前回
: TCP/IP
,ソケット 今回: HTTP
,HTTP/2
本日のソースコード
httpget.txt:
パケットダンプhttp.rb: ruby
でhttp get
するJava
でhttp (
ソース無し)
まずはパケットを見てみる
wireshark
でパケットをキャプチャしたもの →httpget.txt
→httpget cookie.txt (
クッキー付き)
telnet
コマンドで直接入力するという手もあるtelnet localhost 80
GET /index.html HTTP/1.1
Host: 172.28.
∼RFC2616
の用語
RFC2616: HTTP/1.1 (http://www.ietf.org/rfc/rfc2616.txt)
(RFC7230-7235によって上書きされているが,ここでは RFC2616)Resource: URI
で識別されるネットワーク上のオブジェクトClient
User Agent:
リクエストを発行するプログラム(
ブラウザ等)
Server
Origin Server:
指定したリソースが存在するサーバProxy (
半分はクライアントで半分はサーバ):
透過型プロキシ(
データ変換なし)
非透過型プロキシ(
データ変換あり)
Gateway:
サーバを中継するサーバ(
クライアントから見るとオリジン サーバ)
Tunnel:
見えないFirst hand:
オリジンサーバから直接返ってくるレスポンスのこと.通信モデル
クライアントとサーバが基本inbound
とoutbound (
下りと上り)
proxy
やgateway
が挟まる クライアントからリクエスト サーバからレスポンス 途中でキャッシュしてもよい 接続とのマッピングはしない(
メッセージより上だけを考え ていく)
ただし接続張りっぱなしが1.1
で既定された(Keep-Alive)
HTTP Message
Header + CRLF + Body
ヘッダフィールドで空白で始まる行は前の行の続き
メッセージの中身を
Entity
と言う上の
Body
は正確にはEntity body
と呼ぶEntity
に対するHeader
はMessage Header
に含まれるMIME
によるマルチパート記述(Content-Type
にmultipart
を指定
)
を使えば,複数のエンティティを格納することもでRequest
Request = Request-Line *(( general-header | request-header | entity-header ) CRLF) CRLF [ message-body ]Request-Line = Method SP Request-URI SP HTTP-Version CRLF Method = OPTIONS|GET|HEAD|POST|PUT|DELETE|TRACE|CONNECT request-header = Accept ; 可能なメディアタイプ等 | Authorization | Expect | From | Host ; 要求先のホスト名 | If-Match | If-Modified-Since | Range | Referer | User-Agent
Response
Response = Status-Line *(( general-header | response-header | entity-header ) CRLF) CRLF [ message-body ]Status-Line = HTTP-Version SP Status-Code SP Reason CRLF response-header = Accept-Ranges | Age | ETag | Location | Proxy-Authenticate | Retry-After | Server | Vary | WWW-Authenticate
共通ヘッダ
general-header = Cache-Control | Connection | Date | Pragma | Trailer | Transfer-Encoding | Upgrade | Via | Warning entity-header = Allow | Content-Encoding | Content-Language | Content-Length | Content-Location | Content-MD5 | Content-Range | Content-Type | Expires | Last-Modified接続
目的: TCP-open
の削減とメッセージのパイプライン化Connection:
ヘッダで制御する 閉じたい側が,Connection: close
とする 続けたいときは,Connection: Keep-Alive
とする 接続はいつ切ってもよい(
そのように作る)
同時接続数は2 (RFC7230
では規定せず,ブラウザ依存で6
とか)
パイプラインはインオーダ発行/
インオーダ完了しかでき ない各メソッド
GET:
リソースの取得(
キャッシュ可)
If-Modified-Since, If-Unmodified-Since, If-Match,
If-None-Match, If-Range
(
If-Rangeは Range と組み合わせてリソースの部分取得)
HEAD:
レスポンスにメッセージボディがないGET
.リソー スの存在確認などPOST: (
既存)
リソースへのエンティティの追加(
基本は キャッシュ不可)
PUT:
新しいリソースの保存(
キャッシュ不可)
既存リソースへのPUT
はリソースの置き換えをするべき. 新規保存したら201 Created,
既存リソース置換なら200 OK
.DELETE:
リソースの削除(
キャッシュ不可)
TRACE:
サーバが受け取ったエンティティボディをそのまま 返して貰う.デバッグ用.CONNECT: proxy
にトンネルさせるためのメソッド(SSL
用)
ステータスコード (のうち代表的なもの)
1xx: Informational -
リクエストは受け入れられ処理は継続中100 continue: Expect
と供に使う2xx: Success -
正常に受信され、受け入れられた200 OK:
基本3xx: Redirection -
リクエスト完了にはさらなる動作が必要301 moved permanently:
普通はこれ?
全部で7
種類もあるLocation
ヘッダの中にredirect
先が書いてある4xx: Client Error -
リクエストは間違った構文か実行不可能400 bad request:
基本404 not found:
基本5xx: Server Error -
リクエストの実行に失敗ネゴシエーション
charset
やencoding
user-agent
Referer
英語としてはReferrer
(元はミススペル) どこのページから飛んで来たかをブラウザが付けるUser-Agent: Mozilla/5.0 (X11; U; Linux x86_64; ja; rv:1.9.1.16) Gecko/20121207 Iceweasel/3.5.16 (like Firefox/3.5.16) Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: ja,en-us;q=0.7,en;q=0.3 Accept-Encoding: gzip,deflate Accept-Charset: Shift_JIS,utf-8;q=0.7,*;q=0.7 Keep-Alive: 300 Connection: keep-alive Referer: http://www.google.co.jp/search?hl=ja&source=hp&q=%E8%8A%9D%E6% B5%A6%E5%B7%A5%E6%A5%AD%E5%A4%A7%E5%AD%A6&gbv=2&oq=sibaurakougyou&gs_l= heirloom-hp.3.0.0i4l10.3235.28635.0.29690.46.19.26.0.0.0.120.1535.15j4. 19.0....0...1ac.1.24.heirloom-hp..2.44.1585.XrWLkbqJAWI Cookie: NavicastApi=20130928.150526.35224600.14370; ∼ フラグメント
(#
から後ろ)
は送ってはならないクッキー
RFC2109/2965 (実際は NetScape 仕様らしい)
クッキーの設定 [サーバ→ UA]
Set-Cookie: NAME=VALUE; expires=DATE; path=PATH;
domain=DOMAIN NAME; secure
NAME=VALUE:クッキーの名前と値 expires: 有効期限 (これを過ぎると UA が捨てる) domain: このクッキーを送るべきドメイン. path: このクッキーを送るべきパス名. secure: このクッキーは https の時のみ送られる (重要!) クッキーの削除: 過去の expires の日付けで Set-Cookie を送る. クッキーの取得 [UA →サーバ]
Cookie: NAME1=OPAQUE STRING1; NAME2=OPAQUE STRING2... マッチするものは全部送られる.全部で 4KB.
pathと domain は基本的には自分.path は prefix match.domain は
domain-match (後方マッチ).(TLD のみは NG)
キャッシュ
(Cache System=CS
,Origin Server=OS)
キャッシングの基本動作
:
1. CS
内のキャッシュエントリが期限切れでなければ,それを返 す.(CS
の中で折り返すので,OS
まで行かない.)
2.
期限切れなら,まだ使えるのかCS
がOS
に聞き,OS
が検証す る.(OS
まで行くが転送量は減る.ブラウザ側での再表示不要.)
期限切れの判定: Expires:
ヘッダと現在時刻を比較する.(Expires
の他に,Cache-Control:max-age=
秒数 を使うと,今から 何秒という指定もできる.)
キャッシュエントリの検証
検証方法は2
種類:
Last-Modified: OS
が考えるリソースの最終修正時刻(
秒以下 の分解能はないので確実ではない)
ETag:
そのリソースのハッシュ値等(
確実に判定できる)
関係する(Request)
ヘッダフィールド:
IF-Modifed-Since:
時刻 リソースが指定時刻より後に更新されていなければ,304 (Not
Modified)
を返す.IF-Match: entity-tag
前の状態から変化がなかったら実行(
主にPUT)
IF-None-Match: entity-tag
前の状態から変化があったら実行(
主にGET)
キャッシュ (その他)
キャッシュの禁止:
Cache-Control: no-cache
でキャッシュを禁止できる(
両方向)
. バック・フォワードボタン ユーザエージェントのもつ履歴(
バック,フォワードボタン)
は,以前に表示したものをそのまま表示することに意味があ るので,キャッシュ検証してはならない.アクセス認証 (BASIC 認証)
→リクエスト
GET ...
←レスポンス
401 Authorization Required
WWW-Authenticate: Basic realm="..."
→リクエスト
GET ...
Authorization: Basic
∼ realmは,何に対する認証かをさす (画面に表示される). ∼は Base64 エンコードした”ユーザ ID:パスワード” 以降,ブラウザは勝手に Authorization:フィールドを送る (ログアウトと いう概念はない)アクセス認証 (DIGEST 認証)
→リクエスト GET ... ←レスポンス
401 Authorization Required
WWW-Authenticate: Digest realm="…",nonce="…" →リクエスト
GET ...
Authorization: Digest username="…",nonce="...",cnonce="…",response= ∼
nonce, cnonce, user名, password から MD5 で response の∼を作る
cnonceはクライアントが作るランダム文字列
サーバにはパスワードを MD5 したものを置いておく
便利なツール
フェッチ
curl, wget, webcopy
パケットキャプチャ
tcpdump windump
wireshark (ethereal)