mhttp: implement MListenAndServe, using new mctx/mrun/mcfg framework
This commit is contained in:
parent
a0a531cdd2
commit
ef2e76de45
@ -10,35 +10,47 @@ import (
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/mediocregopher/mediocre-go-lib/m"
|
||||
"github.com/mediocregopher/mediocre-go-lib/mcfg"
|
||||
"github.com/mediocregopher/mediocre-go-lib/mctx"
|
||||
"github.com/mediocregopher/mediocre-go-lib/merr"
|
||||
"github.com/mediocregopher/mediocre-go-lib/mlog"
|
||||
"github.com/mediocregopher/mediocre-go-lib/mnet"
|
||||
"github.com/mediocregopher/mediocre-go-lib/mrun"
|
||||
)
|
||||
|
||||
// CfgServer initializes and returns an *http.Server which will initialize on
|
||||
// the Start hook. This also sets up config params for configuring the address
|
||||
// being listened on.
|
||||
func CfgServer(cfg *mcfg.Cfg, h http.Handler) *http.Server {
|
||||
cfg = cfg.Child("http")
|
||||
addr := cfg.ParamString("addr", ":0", "Address to listen on. Default is any open port")
|
||||
// MListenAndServe returns an http.Server which will be initialized and have
|
||||
// ListenAndServe called on it (asynchronously) when the start event is
|
||||
// triggered on ctx (see mrun.Start). The Server will have Shutdown called on it
|
||||
// when the stop event is triggered on ctx (see mrun.Stop).
|
||||
//
|
||||
// This function automatically handles setting up configuration parameters via
|
||||
// mcfg. The default listen address is ":0".
|
||||
func MListenAndServe(ctx mctx.Context, h http.Handler) *http.Server {
|
||||
ctx = mctx.ChildOf(ctx, "http")
|
||||
listener := mnet.MListen(ctx, "tcp", "")
|
||||
listener.NoCloseOnStop = true // http.Server.Shutdown will do this
|
||||
logger := mlog.From(ctx).WithKV(listener)
|
||||
|
||||
srv := http.Server{Handler: h}
|
||||
cfg.Start.Then(func(ctx context.Context) error {
|
||||
srv.Addr = *addr
|
||||
kv := mlog.KV{"addr": *addr}
|
||||
log := m.Log(cfg, kv)
|
||||
log.Info("listening")
|
||||
go func() {
|
||||
err := srv.ListenAndServe()
|
||||
// TODO the listening log should happen here, somehow, now that we
|
||||
// know the actual address being listened on
|
||||
log.Fatal("http server fataled", mlog.ErrKV(err))
|
||||
}()
|
||||
mrun.OnStart(ctx, func(mctx.Context) error {
|
||||
srv.Addr = listener.Addr().String()
|
||||
mrun.Thread(ctx, func() error {
|
||||
if err := srv.Serve(listener); err != http.ErrServerClosed {
|
||||
logger.Error("error serving listener", merr.KV(err))
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return nil
|
||||
})
|
||||
|
||||
// TODO shutdown logic
|
||||
mrun.OnStop(ctx, func(innerCtx mctx.Context) error {
|
||||
logger.Info("shutting down server")
|
||||
if err := srv.Shutdown(context.Context(innerCtx)); err != nil {
|
||||
return err
|
||||
}
|
||||
return mrun.Wait(ctx, innerCtx.Done())
|
||||
})
|
||||
|
||||
return &srv
|
||||
}
|
||||
|
||||
|
@ -1,12 +1,51 @@
|
||||
package mhttp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
. "testing"
|
||||
|
||||
"github.com/mediocregopher/mediocre-go-lib/mctx"
|
||||
"github.com/mediocregopher/mediocre-go-lib/mlog"
|
||||
"github.com/mediocregopher/mediocre-go-lib/mrun"
|
||||
"github.com/mediocregopher/mediocre-go-lib/mtest/massert"
|
||||
)
|
||||
|
||||
func TestMListenAndServe(t *T) {
|
||||
ctx := mctx.ChildOf(mctx.New(), "test")
|
||||
mlog.CtxSet(ctx, mlog.From(ctx).WithMaxLevel(mlog.DebugLevel))
|
||||
|
||||
h := http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
io.Copy(rw, r.Body)
|
||||
})
|
||||
|
||||
srv := MListenAndServe(ctx, h)
|
||||
if err := mrun.Start(ctx); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
body := bytes.NewBufferString("HELLO")
|
||||
resp, err := http.Post("http://"+srv.Addr, "text/plain", body)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
respBody, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
} else if string(respBody) != "HELLO" {
|
||||
t.Fatalf("unexpected respBody: %q", respBody)
|
||||
}
|
||||
|
||||
if err := mrun.Stop(ctx); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddXForwardedFor(t *T) {
|
||||
assertXFF := func(prev []string, ipStr, expected string) massert.Assertion {
|
||||
r := httptest.NewRequest("GET", "/", nil)
|
||||
|
Loading…
Reference in New Issue
Block a user