Skip to content

Instantly share code, notes, and snippets.

@carlmjohnson carlmjohnson/net-dsl.go
Last active Dec 19, 2016

Embed
What would you like to do?
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
You can’t perform that action at this time.