http.HandleFunc, http.ListenAndServeの実装を辿ってみたメモ

GoでWebサーバを書く
===

GoでWebサーバを書く場合、標準の`net/http`パッケージを使用することが多い。
便利な反面、中身を知らずに使ってしまう危険があるように思う。

net/httpパッケージの利用
---

サーバを起動する最小限のコードは下記のようになるかと思う。

```go
func homeHandle(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Welcome to the home page!")
}

func main() {
	http.HandleFunc("/", homeHandle)
	http.ListenAndServe(":8080", nil)
}
```

以下、`http.HandleFunc`,`http.ListenAndServe`の実装について、
ドキュメントとソースコードからピックアップして辿ってみた内容をメモしておく。

goバージョンは下記を使用。

```
$ go version
go version go1.9.2 darwin/amd64
```

### http.HandleFunc

まずはmain()の一行目`http.HandleFunc`から見ていく。

```go
// HandleFunc registers the handler function for the given pattern
// in the DefaultServeMux.
// The documentation for ServeMux explains how patterns are matched.
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
	DefaultServeMux.HandleFunc(pattern, handler)
}
```

`DefaultServeMux.HandleFunc`が呼ばれている。
`DefaultServeMux`とは下記に定義されるように、デフォルトの`Servemux`である。

```go
// DefaultServeMux is the default ServeMux used by Serve.
var DefaultServeMux = &defaultServeMux

var defaultServeMux ServeMux
```
```go
type ServeMux struct {
    ...
}
```

つまり`DefaultServeMux.HandleFunc `とは`http.ServeMux.HandleFunc`に
定義されていることになる。

```go
// HandleFunc registers the handler function for the given pattern.
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
	mux.Handle(pattern, HandlerFunc(handler))
}
```

上記では`http.ServeMux.Handle`が呼ばれる。

```go
// 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) {
    ...
}
```

上記でpatternごとのhandler登録が行われるようである。
主要な処理部分は下記の一行である。

```go
	mux.m[pattern] = muxEntry{explicit: true, h: handler, pattern: pattern}
```

muxEntryとしてmux.mへの登録が行われる。
`Servemux`, `muxEntry`の定義は下記にある。

```go
type ServeMux struct {
	...
	m     map[string]muxEntry
	...
}

type muxEntry struct {
	explicit bool
	h        Handler
	pattern  string
}
```

また、`explicit`を使用して、重複した`pattern`が登録されないよう
チェックをおこなっている。

```go
	if mux.m[pattern].explicit {
		panic("http: multiple registrations for " + pattern)
	}
```

一度登録された後は`mux.m[pattern].explicit == true`となり、
同じ`pattern`に二度目に登録しようとすると`panic`が呼ばれることになる。

`http.Servemux.Handle`のコメント行にも下記とある。

> // If a handler already exists for pattern, Handle panics.


以上が`http.HandleFunc`部分となる。


### http.ListenAndServe

次に`http.ListenAndServe`を見ていく。
定義は下記となる。

```go
// ListenAndServe listens on the TCP network address addr
// and then calls Serve with handler to handle requests
// on incoming connections.
// ...
func ListenAndServe(addr string, handler Handler) error {
	server := &Server{Addr: addr, Handler: handler}
	return server.ListenAndServe()
}
```

`http.Server`にaddr, handlerが格納され、そのメソッドである、
`http.Server.ListenAndServe`が呼ばれるのが分かる。
その定義部分は下記となる。

```go
// ListenAndServe listens on the TCP network address srv.Addr and then
// calls Serve to handle requests on incoming connections.
func (srv *Server) ListenAndServe() error {
	...
    ln, err := net.Listen("tcp", addr)
    ...
    return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)})
}
```

指定したaddrが`net.Listen`に渡される。
その後は`net.Listener`を使用し、下記`http.Server.Serve`が呼ばれる。

```go
// Serve accepts incoming connections on the Listener l, creating a
// new service goroutine for each. The service goroutines read requests and
// then call srv.Handler to reply to them.
// ...
func (srv *Server) Serve(l net.Listener) error {
    ...
	baseCtx := context.Background() // base is always background, per Issue 16220
	ctx := context.WithValue(baseCtx, ServerContextKey, srv)
	for {
		rw, e := l.Accept()
        ...
        c := srv.newConn(rw)
		c.setState(c.rwc, StateNew) // before Serve can return
        go c.serve(ctx)
    }
}
```

`http.Server.Serve`では`context`や`net`パッケージを使った処理が行われているが、
この部分は今回のスコープ外のため割愛する。
(単に勉強不足のため別途学習した内容をまとめる予定)

> The service goroutines read requests and then call srv.Handler to reply to them.

ここで上記コメント内の記述にもある通り、`c.serve`メソッドがgoroutineとして起動される。

```go
// Serve a new connection.
func (c *conn) serve(ctx context.Context) {
    ...
	for {
        w, err := c.readRequest(ctx)
        ...
		// Until the server replies to this request, it can't read another,
		// so we might as well run the handler in this goroutine.
        // ...
        serverHandler{c.server}.ServeHTTP(w, w.req)
        ...
    }
}
```

上記で`http.Server`に保持していた情報は`serverHandler`に格納され、
そのメソッドである`ServeHTTP`が呼ばれる。定義は下記にある。

```go
// serverHandler delegates to either the server's Handler or
// DefaultServeMux and also handles "OPTIONS *" requests.
type serverHandler struct {
	srv *Server
}

func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {
	handler := sh.srv.Handler
	if handler == nil {
		handler = DefaultServeMux
	}
	...
	handler.ServeHTTP(rw, req)
}
```

ここで初めて、`http.ListenAndServe`に指定したhandlerが取り出される。

```go
	if handler == nil {
		handler = DefaultServeMux
	}
```

今回は`nil`を指定していたので、上記の処理で`http.DefaultServeMux`に置き換えられる。

```go
	handler.ServeHTTP(rw, req)
```

したがって上記`http.DefaultServeMux.ServeHTTP`の呼び出しによって、
`http.ResponseWriter`, `http.Request`が処理されるというのが分かった。
(ここの処理部分についても学習した後にまとめたいと思う)


## まとめ

以上で`http.HandleFunc`,`http.ListenAndServe`の実装を
ソースコードからピックアップして辿ってきた。

やり残しの課題は下記となる。

- `context`や`net`パッケージを使った処理
- `http.ServeMux.ServeHTTP`による`http.ResponseWriter`,`http.Request`の処理

cf. `net/http`パッケージのソースコード
→ 下記コマンドなどと打って確認

```bash
$ godoc -src net/http | less
```

- Web上の最新版(4/24更新)は下記  
https://golang.org/src/net/http/server.go