package main import ( "bytes" "log" "net" "net/http" "strconv" "strings" ) type ResponseWriter struct { http.ResponseWriter StatueCode int } func (w *ResponseWriter) WriteHeader(statusCode int) { if w.StatueCode != 0 { return } w.StatueCode = statusCode w.ResponseWriter.WriteHeader(statusCode) } func (w *ResponseWriter) Write(body []byte) (int, error) { if w.StatueCode == 0 { w.WriteHeader(200) } return w.ResponseWriter.Write(body) } func MakeResponse(w http.ResponseWriter, status int, body []byte) (int, error) { w.WriteHeader(status) return w.Write(body) } func AbortError(w http.ResponseWriter, err interface{}) (int, error) { switch v := err.(type) { case int: w.WriteHeader(v) return w.Write([]byte(strconv.Itoa(v))) case string: w.WriteHeader(500) return w.Write([]byte(v)) case error: w.WriteHeader(500) return w.Write([]byte(v.Error())) default: w.WriteHeader(500) return w.Write([]byte(strconv.Itoa(500))) } } func Catch(rw *ResponseWriter, r *http.Request) { ex := recover() if ex != nil { AbortError(rw, r) log.Printf("%s %s %d %s %s\n", GetIP(r), r.Method, rw.StatueCode, r.URL, r.Header.Get("User-Agent")) } } func Middleware(next http.Handler) http.Handler { return http.HandlerFunc( func(w http.ResponseWriter, r *http.Request) { rw := &ResponseWriter{w, 0} defer Catch(rw, r) abort := false if flagAllow != "" { if !matchIPGlob(GetIP(r), flagAllow) { MakeResponse(rw, 403, []byte("permission denyed")) abort = true } } if !abort { next.ServeHTTP(rw, r) } if !strings.HasPrefix(r.URL.Path, "/public") { log.Printf("%s %s %d %s %s\n", GetIP(r), r.Method, rw.StatueCode, r.URL, r.Header.Get("User-Agent")) } }, ) } func GetIP(r *http.Request) string { ip := r.Header.Get("X-Real-Ip") if ip == "" { ips := r.Header.Get("X-Forwarded-For") ipArr := strings.Split(ips, ",") ip = strings.Trim(ipArr[len(ipArr)-1], " ") } if ip == "" { var err error ip, _, err = net.SplitHostPort(r.RemoteAddr) if err != nil { ip = r.RemoteAddr } } return ip } func Parse(w http.ResponseWriter, name string, data interface{}) error { buf := &bytes.Buffer{} err := tmpl.ExecuteTemplate(buf, "home", data) if err != nil { AbortError(w, err) return err } _, err = w.Write(buf.Bytes()) return err }