Real World Httpを読んだので、まとめ(第1章)

zumikiti

December 10, 2019

HTTP の歴史

# server.go
package main

import (
	"fmt"
	"log"
	"net/http"
	"net/http/httputil"
)

func handler(w http.ResponseWriter, f *http.Request) {
	dump, err := httputil.DumpRequest(f, true)
	if err != nil {
		http.Error(w, fmt.Sprint(err), http.StatusInternalServerError)
		return
	}
	fmt.Println(string(dump))
	fmt.Fprint(w, "<html><body>hello</body></html>\n")
}

func main() {
	var httpServer http.Server
	http.HandleFunc("/", handler)
	log.Println("start http listing :1888")
	httpServer.Addr = ":1888"
	log.Println(httpServer.ListenAndServe())
}

サーバーを起動する。

$ go run server.go
2019/12/07 08:07:55 start http listing :1888

1.2 HTTP0.9 でできること

# 単純な GET 
$ curl --http1.0 http://localhost:1888/greeting
<html><body>hello</body></html> 

[server.go 側]
GET /greeting HTTP/1.0
Host: localhost:1888
Connection: close
Accept: */*
User-Agent: curl/7.54.0
# 検索条件追加した場合
# --data-urlencode は --get があるときに動作
# http://localhost:1888?search=world となる"
$ curl --http1.0 --get --data-urlencode "search world" http://localhost:1888

[server.go 側]
GET /?search%20world HTTP/1.0
Host: localhost:1888
Connection: close
Accept: */*
User-Agent: curl/7.54.0

1.3 HTTP/0.9 から 1.0 への道のり

# 詳細なレスポンスの内容をみる(-v)
$ curl -v --http1.0 http://localhost:1888
* Rebuilt URL to: http://localhost:1888/
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 1888 (#0)
> GET / HTTP/1.0
> Host: localhost:1888
> User-Agent: curl/7.54.0
> Accept: */*
>
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Date: Fri, 06 Dec 2019 22:57:28 GMT
< Content-Length: 32
< Content-Type: text/html; charset=utf-8
<
<html><body>hello</body></html>
* Closing connection 0

1.4 HTTP の祖先(1) 電子メール

1.4.1 ヘッダーの送信

mail ヘッダーの送信(-H)

$ curl --http1.0 -H "X-Text: Hello" http://localhost:1888

[server.go 側]
2019/12/07 08:07:55 start http listing :1888
GET / HTTP/1.0
Host: localhost:1888
Connection: close
Accept: */*
User-Agent: curl/7.54.0
X-Text: Hello

User-Agent を偽装する

$ curl --http1.0 -A "Mozille/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)" http://localhost:1888

[server.go 側]
GET / HTTP/1.0
Host: localhost:1888
Connection: close
Accept: */*
User-Agent: Mozille/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)

1.4.3 MIME タイプ

ファイルの種類を区分するための文字列で、電子メールのために作られた。初出は1992年のRFC1341です。 ブラウザでは、MIME タイプによって画面に表示したり、保存ダイアログを出したりといった機能を提供します。

1.4.5 電子メールとの違い

HTTP の通信は高速で電子メールが往復しているとも言える。

HTTP もヘッダーを改行コードで折り返すことを許可していたが、一部ブラウザでうまく動作せず、レスポンス分割攻撃という攻撃に悪用されることもあったため、RFC7230 で非推奨となりました。

1.5 HTTP の先祖(2) ニュースグループ

ニュースグループという大規模掲示板があった。 複数のサーバがマスター・スレーブ構造で繋がっており、スレーブのサーバーがマスターのサーバーに定期的に情報を取りに行く。この通信に使用されていたのが、Network News Transfer Protocol (NNTP)。 HTTP/0.9 の 5年前の1986年に RFC977 で定義されています。

# POST リクエスト
$ curl --http1.0 -X POST http://localhost:1888/greeting
# server.go側
POST /greeting HTTP/1.0
Host: localhost:1888
Connection: close
Accept: */*
User-Agent: curl/7.54.0

1.5.2 ステータスコード

1.6 リダイレクト

300 番台のステータスの一部は、サーバーがブラウザに対して、指示するステータスコードです。300 以外の場合は、Location ヘッダーを使ってリダイレクト先をサーバーからクライアントへ伝達します。

| ステータスコード | メソッドの変更 | 恒久的 / 一時的 | キャッシュ | 説明 | |–

クライアントは、Location ヘッダーを見て、サイドリクエストを送信し直します。 curl コマンドに -L を付与すると、ステータスコード 300 番台かつ Location ヘッダーに値があれば、その指定された URL に再度リクエストを送信します。

リダイレクト回数は、HTTP/1.0 の最初の RFC では、5回までを目安と書かれていたが、RFC2616 の HTTP/1.1 でその制限がなくなりました。 しかし、Google では以下の欠点からリダイレクト回数は5回以下、できれば3回以下というガイドラインが設けられている。 リダイレクトの欠点として、リダイレクト先が別サーバーだった場合、 TCP セッションの接続、HTTP の送受信と2往復の通信が発生します。リダイレクトが増えるほど表示に時間がかかる。

1.7 URL (Uniform Resource Locators)

1.7.1 URL の構造

URL の全要素が入ったサンプルは以下。
スキーマ://ユーザ:パスワード@ホスト名:ポート/パス#フラグメント?クエリー

1.7.2 URL と国際化

1.8 ボディ

* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Date: Mon, 09 Dec 2019 22:13:27 GMT
< Content-Length: 32
< Content-Type: text/html; charset=utf-8
< ##### これ以降の Content-Length で指定されたバイト数分がボディ
<html><body>hello</body></html>
* Closing connection 0
# JSON 送信
$ curl -d "{\"hello\": \"World\"}" -H "Content-Type: application/json" http://localhost:1888

# ローカルに test.json がある場合
$ curl -d @test.json -H "Content-Type: application/json" http://localhost:1888

GET リクエスト時のボディ

# -X GET で強制的にメソッドを切り替える
$ curl -X GET --data "hello=world" http://localhost:1888

# server.go 側の表示
GET / HTTP/1.1
Host: localhost:1888
Accept: */*
Content-Length: 11
Content-Type: application/x-www-form-urlencoded
User-Agent: curl/7.54.0

hello=world