package httpreverse import ( "b612.me/staros/sysconf" "errors" "io/ioutil" "net/http" "net/http/httputil" "net/url" "strings" "sync" ) type ReverseConfig struct { Name string Addr string ReverseURL map[string]*url.URL Port int UsingSSL bool Key string Cert string Host string SkipSSLVerify bool InHeader [][2]string OutHeader [][2]string Cookie [][3]string //[3]string should contains path::key::value ReplaceList [][2]string ReplaceOnce bool proxy map[string]*httputil.ReverseProxy XForwardMode int //0=off 1=useremote 2=add httpmux http.ServeMux httpserver http.Server basicAuthUser string basicAuthPwd string protectAuthPage []string blackip map[string]int whiteip map[string]int warningpage string warnpagedata []byte } type HttpReverseServer struct { Config []*ReverseConfig } func Parse(path string) (HttpReverseServer, error) { var res HttpReverseServer ini := sysconf.NewIni() err := ini.ParseFromFile(path) if err != nil { return res, err } for _, v := range ini.Data { var ins = ReverseConfig{ Name: v.Name, Host: v.Get("host"), Addr: v.Get("addr"), Port: v.Int("port"), UsingSSL: v.Bool("enablessl"), Key: v.Get("key"), Cert: v.Get("cert"), ReplaceOnce: v.Bool("replaceonce"), XForwardMode: v.Int("xforwardmode"), basicAuthUser: v.Get("authuser"), basicAuthPwd: v.Get("authpasswd"), warningpage: v.Get("warnpage"), } if ins.warningpage != "" { data, err := ioutil.ReadFile(ins.warningpage) if err != nil { return res, err } ins.warnpagedata = data } ins.proxy = make(map[string]*httputil.ReverseProxy) ins.ReverseURL = make(map[string]*url.URL) for _, reverse := range v.GetAll("reverse") { kv := strings.SplitN(reverse, "::", 2) if len(kv) != 2 { return res, errors.New("reverse settings not correct:" + reverse) } ins.ReverseURL[strings.TrimSpace(kv[0])], err = url.Parse(strings.TrimSpace(kv[1])) if err != nil { return res, err } } for _, header := range v.GetAll("inheader") { kv := strings.SplitN(header, "::", 2) if len(kv) != 2 { return res, errors.New("header settings not correct:" + header) } ins.InHeader = append(ins.InHeader, [2]string{strings.TrimSpace(kv[0]), strings.TrimSpace(kv[1])}) } for _, authpage := range v.GetAll("authpage") { ins.protectAuthPage = append(ins.protectAuthPage, authpage) } ins.blackip = make(map[string]int) for _, blackip := range v.GetAll("blackip") { ip, cidr, err := IPCIDR(blackip) if err != nil { return res, err } ins.blackip[ip] = cidr } ins.whiteip = make(map[string]int) for _, whiteip := range v.GetAll("whiteip") { ip, cidr, err := IPCIDR(whiteip) if err != nil { return res, err } ins.whiteip[ip] = cidr } for _, header := range v.GetAll("outheader") { kv := strings.SplitN(header, "::", 2) if len(kv) != 2 { return res, errors.New("header settings not correct:" + header) } ins.OutHeader = append(ins.OutHeader, [2]string{strings.TrimSpace(kv[0]), strings.TrimSpace(kv[1])}) } for _, cookie := range v.GetAll("cookie") { kv := strings.SplitN(cookie, "::", 3) if len(kv) != 3 { return res, errors.New("cookie settings not correct:" + cookie) } ins.Cookie = append(ins.Cookie, [3]string{strings.TrimSpace(kv[0]), strings.TrimSpace(kv[1]), strings.TrimSpace(kv[2])}) } for _, replace := range v.GetAll("replace") { kv := strings.SplitN(replace, "::", 2) if len(kv) != 2 { return res, errors.New("replace settings not correct:" + replace) } ins.ReplaceList = append(ins.ReplaceList, [2]string{strings.TrimSpace(kv[0]), strings.TrimSpace(kv[1])}) } res.Config = append(res.Config, &ins) } return res, nil } func (h *HttpReverseServer) Run() error { var wg sync.WaitGroup var mu sync.Mutex var haveErr string for _, v := range h.Config { wg.Add(1) go func(v *ReverseConfig) { defer wg.Done() err := v.Run() if err != nil { mu.Lock() haveErr += err.Error() + "\n" mu.Unlock() } }(v) } wg.Wait() if haveErr != "" { return errors.New(haveErr) } return nil } func (h *HttpReverseServer) Close() error { var haveErr string for _, v := range h.Config { err := v.Close() if err != nil { haveErr += err.Error() + "\n" } } if haveErr != "" { return errors.New(haveErr) } return nil }