diff --git a/go.mod b/go.mod index 7459203..01e6899 100644 --- a/go.mod +++ b/go.mod @@ -5,4 +5,5 @@ go 1.13 require ( github.com/gobuffalo/packr v1.30.1 github.com/golangci/golangci-lint v1.21.0 // indirect + github.com/satori/go.uuid v1.2.0 ) diff --git a/go.sum b/go.sum index faae700..a07060a 100644 --- a/go.sum +++ b/go.sum @@ -145,9 +145,11 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxv github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= @@ -196,6 +198,8 @@ github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rogpeppe/go-internal v1.3.0 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/securego/gosec v0.0.0-20191002120514-e680875ea14d h1:BzRvVq1EHuIjxpijCEKpAxzKUUMurOQ4sknehIATRh8= github.com/securego/gosec v0.0.0-20191002120514-e680875ea14d/go.mod h1:w5+eXa0mYznDkHaMCXA4XYffjlH+cy1oyKbfzJXa2Do= github.com/shirou/gopsutil v0.0.0-20190901111213-e4ec7b275ada/go.mod h1:WWnYX4lzhCH5h/3YBfyVA3VbLYjlMZZAQcW9ojMexNc= @@ -323,6 +327,7 @@ google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ij gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= diff --git a/internal/http.go b/internal/http.go index e6e4001..a4a18eb 100644 --- a/internal/http.go +++ b/internal/http.go @@ -1,11 +1,15 @@ package internal import ( + "context" "fmt" "log" "net/http" "os" "sync" + "time" + + uuid "github.com/satori/go.uuid" ) type Shortcuts map[string]string @@ -29,33 +33,43 @@ func NewServer(tp TemplateRenderer, shortcutStore *ShortcutStore, accessLogging mux.HandleFunc("/search", handlerFunc) mux.HandleFunc("/search_to_home", handlerFunc) - return mux + return accessLoggerMiddleware(mux) } -func searchHandler(scs *CommandHandler, shortcutStore *ShortcutStore, logAccess bool) http.HandlerFunc { +func accessLoggerMiddleware(middleware http.Handler) http.Handler { accessLogger := log.New(os.Stdout, "[access] ", log.Ldate|log.Lmicroseconds|log.Lshortfile) + return http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) { + requestId := uuid.NewV4() + setupHeaders(res.Header(), requestId.String()) + accessLogger.Printf("[%s] %s %s '%s'", requestId, getRemoteIP(req), req.Method, req.URL.String()) + middleware.ServeHTTP(res, req.WithContext(context.WithValue(req.Context(), "id", requestId.String()))) + }) +} +func searchHandler(scs *CommandHandler, shortcutStore *ShortcutStore, logAccess bool) http.HandlerFunc { + searchLogger := log.New(os.Stdout, "[search] ", log.Ldate|log.Lmicroseconds|log.Lshortfile) return func(res http.ResponseWriter, req *http.Request) { + requestId := req.Context().Value("id") v := req.URL.Query() commandString := v.Get("q") action, err := scs.Handle(commandString) if err != nil { if logAccess { - accessLogger.Printf("'%s' -> got error: '%s'", commandString, err.Error()) + searchLogger.Printf("[%s] '%s' -> got error: '%s'", requestId, commandString, err.Error()) } - http.Redirect(res, req, fmt.Sprintf("https://duckduckgo.com?q=%s", commandString), http.StatusFound) + http.Redirect(res, req, fmt.Sprintf("https://duckduckgo.com?q=%s", commandString), http.StatusFound) return } - accessLogger.Printf("'%s' %s -> 302 %s", commandString, action.Action, action.Location) - + searchLogger.Printf("[%s] '%s' %s -> 302 %s", requestId, commandString, action.Action, action.Location) if action.Action != "lookup" { if err := shortcutStore.SaveShortcuts(scs.Shortcuts, nil); err != nil { if logAccess { - accessLogger.Printf("'%s' %s -> could not save shortcuts database file: %v", commandString, action.Action, err) + searchLogger.Printf("[%s] '%s' %s -> could not save shortcuts database file: %v", requestId, commandString, action.Action, err) } + http.Error(res, err.Error(), http.StatusInternalServerError) return @@ -65,3 +79,24 @@ func searchHandler(scs *CommandHandler, shortcutStore *ShortcutStore, logAccess http.Redirect(res, req, action.Location, http.StatusFound) } } + +func setupHeaders(headers http.Header, requestId string) { + headers.Set("X-RiffRaff-Request-Id", requestId) + headers.Set("Server", "Riff Raff") + headers.Set("Cache-Control", fmt.Sprintf("public, max-age=%s", time.Hour/time.Second)) +} + +func getRemoteIP(req *http.Request) string { + ip := req.RemoteAddr + h := req.Header + + if realIpHeader := h.Get("X-Real-Ip"); realIpHeader != "" { + ip = realIpHeader + } + + if forwardIpHeader := h.Get("X-Forwarded-For"); forwardIpHeader != "" { + ip = forwardIpHeader + } + + return ip +}