早くエンジニアになりたい

masatany's memorandum

nc(netcat)コマンドでHTTPサーバーの気持ちを知る

この記事はFusic Advent Calendar 2017 12日目の記事です。

WEBエンジニアとしていつもお世話になっているApacheやNginxと言った「HTTPサーバーの気持ち」を知ろうと思い立ったので、ncコマンドを使ってHTTPリクエストを受けてHTTPレスポンスを返す一連の流れを体験してみました。

まがいなりにもネットワークスペシャリストなのでネットワーク関連の記事を書こうと思っていましたが、良いネタが思いつかなかったので、今日はレイヤー7で遊ぼうと思います。

ncコマンドで簡易サーバーを立てる

何はともあれ、HTTPを受けるためのサーバーが必要です。 8000番ポートで待ち受けるTCPサーバーをncコマンドで構築します。

while : ; do  nc -l 127.0.0.1 8000; done

これでオレオレHTTPサーバ(文字通り)の構築は終わりです。簡単ですね。 もちろんこのサーバーは、同時に1つのリクエストしか処理できません。

ncコマンドはコネクションがクローズすると、プロセスが終了してしまいます。 一々コマンドを再実行してもいいですが、面倒臭いのでwhileで永続化しています。

HTTPリクエストを受けてみる

おもむろにブラウザ(Chromeがおすすめ)を立ち上げて、http://localhost:8000にアクセスしてみます。 おそらく、下記のようなHTTPリクエストが飛んでくるはずです。

$ while : ; do  nc -l 127.0.0.1 8000; done
GET / HTTP/1.1
Host: localhost:8000
Connection: keep-alive
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36
Upgrade-Insecure-Requests: 1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: ja,en-US;q=0.9,en;q=0.8
Cookie: username-localhost-50080="2|1:0|10:1511168650|24:username-localhost-50080|44:Nzc3OWJmNjE0NTI5NDEzZDk2Y2I2MzU5ZmEwMmE1MDQ=|4279df9a2de706e91212b77f6ef85216f0b7f2f9fb8211e6430c53b5f283b952"

f:id:k_masatany:20171208233945p:plain

ブラウザにはまだ何も表示されません。 レスポンスを返していないのだから当然ですね。

HTTPレスポンスを返す

いつまでもブラウザを待たせているのもかわいそうなので、そろそろレスポンスを返してあげます。 コンソールに、下記の内容のレスポンスヘッダを返します。

HTTP/1.1 200 OK
Server: k-masatany 28.5 (nightly)
Content-Type: text/html

<!DOCTYPE html>
<html>
<title>nc server</title>
</head>
<body>

ここまで入力すると、Chromeを使っていれば、開いているページが真っ白になり、ページタイトルが「nc server」になっているはずです。 Safariだと、Ctrl+DでEOFを送信するまでレンダリングは行われませんでした。 f:id:k_masatany:20171208234624p:plain

bodyの内容も送る

真っ白なページでは面白くないのでbodyの内容を送ってみましょう。 先ほどの<body>に続いて、下記の内容を書いて行きます。

<div>Hello, HTTP World!</div>
<h1>H1 Message</h1>
<h2 style="color: red">Red Color Message<h2>
<h3>hogehoge</h3>

Chromeでは、タグを閉じるたび、レンダリングが行われます。 f:id:k_masatany:20171208235246p:plain

404 NotFoundを返してみる

http://localhost:8000/notfoundにアクセスしてみます。 ここにはコンテンツがないので、404を返してみます。 (オレオレHTTPサーバにはそもそもコンテンツがないので全部404なのですが・・・)

HTTP/1.1 404 Not Found
Server: k-masatany 28.5 (nightly)
Content-Type: text/html

<!DOCTYPE html>
<html>
<title>nc server</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/css/bootstrap.min.css" integrity="sha384-PsH8R72JQ3SOdhVi3uxftmaW6Vc51MKb0q5P2rRUpPvrszuE4W1povHYgTpBfshb" crossorigin="anonymous">
</head>
<body>
<h1 class="display-1">404 Not Found</h1>
<p class="h2">ご指定のページは見つかりませんでした<p>

f:id:k_masatany:20171209002214p:plain おっと、文字化けしてますね(しれっとBootstrap適用)。

ページをリロードして、metaタグを追加したレスポンスbodyを再送信します。

HTTP/1.1 404 Not Found
Server: k-masatany 28.5 (nightly)
Content-Type: text/html

<!DOCTYPE html>
<html>
<meta charset="utf-8">
<title>nc server</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/css/bootstrap.min.css" integrity="sha384-PsH8R72JQ3SOdhVi3uxftmaW6Vc51MKb0q5P2rRUpPvrszuE4W1povHYgTpBfshb" crossorigin="anonymous">
</head>
<body>
<h1 class="display-1">404 Not Found</h1>
<p class="h2">ご指定のページは見つかりませんでした<p>

f:id:k_masatany:20171209002222p:plain 日本語も無事表示されました。

404ステータスコードを返しても、bodyにコンテンツを入れていると、描画されてしまうので、 レスポンスボディを消してみます。

HTTP/1.1 404 Not Found
Server: k-masatany 28.5 (nightly)
Content-Type: text/html
^D # Ctrl+D

ChromeのHTTP ERROR 404ページになりました。 きちんとステータスコードが影響しています。f:id:k_masatany:20171209002839p:plain

HTTPで遊んでみて

色々HTTPで遊んでみましたが、各種HTTPヘッダに対する応答をはじめ、オレオレおHTTPサーバーでは様々な機能が使えません。

こんな面倒なことをいつも一瞬でやってくれているHTTPサーバーに感謝を感じる遊びでした。

最後に

忙しくてレスポンスが返せない時は、きちんと503エラーを返しましょう。

f:id:k_masatany:20171209003745p:plain

HTTP/1.1 503 Service Unavailable
Server: k-masatany 28.5 (nightly)
Content-Type: text/html
^D # Ctrl+D