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

98
util.go
View File

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