Evan Chen 2021-10-19 12:34:01 +08:00
parent 1dbb80d326
commit 1d7b8f5868
4 changed files with 161 additions and 73 deletions

26
api.go
View File

@ -11,7 +11,7 @@ import (
func ListFiles(w http.ResponseWriter, r *http.Request) { func ListFiles(w http.ResponseWriter, r *http.Request) {
data, err := json.Marshal(files) data, err := json.Marshal(files)
if err != nil { if err != nil {
HttpWriter(w, 500, err.Error()) AbortError(w, err)
return return
} }
w.Write(data) w.Write(data)
@ -21,12 +21,12 @@ func GetFile(w http.ResponseWriter, r *http.Request) {
name := r.URL.Query().Get("name") name := r.URL.Query().Get("name")
file, ok := files[name] file, ok := files[name]
if name == "" || !ok { if name == "" || !ok {
HttpWriter(w, 404, "file not found") MakeResponse(w, 404, []byte("file not found"))
return return
} }
data, err := file.Read() data, err := file.Read()
if err != nil { if err != nil {
HttpWriter(w, 500, err.Error()) AbortError(w, err)
return return
} }
response, err := json.Marshal(map[string]string{ response, err := json.Marshal(map[string]string{
@ -36,7 +36,7 @@ func GetFile(w http.ResponseWriter, r *http.Request) {
"data": string(data), "data": string(data),
}) })
if err != nil { if err != nil {
HttpWriter(w, 500, err.Error()) AbortError(w, err)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
@ -47,21 +47,21 @@ func PostFile(w http.ResponseWriter, r *http.Request) {
data, err := ioutil.ReadAll(r.Body) data, err := ioutil.ReadAll(r.Body)
r.Body.Close() r.Body.Close()
if err != nil { if err != nil {
HttpWriter(w, 500, err.Error()) AbortError(w, err)
return return
} }
f := configui.File{} f := configui.File{}
if err := json.Unmarshal(data, &f); err != nil { if err := json.Unmarshal(data, &f); err != nil {
HttpWriter(w, 500, err.Error()) AbortError(w, err)
return return
} }
file, ok := files[f.Alias] file, ok := files[f.Alias]
if !ok { if !ok {
HttpWriter(w, 404, "file not found") MakeResponse(w, 404, []byte("file not found"))
return return
} }
if err := file.Write([]byte(f.Data)); err != nil { if err := file.Write([]byte(f.Data)); err != nil {
HttpWriter(w, 500, err.Error()) AbortError(w, err)
return return
} }
w.Write([]byte("ok")) w.Write([]byte("ok"))
@ -71,12 +71,12 @@ func Apply(w http.ResponseWriter, r *http.Request) {
name := r.URL.Query().Get("name") name := r.URL.Query().Get("name")
file, ok := files[name] file, ok := files[name]
if name == "" || !ok { if name == "" || !ok {
HttpWriter(w, 404, "file not found") MakeResponse(w, 404, []byte("file not found"))
return return
} }
result, err := file.Do() result, err := file.Do()
if err != nil { if err != nil {
HttpWriter(w, 500, err.Error()) AbortError(w, err)
return return
} }
w.Write([]byte(result)) w.Write([]byte(result))
@ -95,12 +95,12 @@ func LoadConfig(w http.ResponseWriter, r *http.Request) {
data, err := ioutil.ReadAll(r.Body) data, err := ioutil.ReadAll(r.Body)
r.Body.Close() r.Body.Close()
if err != nil { if err != nil {
HttpWriter(w, 500, err.Error()) AbortError(w, err)
return return
} }
ftmp, err := configui.ReadConfig(string(data)) ftmp, err := configui.ReadConfig(string(data))
if err != nil { if err != nil {
HttpWriter(w, 500, err.Error()) AbortError(w, err)
return return
} }
files = configui.GetFileMap(ftmp) files = configui.GetFileMap(ftmp)
@ -110,7 +110,7 @@ func LoadConfig(w http.ResponseWriter, r *http.Request) {
func getConfigHandler(w http.ResponseWriter, r *http.Request) { func getConfigHandler(w http.ResponseWriter, r *http.Request) {
data, err := GetConfig() data, err := GetConfig()
if err != nil { if err != nil {
HttpWriter(w, 500, err.Error()) AbortError(w, err)
return return
} }
w.Write(data) w.Write(data)

108
netutil.go Normal file
View File

@ -0,0 +1,108 @@
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)
}
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
}

View File

@ -37,6 +37,6 @@ func setRoutes(mux *http.ServeMux) {
Lang: "json", Lang: "json",
} }
serve(w, "home", data) Parse(w, "home", data)
}) })
} }

92
util.go
View File

@ -2,40 +2,53 @@ package main
import ( import (
"archive/tar" "archive/tar"
"bytes"
"compress/gzip" "compress/gzip"
"io" "io"
"log"
"net"
"net/http"
"os" "os"
"strings" "strings"
) )
func Middleware(next http.Handler) http.Handler { func matchIPGlob(ip, pattern string) bool {
return http.HandlerFunc( parts := strings.Split(pattern, ".")
func(w http.ResponseWriter, r *http.Request) { seg := strings.Split(ip, ".")
defer func() { for i, part := range parts {
r := recover()
if r != nil { // normalize pattern to 3 digits
log.Println("panic", r) switch len(part) {
w.WriteHeader(500) case 1:
if part == "*" {
part = "***"
} else {
part = "00" + part
} }
}() case 2:
abort := false if strings.HasPrefix(part, "*") {
if flagAllow != "" { part = "*" + part
if GetIP(r) != flagAllow { } else if strings.HasSuffix(part, "*") {
HttpWriter(w, 403, "permission denyed") part = part + "*"
abort = true } else {
part = "0" + part
} }
} }
if !abort { // normalize ip to 3 digits
next.ServeHTTP(w, r) switch len(seg[i]) {
case 1:
seg[i] = "00" + seg[i]
case 2:
seg[i] = "0" + seg[i]
} }
log.Printf("%s %s %s %s\n", GetIP(r), r.Method, r.URL, r.Header.Get("User-Agent"))
}, for j := range part {
) if string(part[j]) == "*" {
continue
}
if part[j] != seg[i][j] {
return false
}
}
}
return true
} }
func bundle(buf io.Writer, paths []string, flat bool) error { func bundle(buf io.Writer, paths []string, flat bool) error {
@ -95,36 +108,3 @@ func bundle(buf io.Writer, paths []string, flat bool) error {
return nil return nil
} }
func HttpWriter(w http.ResponseWriter, status int, errStr string) {
w.WriteHeader(status)
w.Write([]byte(errStr))
}
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 serve(w http.ResponseWriter, name string, data interface{}) error {
buf := &bytes.Buffer{}
err := tmpl.ExecuteTemplate(buf, "home", data)
if err != nil {
HttpWriter(w, 500, err.Error())
return err
}
_, err = w.Write(buf.Bytes())
return err
}