Go
Cgi
Go2Day 2

GoでCGIしてみる

というわけでCGIしてみます。

一般的なGoのWebアプリケーションからの置き換え

普通、GoでWebアプリケーションを作るときは、net/httpを用いてHTTPをしゃべるサーバを立てるかと思います。もしくは、各種フレームワークが同じようなことをやるでしょう。

import "net/http"

func main() {
    http.ListenAndServe(
        ":8080",
        http.HandlerFunc(func (w http.ResponseWriter, r *http.Request) {
            // do something
        }),
    )
}

CGIの場合は、Apache等のサーバがHTTPをしゃべるサーバとなり、CGIプログラムをサーバが実行します。なので、上記方法はそのまま使えません。

そこでGoにはnet/http/cgiというものがあります。これは上記net/httpListenAndServeを置き換えればいいだけです。

import (
    "net/http"
    "net/http/cgi"
)

func main() {
    cgi.Serve(
        http.HandlerFunc(func (w http.ResponseWriter, r *http.Request) {
            // do something
        }),
    )
}

ローカルでの確認方法

現代においてはApacheを立てるというのも相対的に難儀な作業になってきました。そこでCGIアプリケーションを確認するための簡易的な方法を紹介します。

HTTPサーバミドルウェアのh2oを用います。以下の設定でCGIアプリケーションの確認ができます。

listen:
  port: 8081
user: username
hosts:
  "localhost":
    paths:
      /:
        file.dir: ./
        file.index: ["index.cgi"]
        file.custom-handler:
          extension: .cgi
          fastcgi.spawn:
            command: "exec $H2O_ROOT/share/h2o/fastcgi-cgi"

access-log: log/access-log
error-log: log/error-log
pid-file: log/pid-file

以上をh2o.ymlで保存し、

$ h2o -c h2o.yml

で起動します。GoのCGIアプリケーションはindex.cgiで保存しておきます。もちろんパーミッションは実行可能にしておきます。これで簡単にローカルでCGIアプリケーションの確認ができます。

実際のCGIアプリケーションを作ってみる

https://gist.github.com/mackee/2247f081ad860ed36c7b27bb6886b862

というわけで作ってみました。

image.png

頑張ってる点としては

  • カウンタがファイルサイズで記録して追記で済ませるタイプ
  • コメント欄はファイル記録
    • 当時は考えていなかったCSRFだとかを考えないといけない
    • XSSはhtml/templateがある程度防御してくれている
  • ログはファイルに書いておいてレンタルサーバでデバッグしやすくする

という感じです。

まとめ

  • 簡単にですがGoでCGIについて説明しました
  • コンテナだとかサーバレスだとかはCGIっぽいアーキテクチャかと思います。CGIで済むのであればCGIでプライベートサーバレス環境を作ってみると面白いかと思います