From 86e2d1b0a48fbd84590291969611f1870471c3e0 Mon Sep 17 00:00:00 2001 From: Matthew Holt Date: Tue, 26 Mar 2019 15:45:51 -0600 Subject: Rudimentary start of HTTP servers --- modules/caddyhttp/caddyhttp.go | 75 ++++++++++++++++++++++++++++++++-- modules/caddyhttp/caddyhttp_test.go | 80 +++++++++++++++++++++++++++++++++++++ 2 files changed, 151 insertions(+), 4 deletions(-) create mode 100644 modules/caddyhttp/caddyhttp_test.go (limited to 'modules') diff --git a/modules/caddyhttp/caddyhttp.go b/modules/caddyhttp/caddyhttp.go index 296e28f..99efef0 100644 --- a/modules/caddyhttp/caddyhttp.go +++ b/modules/caddyhttp/caddyhttp.go @@ -1,7 +1,13 @@ package caddyhttp import ( + "fmt" "log" + "net" + "net/http" + "strconv" + "strings" + "time" "bitbucket.org/lightcodelabs/caddy2" ) @@ -9,7 +15,7 @@ import ( func init() { err := caddy2.RegisterModule(caddy2.Module{ Name: "http", - New: func() (interface{}, error) { return httpModuleConfig{}, nil }, + New: func() (interface{}, error) { return new(httpModuleConfig), nil }, }) if err != nil { log.Fatal(err) @@ -20,8 +26,69 @@ type httpModuleConfig struct { Servers map[string]httpServerConfig `json:"servers"` } +func (hc *httpModuleConfig) Run() error { + fmt.Printf("RUNNING: %#v\n", hc) + + for _, srv := range hc.Servers { + s := http.Server{ + ReadTimeout: time.Duration(srv.ReadTimeout), + ReadHeaderTimeout: time.Duration(srv.ReadHeaderTimeout), + } + + for _, lnAddr := range srv.Listen { + proto, addrs, err := parseListenAddr(lnAddr) + if err != nil { + return fmt.Errorf("parsing listen address '%s': %v", lnAddr, err) + } + for _, addr := range addrs { + ln, err := caddy2.Listen(proto, addr) + if err != nil { + return fmt.Errorf("%s: listening on %s: %v", proto, addr, err) + } + go s.Serve(ln) + } + } + } + + return nil +} + +func parseListenAddr(a string) (proto string, addrs []string, err error) { + proto = "tcp" + if idx := strings.Index(a, ":::"); idx >= 0 { + proto = strings.ToLower(strings.TrimSpace(a[:idx])) + a = a[idx+3:] + } + var host, port string + host, port, err = net.SplitHostPort(a) + if err != nil { + return + } + ports := strings.SplitN(port, "-", 2) + if len(ports) == 1 { + ports = append(ports, ports[0]) + } + var start, end int + start, err = strconv.Atoi(ports[0]) + if err != nil { + return + } + end, err = strconv.Atoi(ports[1]) + if err != nil { + return + } + if end < start { + err = fmt.Errorf("end port must be greater than start port") + return + } + for p := start; p <= end; p++ { + addrs = append(addrs, net.JoinHostPort(host, fmt.Sprintf("%d", p))) + } + return +} + type httpServerConfig struct { - Listen []string `json:"listen"` - ReadTimeout string `json:"read_timeout"` - ReadHeaderTimeout string `json:"read_header_timeout"` + Listen []string `json:"listen"` + ReadTimeout caddy2.Duration `json:"read_timeout"` + ReadHeaderTimeout caddy2.Duration `json:"read_header_timeout"` } diff --git a/modules/caddyhttp/caddyhttp_test.go b/modules/caddyhttp/caddyhttp_test.go new file mode 100644 index 0000000..c65a9a2 --- /dev/null +++ b/modules/caddyhttp/caddyhttp_test.go @@ -0,0 +1,80 @@ +package caddyhttp + +import ( + "reflect" + "testing" +) + +func TestParseListenerAddr(t *testing.T) { + for i, tc := range []struct { + input string + expectProto string + expectAddrs []string + expectErr bool + }{ + { + input: "", + expectProto: "tcp", + expectErr: true, + }, + { + input: ":", + expectProto: "tcp", + expectErr: true, + }, + { + input: ":1234", + expectProto: "tcp", + expectAddrs: []string{":1234"}, + }, + { + input: "tcp::::1234", + expectProto: "tcp", + expectAddrs: []string{":1234"}, + }, + { + input: "tcp6::::1234", + expectProto: "tcp6", + expectAddrs: []string{":1234"}, + }, + { + input: "tcp4:::localhost:1234", + expectProto: "tcp4", + expectAddrs: []string{"localhost:1234"}, + }, + { + input: "unix:::localhost:1234-1236", + expectProto: "unix", + expectAddrs: []string{"localhost:1234", "localhost:1235", "localhost:1236"}, + }, + { + input: "localhost:1234-1234", + expectProto: "tcp", + expectAddrs: []string{"localhost:1234"}, + }, + { + input: "localhost:2-1", + expectProto: "tcp", + expectErr: true, + }, + { + input: "localhost:0", + expectProto: "tcp", + expectAddrs: []string{"localhost:0"}, + }, + } { + actualProto, actualAddrs, err := parseListenAddr(tc.input) + if tc.expectErr && err == nil { + t.Errorf("Test %d: Expected error but got: %v", i, err) + } + if !tc.expectErr && err != nil { + t.Errorf("Test %d: Expected no error but got: %v", i, err) + } + if actualProto != tc.expectProto { + t.Errorf("Test %d: Expeceted protocol '%s' but got '%s'", i, tc.expectProto, actualProto) + } + if !reflect.DeepEqual(tc.expectAddrs, actualAddrs) { + t.Errorf("Test %d: Expected addresses %v but got %v", i, tc.expectAddrs, actualAddrs) + } + } +} -- cgit v1.2.3