# HandleFunc 解析
* Listing 3.8
```go=
func hello(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello")
}
func main() {
http.HandleFunc("/hello", hello)
}
```
```shell=
http.HandleFunc("/hello", hello)
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request))
at: mux.Handle(pattern, HandlerFunc(handler))
call: func (mux *ServeMux) Handle(pattern string, handler Handler)
```
* `http.HandleFunc("/hello", hello)` call HandleFunc
* `HandleFunc` at line `2470`
* mux.Handle(pattern, HandlerFunc(handler))
* 把 handler (也就是 `hello()`) 轉成 `HandlerFunc` 型態
* [`pkg net/http`](https://golang.org/pkg/net/http/#HandlerFunc): HandlerFunc(f) is a Handler that calls f.
* `http.HandleFunc("/hello", hello)`
* `func HandleFunc(pattern string, handler func(ResponseWriter, *Request))`
* `func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request))`
* `func (*ServeMux) Handle`
* Handle registers the handler for the given pattern in the DefaultServeMux.
## HandleFunc
* 單純是個 wrapper,讓我們直接使用 `DefaultServeMux` 這個 內建的 instance
```go=
var defaultServeMux ServeMux
var DefaultServeMux = &defaultServeMux
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
DefaultServeMux.HandleFunc(pattern, handler)
}
```
* `DefaultServeMux` 只是一個 `ServeMux` 型態的 instance
* 因為我們呼叫 function 版本的` HandleFunc()` 時可以不用自己指定 ServeMux
* 如果需要的話也可以透過以下來宣告自己的 ServeMux 型態的 instance~
* 並直接用 Method 版本的 HandleFunc 註冊 handler
```go=
var myMux *ServeMux
// Register
myMux.HandleFunc(pattern, handler)
```
## `(mux *ServeMux) HandleFunc`
* method 版本的 HandleFunc
* 對 handler 做檢查
* 如果 handler not exist -> report error
* call `(*ServeMux).Handle()` 來執行 pattern & handler 的實際對應
* 把 `handler` (e.g. `hello()`) 轉成 `HandlerFunc` 型態
* `hello()` 在轉換前只是一個
* 沒有 type
* 擁有與 `HandlerFunc` 相同 funtion signature 的 function
* Why 需要轉換?
* 因為 `HandlerFunc` 這個 function value 具有 `ServeHTTP` 這個 method, 原本沒有註冊的 `hello()` 沒有
```go=
type HandlerFunc func(ResponseWriter, *Request)
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
if handler == nil {
panic("http: nil handler")
}
mux.Handle(pattern, HandlerFunc(handler))
}
```
```go=
// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
```
## `(mux *ServeMux) Handle`
* 真正進行註冊的 function
* 透過 `Servemux.m` 這個 map 來執行註冊這個動作
* 透過 `Servemux.m` 這個 `map[string]muxEntry` 來把對應的 pattern map 到對應的 handler 上
```go=
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
}
```
```go=
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
}
}
```
:::success
:bulb: TODO: 透過 `map[string]handler` 的方法來做 fib counting 的 handler function selector !
:::
## 執行
* :question: 有哪些 object implement `ServeHTTP()` method ?
```go=
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request)
func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request)
```
## Handler 與 HandlerFunc 差異?
* Handler 是個 interface
* HandlerFunc 是個 function value
* 具有 `HandlerFunc.ServeHTTP()` method
```go=
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
type HandlerFunc func(ResponseWriter, *Request)
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request)
```
* 為甚麼需要 `Handler` interface?
## How to serve?
### ListenAndServe
```go=
// Listen and serve (function)
func ListenAndServe(addr string, handler Handler) error {
server := &Server{Addr: addr, Handler: handler}
return server.ListenAndServe()
}
// Listen and serve (method)
// ListenAndServe listens on the TCP network address srv.Addr and then
// calls Serve to handle requests on incoming connections.
// Accepted connections are configured to enable TCP keep-alives.
//
// If srv.Addr is blank, ":http" is used.
//
// ListenAndServe always returns a non-nil error. After Shutdown or Close,
// the returned error is ErrServerClosed.
func (srv *Server) ListenAndServe() error {
...
ln, err := net.Listen("tcp", addr)
// handle error...
return srv.Serve(ln)
}
```
* What is `ln` ?
* `(net.Listener)` interface
* A Listener is a generic network listener for stream-oriented protocols.`
### `(src *Server).Serve(net.Listener)`
* accept connection from Listener `ln`
* create service goroutine for each connection
```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.
//
// HTTP/2 support is only enabled if the Listener returns *tls.Conn
// connections and they were configured with "h2" in the TLS
// Config.NextProtos.
//
// Serve always returns a non-nil error and closes l.
// After Shutdown or Close, the returned error is ErrServerClosed.
func (srv *Server) Serve(l net.Listener) error {
//...
for {
rw, err := l.Accept()
// handle err
connCtx := ctx
if cc := srv.ConnContext; cc != nil {
connCtx = cc(connCtx, rw)
if connCtx == nil {
panic("ConnContext returned nil")
}
}
tempDelay = 0
c := srv.newConn(rw)
c.setState(c.rwc, StateNew) // before Serve can return
go c.serve(connCtx)
}
}
func (srv *Server) newConn(rwc net.Conn) *conn {
c := &conn{
server: srv,
rwc: rwc,
}
if debugServerConnections {
c.rwc = newLoggingConn("server", c.rwc)
}
return c
}
```
* What does `srv.newConn(rw)` do?
* `func (srv *Server) newConn(rwc net.Conn) *conn`
* Create new connection from rwc.
* rwc: type: `type Conn interface`
* Conn is a generic stream-oriented network connection.
* ref: [pkg http - server.go](https://golang.org/src/net/http/server.go?s=78188:82485#L2510)
* `go c.serve(connCtx)`
* `c`:
* type `*conn`
* What is `conn`?
* `type conn struct`
* A conn represents the server side of an HTTP connection.
* [`func (c *conn) serve(ctx context.Context)`](https://golang.org/src/net/http/server.go?s=78188:82485#L1794)
* Serve a new connection.
* call [serverHandler{c.server}.ServeHTTP(w, w.req)
](https://golang.org/src/net/http/server.go?s=78188:82485#L1794)
```go=
func (c *conn) serve(ctx context.Context) {
...
// HTTP/1.x from here on.
for {
...
serverHandler{c.server}.ServeHTTP(w, w.req)
}
...
}
// 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 //serverHandler.Server.Handler (default is http.DefaultServeMux)
if handler == nil {
handler = DefaultServeMux
}
if req.RequestURI == "*" && req.Method == "OPTIONS" {
handler = globalOptionsHandler{}
}
handler.ServeHTTP(rw, req) // (Serve)
}
```
* 在 line 8:
* `handler := sh.srv.Handler`
* 就是把第一步
* `func ListenAndServe(addr string, handler Handler)` 註冊的 handler assign 到 `handler` 這個變數
* 如果一開始呼叫 `ListenAndServe()` 時沒有傳入 handler,
* 就會在 line 10 註冊成 `DefaultServeMux` 這個 `*ServeMux` 型態的 multiplexer
* 在 line 15:
* 呼叫 (*ServeMux).ServeHTTP(rw, req)
:::success
TODO:
* What is `sh.srv.Handler`?
* [`handler.ServeHTTP(rw, req)`]()
:::
## `(mux *ServeMux) ServeHTTP(rw, req)`
```go=
// ServeHTTP dispatches the request to the handler whose
// pattern most closely matches the request URL.
func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {
if r.RequestURI == "*" {
if r.ProtoAtLeast(1, 1) {
w.Header().Set("Connection", "close")
}
w.WriteHeader(StatusBadRequest)
return
}
h, _ := mux.Handler(r) // h - type: Handler, kind: interface
h.ServeHTTP(w, r)
}
```
* line 11:
* [`func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string)`
](https://golang.org/src/net/http/server.go?s=78188:82485#L1794)
* 作用
* Handler returns the handler to use for the given request,
* 也就是透過呼叫 `(mux *ServeMux) handler()` 來取出對應 `pattern` 的 handler,並 assign 給 `h`
* `(mux *ServeMux) handler(host, path string) (h Handler, pattern string)`
* `handler()` 呼叫 `(mux *ServeMux) match(path string) (h Handler, pattern string)`
* `match()` 會從 `ServeMux.m` 這個 map 取出對應 `pattern` 的 `Handler` `h`
* h - type: Handler, kind: interface
* 最後在 line 12 透過 h 這個 Handler 型態的 interface 呼叫
* `(f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request`
* 他會呼叫我們已經註冊的 對應 pattern 的 handler
### (mux *ServeMux) Handler(r *Request) (h Handler, pattern string)
```go=
// ServeMux is an HTTP request multiplexer.
// It matches the URL of each incoming request against a list of registered
// patterns and calls the handler for the pattern that
// most closely matches the URL.
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
}
func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string) {
// CONNECT requests are not canonicalized.
if r.Method == "CONNECT" {
// If r.URL.Path is /tree and its handler is not registered,
// the /tree -> /tree/ redirect applies to CONNECT requests
// but the path canonicalization does not.
if u, ok := mux.redirectToPathSlash(r.URL.Host, r.URL.Path, r.URL); ok {
return RedirectHandler(u.String(), StatusMovedPermanently), u.Path
}
return mux.handler(r.Host, r.URL.Path)
}
// All other requests have any port stripped and path cleaned
// before passing to mux.handler.
host := stripHostPort(r.Host)
path := cleanPath(r.URL.Path)
// If the given path is /tree and its handler is not registered,
// redirect for /tree/.
if u, ok := mux.redirectToPathSlash(host, path, r.URL); ok {
return RedirectHandler(u.String(), StatusMovedPermanently), u.Path
}
if path != r.URL.Path {
_, pattern = mux.handler(host, path)
url := *r.URL
url.Path = path
return RedirectHandler(url.String(), StatusMovedPermanently), pattern
}
return mux.handler(host, r.URL.Path)
}
// handler is the main implementation of Handler.
// The path is known to be in canonical form, except for CONNECT methods.
func (mux *ServeMux) handler(host, path string) (h Handler, pattern string) {
mux.mu.RLock()
defer mux.mu.RUnlock()
// Host-specific pattern takes precedence over generic ones
if mux.hosts {
h, pattern = mux.match(host + path)
}
if h == nil {
h, pattern = mux.match(path)
}
if h == nil {
h, pattern = NotFoundHandler(), ""
}
return
}
// Find a handler on a handler map given a path string.
// Most-specific (longest) pattern wins.
func (mux *ServeMux) match(path string) (h Handler, pattern string) {
// Check for exact match first.
v, ok := mux.m[path]
if ok {
return v.h, v.pattern
}
// Check for longest valid match. mux.es contains all patterns
// that end in / sorted from longest to shortest.
for _, e := range mux.es {
if strings.HasPrefix(path, e.pattern) {
return e.h, e.pattern
}
}
return nil, ""
}
// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
```