LoginSignup
1
0

More than 3 years have passed since last update.

Golang入門.2 -http.Handleの実装を見る-

Last updated at Posted at 2020-03-29

はじめに

 Golang入門.1 -http.HandleでHello World!-の続きです。

今回のテーマ

 http.Handle関数の処理を追いかけます。なお、今回も以下のコードを参照しますが、メインはhttp.Handle関数のソースコードです。

github

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 ServeMuxhandlerpatternが登録されるという説明を行いました。今回は実際にソースコードを見ながら処理の流れや使用されている構造体について確認していきます。具体的な説明は全てコード編にまとめます。

コード編

 実際にソースコードを読む手順で解説を行います。
 まず、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です。実装から明らかなように、handlerpatternが組みになっている構造体です。この構造体を必要に応じて追加していくことが処理の肝になってくることが予想されます。
 最後に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

で実際にpatternhandlerの情報を保持したmuxEntryを登録しています。また、mux.mがまだ存在しない場合はmake関数を用いて初期化しています。以上が登録までの流れです。

最後に

読んで頂きありがとうございました。server.ListenAnderve関数なども準備が出来次第記事にしたいと思います。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0