はじめに
Golang入門.1 -http.HandleでHello World!-の続きです。
今回のテーマ
http.Handle
関数の処理を追いかけます。なお、今回も以下のコードを参照しますが、メインはhttp.Handle
関数のソースコードです。
[github] (https://github.com/ryuji0123/go-samples/blob/master/mux.go)
package main
import (
"fmt"
"net/http"
)
type HelloHandler struct{}
func (h *HelloHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello World!")
}
func main() {
hello := HelloHandler{}
server := http.Server{
Addr: "127.0.0.1:8080",
}
http.Handle("/", &hello)
server.ListenAndServe()
}
概念編
前回、type ServeMux
にhandler
とpattern
が登録されるという説明を行いました。今回は実際にソースコードを見ながら処理の流れや使用されている構造体について確認していきます。具体的な説明は全てコード編にまとめます。
コード編
実際にソースコードを読む手順で解説を行います。
まず、Handle
関数の実装を確認します。
// Handle registers the handler for the given pattern
// in the DefaultServeMux.
// The documentation for ServeMux explains how patterns are matched.
func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }
どうやらDefaultServeMux
におけるHandle
関数を呼び出すために定義されているようです。次にDefaultServeMux
の実装を確認します。
// DefaultServeMux is the default ServeMux used by Serve.
var DefaultServeMux = &defaultServeMux
var defaultServeMux ServeMux
ここだけ見ても特にわかりませんね。type ServeMux
が鍵になりそうです。
type ServeMux struct {
mu sync.RWMutex
m map[string]muxEntry
es []muxEntry // slice of entries sorted from longest to shortest.
hosts bool // whether any patterns contain hostnames
}
type muxEntry struct {
h Handler
pattern string
}
ようやく構造体にたどり着きました。次に示すHandle
関数を見るとわかるのですが、今回注目しているhandler
の登録に関わっているのはServeMux.m
です。より直接的にはServeMux.m
に格納されているtype muxEntry
です。実装から明らかなように、handler
とpattern
が組みになっている構造体です。この構造体を必要に応じて追加していくことが処理の肝になってくることが予想されます。
最後にHandle
関数の実装を確認します。
// Handle registers the handler for the given pattern.
// If a handler already exists for pattern, Handle panics.
func (mux *ServeMux) Handle(pattern string, handler Handler) {
mux.mu.Lock()
defer mux.mu.Unlock()
if pattern == "" {
panic("http: invalid pattern")
}
if handler == nil {
panic("http: nil handler")
}
if _, exist := mux.m[pattern]; exist {
panic("http: multiple registrations for " + pattern)
}
if mux.m == nil {
mux.m = make(map[string]muxEntry)
}
e := muxEntry{h: handler, pattern: pattern}
mux.m[pattern] = e
if pattern[len(pattern)-1] == '/' {
mux.es = appendSorted(mux.es, e)
}
if pattern[0] != '/' {
mux.hosts = true
}
}
序盤では同期処理やエラー処理を行なっています。その後、
if _, exist := mux.m[pattern]; exist {
panic("http: multiple registrations for " + pattern)
}
ではpattern
が既出であるか確認しています。そして、
if mux.m == nil {
mux.m = make(map[string]muxEntry)
}
e := muxEntry{h: handler, pattern: pattern}
mux.m[pattern] = e
で実際にpattern
とhandler
の情報を保持したmuxEntry
を登録しています。また、mux.m
がまだ存在しない場合はmake
関数を用いて初期化しています。以上が登録までの流れです。
最後に
読んで頂きありがとうございました。server.ListenAnderve
関数なども準備が出来次第記事にしたいと思います。