GoでHiromiというエキゾチックでシンプルなHTTPサーバーを作った

# この記事は？
ネタです！
Go言語とHTTPサーバーの作りを学ぶためにGoでステータスコード`240 Exotic!`を返すシンプルなHTTPサーバーを作ってみました!
Goで作ったので名前はHiromiです🎤

ソースコードは[こちら](https://github.com/tofu511/Hiromi)🔥

# きっかけ
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">Swiftで書かれた「Taylor」というナイスな名前のHTTPサーバーがあったので、 Goで書かれた「Hiromi」があってもいいのではないか。リクエストのAccept-Languageがjaの場合、「2億6000万 Exotic」というステータスコードを返しちゃうようなやつ。<a href="https://t.co/kpo3Uvzg04">https://t.co/kpo3Uvzg04</a></p>&mdash; Shunsuke Tadokoro (@todokr) <a href="https://twitter.com/todokr/status/1045708609647140864?ref_src=twsrc%5Etfw">2018年9月28日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
アドベントカレンダーのネタを考えていたら、@todokrさんからネタをもらいパクらせていただきました。(アドベントカレンダーには間に合わなかったけど。。)

# 注意事項
ネタで作ったHTTPサーバーなので、セキュリティなどはあまり考慮できていません。
(ないとは思うけど)この実装を使用して発生して起きた問題には作者は一切責任を負いません。

# 仕様
- `localhost:5163`でHTTPリクエストを受け取り、HTTPレスポンスを返す
- 対応するHTTPメソッドは`GET`のみ
- リクエストはブロックしない（マルチスレッド）
- Keep-Aliveしない
- HTTP Cacheしない
- **Accept-Languageが`ja`の場合、ステータスコード`200 OK`が`240 Exotic!`になる**

# 郷ひろみについて
>郷 ひろみ（ごう ひろみ、1955年10月18日 - ）は、日本の男性歌手、俳優、タレントで新御三家の1人。本名は原武 裕美（はらたけ ひろみ）。血液型A型、身長178cm (Wikipediaより)

みなさんご存知ですよね！

# 2億4千万の瞳について
>「2億4千万の瞳 -エキゾチック・ジャパン-」（におくよんせんまんのひとみ エキゾチック・ジャパン）は、郷ひろみの楽曲で、50枚目のシングル。1984年2月25日発売。

歌詞は[こちらから](http://www.kasi-time.com/item-32288.html)🎧

# メイン処理
メインの処理では大まかに以下のことを行なっています。
思っていたよりやることは少なくシンプルになりました。

- ソケットを作成
- ↑で作ったソケットでクライアントからの接続を待つ
- クライアントからのリクエストを読み込む
- パスがRootの場合は読み込むファイルを指定する
- ファイルを読み込む
- レスポンスのステータスコードを作成する
- ファイルの拡張子に合うContent-typeを設定する
- レスポンスを作成する
- レスポンスをクライアントに返却する
- コネクションを閉じる

```go
func main() {
	endpoint := strings.Join([]string{Host, Port}, ":")
	listener, err := net.Listen("tcp", endpoint) // ソケット作成
	if err != nil {
		panic(err)
	}

	fmt.Printf("Server is running at %s\n", endpoint)

	for {
		conn, err := listener.Accept() // クライアントからの接続を待つ

		if err != nil {
			panic(err)
		}

		go func() {
			request := parseRequest(conn) // クライアントからのリクエストを読み込む

			filePath := convertPath(DocumentRoot + request.URL.Path) // パスがRootの場合は読み込むファイルを指定する
			file := readFileFromUrlPath(filePath) // ファイルを読み込む

			status := createStatus(filePath, request.Header.Get("Accept-Language")) // レスポンスのステータスコードを作成する

			contentType, _ := contentTypeMap[path.Ext(filePath)] // ファイルの拡張子に合うContent-typeを設定する

			response := createResponse(status, contentType, string(file)) // レスポンスを作成する

			fmt.Fprint(conn, response) // レスポンスをクライアントに返却する

			conn.Close() // コネクションを閉じる
		}()
	}
}
```

# リクエストを送ってみる
サーバーを起動させた後、Chromeから`localhost:5163`にリクエストを送ってみると以下のようなレスポンスが返ります。

```
HTTP/1.1 240 Exotic!
Server: Hiromi
Date: Tue, 25 Dec 2018 23:10:16 JST
Connection: close
Content-type: text/html
```

`Accept-Language`が`ja-JP`じゃない場合はこうなります。

```
HTTP/1.1 200 OK 
Server: Hiromi
Date: Tue, 25 Dec 2018 23:13:45 JST
Connection: close
Content-type: text/html
```

# やりたかったけど断念したこと
- ステータスコードは`2400000000(2億4千万) Exotic!`を返したかったが、RFCの仕様ではステータスコードは３桁である必要があったので、泣く泣く断念。ちなみに`2400000000(2億4千万) Exotic!`を設定すると桁が溢れるからかChromeなどのブラウザでは`2400000000(2億4千万)`を表示してくれませんでした😩

- 郷ひろみの写真を表示したかったけど権利の関係で断念😓

# 最後に
作ったものは結構なネタですが、HTTPサーバーを自作すると普段HTTP通信でどのようなことが行われているか理解できます。
シンプルなHTTPサーバーであれば処理自体もそこまで複雑ではないので、新しい言語の勉強にも使えるので一石二鳥です！

# 参考資料
[簡単なHTTPサーバーを作る](https://qiita.com/opengl-8080/items/ca152658a0e52c786029)
[todokr/simple-http-server](https://github.com/todokr/simple-http-server)
[新しいプログラミング言語の学び方 HTTPサーバーを作って学ぶ Java, Scala, Clojure](https://speakerdeck.com/todokr/xin-siihurokuraminkuyan-yu-falsexue-hifang-httpsahawozuo-tutexue-hu-java-scala-clojure)
[GoでたたくTCPソケット（前編）](http://ascii.jp/elem/000/001/276/1276572/)
[Webサーバを作りながら学ぶ　基礎からのWebアプリケーション開発入門](http://amzn.asia/d/fvXTzaa)
[izqui/Taylor](https://github.com/izqui/Taylor)