Last active
December 19, 2016 03:13
-
-
Save earthboundkid/855c31109df51d42bc2fca7da7cab23c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| import ( | |
| "fmt" | |
| "log" | |
| "net" | |
| "net/http" | |
| "time" | |
| ) | |
| func hello(w http.ResponseWriter, r *http.Request) { | |
| fmt.Fprintf(w, "Hello\n") | |
| } | |
| type RequestFilter func(*http.Request) bool | |
| func PasswordHeader(password string) RequestFilter { | |
| return func(r *http.Request) bool { | |
| return r.Header.Get("X-Password") == password | |
| } | |
| } | |
| func CIDR(cidrs ...string) RequestFilter { | |
| nets := make([]*net.IPNet, len(cidrs)) | |
| for i, cidr := range cidrs { | |
| // TODO: handle err | |
| _, nets[i], _ = net.ParseCIDR(cidr) | |
| } | |
| return func(r *http.Request) bool { | |
| // TODO: handle err | |
| host, _, _ := net.SplitHostPort(r.RemoteAddr) | |
| ip := net.ParseIP(host) | |
| for _, net := range nets { | |
| if net.Contains(ip) { | |
| return true | |
| } | |
| } | |
| return false | |
| } | |
| } | |
| func Method(methods ...string) RequestFilter { | |
| return func(r *http.Request) bool { | |
| for _, m := range methods { | |
| if r.Method == m { | |
| return true | |
| } | |
| } | |
| return false | |
| } | |
| } | |
| type Filters []RequestFilter | |
| // Combine creates a RequestFilter that is the conjunction | |
| // of all the RequestFilters in f. | |
| func (f Filters) Combine() RequestFilter { | |
| return func(r *http.Request) bool { | |
| for _, filter := range f { | |
| if !filter(r) { | |
| return false | |
| } | |
| } | |
| return true | |
| } | |
| } | |
| type Middleware func(http.Handler) http.Handler | |
| func Allow(f RequestFilter) Middleware { | |
| return func(h http.Handler) http.Handler { | |
| return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | |
| if f(r) { | |
| h.ServeHTTP(w, r) | |
| } else { | |
| // TODO | |
| w.WriteHeader(http.StatusForbidden) | |
| } | |
| }) | |
| } | |
| } | |
| func SetHeader(key, value string) Middleware { | |
| return func(h http.Handler) http.Handler { | |
| return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | |
| w.Header().Set(key, value) | |
| h.ServeHTTP(w, r) | |
| }) | |
| } | |
| } | |
| func Logging(h http.Handler) http.Handler { | |
| return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | |
| fmt.Printf("[%v] - %s %s\n", time.Now(), r.Method, r.RequestURI) | |
| h.ServeHTTP(w, r) | |
| }) | |
| } | |
| type Stack []Middleware | |
| // Apply returns an http.Handlerfunc that has had all of the | |
| // Middleware functions in s, if any, to f. | |
| func (s Stack) Apply(f http.Handler) http.Handler { | |
| g := f | |
| for _, middleware := range s { | |
| g = middleware(g) | |
| } | |
| return g | |
| } | |
| type Endpoint struct { | |
| Handler http.Handler | |
| Allow Filters | |
| Middleware Stack | |
| } | |
| // Builds the endpoint described by e, by applying | |
| // access restrictions and other middleware. | |
| func (e Endpoint) Build() http.Handler { | |
| allowFilter := e.Allow.Combine() | |
| restricted := Allow(allowFilter)(e.Handler) | |
| return e.Middleware.Apply(restricted) | |
| } | |
| type Routes map[string]Endpoint | |
| func (r Routes) Serve(addr string) error { | |
| mux := http.NewServeMux() | |
| for pattern, endpoint := range r { | |
| mux.Handle(pattern, endpoint.Build()) | |
| } | |
| return http.ListenAndServe(addr, mux) | |
| } | |
| func main() { | |
| routes := Routes{ | |
| "/hello": { | |
| Handler: http.HandlerFunc(hello), | |
| Middleware: Stack{ | |
| Logging, | |
| }, | |
| }, | |
| "/private": { | |
| Handler: http.HandlerFunc(hello), | |
| Allow: Filters{ | |
| CIDR("127.0.0.1/32"), | |
| PasswordHeader("opensesame"), | |
| }, | |
| Middleware: Stack{ | |
| Logging, | |
| }, | |
| }, | |
| "/test": { | |
| Handler: http.HandlerFunc(hello), | |
| Middleware: Stack{ | |
| Logging, | |
| SetHeader("X-Foo", "Bar"), | |
| }, | |
| }, | |
| } | |
| log.Fatal(routes.Serve(":1217")) | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment