package main import ( "log" "net/http" "net/url" "os" "regexp" "strings" ) //go:generate go run scripts/includebangs.go func main() { http.HandleFunc("/eval", func(w http.ResponseWriter, r *http.Request) { searchQuery := r.URL.Query().Get("query") searchEngine := r.URL.Query().Get("engine") if searchQuery == "" || searchEngine == "" { http.Error(w, "400 Bad Request", http.StatusBadRequest) return } searchQuery, searchEngine = evaluateBang(searchQuery, searchEngine) searchURL := buildSearchURL(searchEngine, searchQuery) http.Redirect(w, r, searchURL, http.StatusSeeOther) }) listenAddress := getSetting("LISTEN_ADDRESS", ":8081") log.Printf("Listening at %s", listenAddress) log.Fatalf("Failed to start http server: %v", http.ListenAndServe(listenAddress, nil)) } func getenv(name string, fallback string) (value string) { value = os.Getenv(name) if value == "" { return fallback } return } func getSetting(name, fallback string) (value string) { return getenv("BANG_EVALUATOR_"+name, fallback) } func buildSearchURL(template string, query string) (searchUrl string) { searchUrl = strings.Replace(template, "%s", url.QueryEscape(query), 1) searchUrl = strings.Replace(searchUrl, "%S", query, 1) return searchUrl } func parseBang(searchQuery string) (bang string, query string) { regexStartBang, _ := regexp.Compile("\\!(.*) (.*)") regexEndBang, _ := regexp.Compile("(.*) \\!(.*)") startBang := regexStartBang.FindSubmatch([]byte(searchQuery)) endBang := regexEndBang.FindSubmatch([]byte(searchQuery)) if len(endBang) == 3 { bang = strings.ToLower(string(endBang[2])) query = string(endBang[1]) return } else if len(startBang) == 3 { bang = strings.ToLower(string(startBang[1])) query = string(startBang[2]) return } else { return "", searchQuery } } func evaluateBang(searchQuery string, searchEngine string) (query string, engine string) { bang, query := parseBang(searchQuery) engine = getBang(bang) if bang == "" || engine == "" { return searchQuery, searchEngine } else { return query, engine } }