HTTP リクエストを手で書く
このラボはVM上で動きます
python3 -m http.serverで小さなWebサーバーを起動し、ブラウザーなしで、ncでリクエストを直接タイプします。HTTPはテキストなので、それができます。
目標
リクエスト行・ヘッダー・空行の構造を手で作り、200・301・404・501のレスポンスを直接受け取って、curl -vが表示するものと突き合わせます。
なぜ重要なのか
HTTPはTCP上のテキストです。リクエスト1行、ヘッダー数行、空行1つ。それがすべてです。この構造を手で作ったことのある人は、プロキシがヘッダーを書き換えるとき、Hostが間違って見当違いのサイトが表示されるとき、リダイレクトがループするときに、何を見ればよいかがわかります。curl -vの>と<を読めることが、APIデバッグの半分です。
ステップ
/root/http/www/index.htmlと/root/http/www/docs/guide.txtを作成し、/root/http/wwwを127.0.0.1:8080で配信するpython3 -m http.serverを起動してください(ログは/root/http/server.logへ)。ncでGET / HTTP/1.1のリクエストを直接書いて送り、レスポンス全体を/root/http/get.txtに保存してください。- 存在しないパス
/missingをリクエストして、404のレスポンスを/root/http/notfound.txtに保存してください。 HEAD /リクエストのレスポンスを/root/http/head.txtに保存してください。ヘッダーはあり、本文はない必要があります。- 末尾にスラッシュのない
/docsをリクエストして、301とLocationヘッダーを含むレスポンスを/root/http/redirect.txtに保存してください。 curl -vで/docs/guide.txtを取得し、リクエストとレスポンスのヘッダーがすべて含まれる出力を/root/http/curl.txtに保存してください。curl -o /dev/null -w '%{http_code}'で、/・/docs・/nopeのステータスコードを、/root/http/codes.txtに경로=코드の3行で保存してください(プレースホルダーはパスとステータスコードです)。/root/http/report.mdに、status_ok=・status_redirect=・status_missing=の3行と、リクエストの3つの部分(リクエスト行・ヘッダー・空行)がそれぞれ何かを書いてください。
参考
- サーバー:
setsid python3 -m http.server 8080 --bind 127.0.0.1 --directory /root/http/www > /root/http/server.log 2>&1 < /dev/null &。 - リクエストの書き方:
printf 'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n' | nc -q 1 127.0.0.1 8080。行末は\r\nで、ヘッダーの後の空行がリクエストの終わりです。 curl -vは、>で送ったもの、<で受け取ったものを表示します。- よくある間違い: 最後の空行を書き忘れることです。サーバーはリクエストが終わるのを待ち続けます。
小さなサイト
/root/http/www/index.html と /root/http/www/docs/guide.txt を作成し、/root/http/wwwを127.0.0.1:8080で配信するpython3 -m http.serverを起動してください(ログは /root/http/server.log へ)。
index.htmlには<h1>タグが1行あれば十分です。サーバーは--directory /root/http/www --bind 127.0.0.1 8080で起動し、ログを/root/http/server.logへ出力してください。ss -ltnに8080が表示されている必要があります。
GETを手で書く
ncでGET / HTTP/1.1のリクエストを直接書いて送り、レスポンス全体を /root/http/get.txt に保存してください。
printf 'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n' | nc -q 1 127.0.0.1 8080 > /root/http/get.txt。レスポンスは、ステータス行、ヘッダー、空行、本文の順です。200 OKとContent-typeと<h1>が表示されている必要があります。
存在しないものを要求すると
存在しないパス/missingをリクエストして、404のレスポンスを /root/http/notfound.txt に保存してください。
ステップ2と同じリクエストで、パスだけを/missingにします。ステータス行が404になっている必要があります。サーバーは生きていて、リソースだけがないという意味です。TCPは成功しています。
HEAD
HEAD /リクエストのレスポンスを /root/http/head.txt に保存してください。ヘッダーはあり、本文はない必要があります。
メソッドだけをHEADに変えてください。Content-Lengthはそのまま返りますが、本文は来ません。大きなファイルのサイズだけを知りたいときや、ヘルスチェックに使います。
301とLocation
末尾にスラッシュのない/docsをリクエストして、301とLocationヘッダーを含むレスポンスを /root/http/redirect.txt に保存してください。
パスは/docs(スラッシュなし)です。ディレクトリなので、サーバーが301とLocation: /docs/で「あちらへ行くように」と答えます。ブラウザーとcurl -Lは、これをたどります。
curl -vで読む
curl -vで/docs/guide.txtを取得し、リクエストとレスポンスのヘッダーがすべて含まれる出力を /root/http/curl.txt に保存してください。
curl -sv http://127.0.0.1:8080/docs/guide.txt > /root/http/curl.txt 2>&1。-vの出力は標準エラー出力なので、2>&1が必要です。> GET /docs/guide.txtと< HTTP/1.0 200 OK、< Content-type: text/plainが表示されている必要があります。
ステータスコードだけ
curl -o /dev/null -w '%{http_code}'で、/・/docs・/nopeのステータスコードを、/root/http/codes.txt に경로=코드の3行で保存してください(プレースホルダーはパスとステータスコードです)。
curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8080/docsが301を返します(-Lを付けていないので、リダイレクトをたどりません)。3行: /=200、/docs=301、/nope=404。
学んだこと
/root/http/report.md に、status_ok=・status_redirect=・status_missing=の3行と、リクエストの3つの部分(リクエスト行・ヘッダー・空行)がそれぞれ何かを書いてください。
3つの値はステップ7のコードです。本文には、Hostヘッダーがなぜ必要か、空行が何を意味するかを含める必要があります。サーバーログ(/root/http/server.log)に、これまでのリクエストがすべて残っているかも確認してください。