// gomod-index is a simple http redirector for go modules. // it listens on a specified address and port and handles go get // requests to a git repo. it is designed to be run behind a tls-terminating // reverse-proxy. // // usage: // // gomod-index [-l listen_addr] [-m module_root] [-g git_repo_root] package main import ( "flag" "html/template" "log" "net/http" "net/url" "strings" ) var ( lFlag = flag.String("l", ":8080", "address and port to listen") mFlag = flag.String("m", "aaoth.xyz", "module root path") gFlag = flag.String("g", "https://git.aaoth.xyz", "repository root path") ) const indexTmpl = `
redirecting to repository...
` var t = template.Must(template.New("index").Parse(indexTmpl)) type Data struct { Mod string Repo string } func indexHandler(w http.ResponseWriter, req *http.Request) { // XXX: do nested modules work? err := req.ParseForm() if err != nil { log.Println("parse form:", err) http.Error(w, "not found", http.StatusNotFound) return } if goGet, ok := req.Form["go-get"]; !ok || len(goGet) < 1 || goGet[0] != "1" { http.Error(w, "not found", http.StatusNotFound) return } path := strings.Trim(req.URL.EscapedPath(), "/") parts := strings.Split(path, "/") if len(parts) < 2 { http.Error(w, "not found", http.StatusNotFound) return } mod, err := url.JoinPath(*mFlag, parts[0], parts[1]) if err != nil { log.Println("ERROR: url join:", err) http.Error(w, "internal server error", http.StatusInternalServerError) return } repo, err := url.JoinPath(*gFlag, parts[0], parts[1]) if err != nil { log.Println("ERROR: url join:", err) http.Error(w, "internal server error", http.StatusInternalServerError) return } data := Data{mod, repo} err = t.ExecuteTemplate(w, "index", data) if err != nil { log.Println("url join:", err) http.Error(w, "internal server error", http.StatusInternalServerError) return } log.Println("go get", mod) } func main() { flag.Parse() mux := http.NewServeMux() mux.HandleFunc("/", indexHandler) log.Println("listening on", *lFlag) log.Fatal(http.ListenAndServe(*lFlag, mux)) }