Go
golang
HTTP
HttpServer

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

この記事は?

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

ソースコードはこちら🔥

きっかけ

アドベントカレンダーのネタを考えていたら、@todokrさんからネタをもらいパクらせていただきました。(アドベントカレンダーには間に合わなかったけど。。)

注意事項

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

仕様

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

郷ひろみについて

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

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

2億4千万の瞳について

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

歌詞はこちらから🎧

メイン処理

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

  • ソケットを作成
  • ↑で作ったソケットでクライアントからの接続を待つ
  • クライアントからのリクエストを読み込む
  • パスがRootの場合は読み込むファイルを指定する
  • ファイルを読み込む
  • レスポンスのステータスコードを作成する
  • ファイルの拡張子に合うContent-typeを設定する
  • レスポンスを作成する
  • レスポンスをクライアントに返却する
  • コネクションを閉じる
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-Languageja-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の仕様ではステータスコードは3桁である必要があったので、泣く泣く断念。ちなみに2400000000(2億4千万) Exotic!を設定すると桁が溢れるからかChromeなどのブラウザでは2400000000(2億4千万)を表示してくれませんでした😩

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

最後に

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

参考資料

簡単なHTTPサーバーを作る
todokr/simple-http-server
新しいプログラミング言語の学び方 HTTPサーバーを作って学ぶ Java, Scala, Clojure
GoでたたくTCPソケット(前編)
Webサーバを作りながら学ぶ 基礎からのWebアプリケーション開発入門
izqui/Taylor