|
|
|
@ -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
|
|
|
|
|
}
|
|
|
|
|