package httpserver import ( "b612.me/apps/b612/utils" "b612.me/apps/b612/version" "b612.me/starcrypto" "b612.me/starlog" "b612.me/starnet" "b612.me/staros" "context" "crypto/tls" "crypto/x509" _ "embed" "encoding/base64" "encoding/json" "errors" "fmt" "html/template" "io" "io/ioutil" "math" "net" "net/http" "os" "path/filepath" "strconv" "strings" "time" ) var ver = version.Version type HttpServerCfgs func(cfg *HttpServerCfg) type HttpServerCfg struct { basicAuthUser string basicAuthPwd string EnvPath []string SubFolder []string uploadFolder string logpath string indexFile string cert string key string allowHttpWithHttps bool autoGenCert bool addr string port string page404 string page403 string page401 string protectAuthPage []string disableMIME bool ctx context.Context hooks []ServerHook httpDebug bool noListPath []string listPwd map[string]string listSameForFile bool // speed limit means xx bytes/s speedlimit uint64 background string mobildBackground string blackpath Router whitepath Router blacklist []string whitelist []string envPath Router } type ServerHook struct { MatchType []string `json:"match_type"` Url string `json:"url"` Timeout int `json:"timeout"` MaxHookLength int `json:"max_hook_length"` } type HttpServer struct { HttpServerCfg } //go:embed bootstrap.css var bootStrap []byte //go:embed jquery.js var jquery []byte //go:embed upload.html var uploadPage []byte //go:embed template.html var templateHtml []byte func WithHooks(hooks []ServerHook) HttpServerCfgs { return func(cfg *HttpServerCfg) { for k, v := range hooks { if v.MaxHookLength == 0 { hooks[k].MaxHookLength = 1024 * 1024 } } cfg.hooks = hooks } } func WithTLSCert(cert, key string) HttpServerCfgs { return func(cfg *HttpServerCfg) { cfg.key = key cfg.cert = cert } } func WithUploadFolder(path string) HttpServerCfgs { return func(cfg *HttpServerCfg) { cfg.uploadFolder = path } } func NewHttpServer(addr, port, path string, opts ...HttpServerCfgs) *HttpServer { var server = HttpServer{ HttpServerCfg: HttpServerCfg{ addr: addr, port: port, EnvPath: []string{path}, }, } for _, opt := range opts { opt(&server.HttpServerCfg) } return &server } func (h *HttpServer) Run(ctx context.Context) error { h.ctx = ctx server := http.Server{ Addr: h.addr + ":" + h.port, Handler: h, ConnContext: func(ctx context.Context, c net.Conn) context.Context { switch conn := c.(type) { case *tls.Conn: return context.WithValue(ctx, "istls", true) case *starnet.Conn: return context.WithValue(ctx, "istls", conn) } return context.WithValue(ctx, "istls", false) }, } go func() { select { case <-h.ctx.Done(): ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) defer cancel() server.Shutdown(ctx) } }() if h.logpath != "" && starlog.GetWriter() == nil { starlog.SetLogFile(h.logpath, starlog.Std, true) } netcards, err := net.Interfaces() if err == nil { for _, v := range netcards { if strings.Contains(v.Flags.String(), "up") { addrs, err := v.Addrs() if err == nil { for _, ip := range addrs { starlog.Cyan("Name:%s\tIP:%s\n", v.Name, ip) } } } } } for idx, val := range h.EnvPath { h.EnvPath[idx], err = filepath.Abs(val) if len(h.SubFolder) > 0 { h.envPath.AddLeaf(h.SubFolder[idx], h.EnvPath[idx]) } } if len(h.EnvPath) > 1 && len(h.EnvPath) != len(h.SubFolder) { return errors.New("EnvPath and SubFolder length not match") } if err != nil { starlog.Errorln("Failed to get abs path of", h.EnvPath) return err } uconn, err := net.Dial("udp", "106.55.44.79:80") if err == nil { schema := "http://" if h.cert != "" || h.autoGenCert { schema = "https://" } starlog.Infof("Visit: %s%s:%s\n", schema, uconn.LocalAddr().(*net.UDPAddr).IP.String(), h.port) uconn.Close() } starlog.Infoln("Listening on " + h.addr + ":" + h.port) if h.cert == "" && !h.autoGenCert { if err := server.ListenAndServe(); err != http.ErrServerClosed { return err } return nil } if !h.allowHttpWithHttps && !h.autoGenCert { if err := server.ListenAndServeTLS(h.cert, h.key); err != http.ErrServerClosed { return err } return nil } var lis net.Listener if !h.autoGenCert { lis, err = starnet.ListenTLS("tcp", h.addr+":"+h.port, h.cert, h.key, h.allowHttpWithHttps) if err != nil { return err } } else { lis, err = starnet.ListenTLSWithConfig("tcp", h.addr+":"+h.port, &tls.Config{}, autoGenCert, h.allowHttpWithHttps) if err != nil { return err } } defer lis.Close() if err := server.Serve(lis); err != http.ErrServerClosed { return err } return nil } var certCache = make(map[string]tls.Certificate) var toolCa *x509.Certificate var toolCaKey any func autoGenCert(hostname string) *tls.Config { if cert, ok := certCache[hostname]; ok { return &tls.Config{Certificates: []tls.Certificate{cert}} } if toolCa == nil { toolCa, toolCaKey = utils.ToolCert("") } cert, err := utils.GenerateTlsCert(utils.GenerateCertParams{ Country: "CN", Organization: "B612 HTTP SERVER", OrganizationUnit: "cert@b612.me", CommonName: hostname, Dns: []string{hostname}, KeyUsage: int(x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment | x509.KeyUsageCertSign), ExtendedKeyUsage: []int{ int(x509.ExtKeyUsageServerAuth), int(x509.ExtKeyUsageClientAuth), }, IsCA: false, StartDate: time.Now().Add(-24 * time.Hour), EndDate: time.Now().AddDate(1, 0, 0), Type: "RSA", Bits: 2048, CA: toolCa, CAPriv: toolCaKey, }) if err != nil { return nil } certCache[hostname] = cert return &tls.Config{Certificates: []tls.Certificate{cert}} } func (h *HttpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { h.Listen(w, r) } func (h *HttpServer) Page404(w http.ResponseWriter) { w.WriteHeader(404) if h.page404 != "" { data, err := os.ReadFile(h.page404) if err == nil { w.Write(data) return } } w.Write([]byte(`B612 Http Server

404 NOT FOUND


`)) } func (h *HttpServer) Page403(w http.ResponseWriter) { w.WriteHeader(403) if h.page403 != "" { data, err := os.ReadFile(h.page403) if err == nil { w.Write(data) return } } w.Write([]byte(` 403 Forbidden

403 Forbidden


B612 HTTP SERVER
`)) } func (h *HttpServer) Page401(w http.ResponseWriter) { w.WriteHeader(401) if h.page401 != "" { data, err := os.ReadFile(h.page401) if err == nil { w.Write(data) return } } w.Write([]byte(` 401 Authorization Required

401 Authorization Required


B612 HTTP SERVER
`)) } func (h *HttpServer) GiveBasicAuth(w http.ResponseWriter) { w.Header().Set("WWW-Authenticate", ` Basic realm="Please Enter Passwd"`) h.Page401(w) } func (h *HttpServer) BasicAuth(log *starlog.StarLogger, w http.ResponseWriter, r *http.Request) bool { if h.basicAuthPwd != "" { if len(h.protectAuthPage) != 0 { for _, v := range h.protectAuthPage { if !(strings.Index(r.URL.Path, v) == 0 || strings.Contains(r.URL.RawQuery, v)) { return true } else { break } } } authHeader := strings.TrimSpace(r.Header.Get("Authorization")) if len(authHeader) == 0 { log.Noticeln("No Authed! Get Path is", r.URL.Path, r.RemoteAddr) h.GiveBasicAuth(w) return false } else { userAuth := base64.StdEncoding.EncodeToString([]byte(h.basicAuthUser + ":" + h.basicAuthPwd)) authStr := strings.Split(authHeader, " ") if strings.TrimSpace(authStr[1]) != userAuth || strings.ToLower(strings.TrimSpace(authStr[0])) != "basic" { log.Noticeln("Auth Failed! Get Path is", r.URL.Path, r.RemoteAddr, "pwd enter is", authHeader) h.GiveBasicAuth(w) return false } log.Infof("Path %s Authoried by %s:%s\n", r.URL.Path, r.RemoteAddr, authHeader) } } return true } func (h *HttpServer) SetUpload(w http.ResponseWriter, r *http.Request, path string) bool { if h.uploadFolder != "" { if r.URL.Query().Get("bootstrap") == "true" { w.Header().Set("Content-Type", "text/css") w.Write(bootStrap) return true } if r.URL.Query().Get("jquery") == "true" { w.Header().Set("Content-Type", "application/javascript") w.Write(jquery) return true } if len(r.URL.Query()["upload"]) != 0 { w.Header().Set("Content-Type", "text/html") w.Write(uploadPage) return true } } return false } func (h *HttpServer) debugMode(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/html") w.WriteHeader(200) html := `B612 Http Server

Debug Mode


%s` resp := "

Url

" resp += "

" + r.Method + " " + r.URL.Path + "

" resp += "

query: " + r.URL.RawQuery + "

" resp += "

fragment: " + r.URL.Fragment + "

" resp += "

FullUrl: " + r.URL.String() + "

" resp += "

Query

" for k, v := range r.URL.Query() { resp += fmt.Sprintf("

%s:%s

", k, v) } resp += "

Header

" for key, val := range r.Header { for _, v := range val { resp += fmt.Sprintf("

%s:%s

", key, v) } } resp += "

Cookie

" for _, c := range r.Cookies() { resp += fmt.Sprintf("

%s:%s

", c.Name, c.Value) } resp += "

RemoteAddr

" resp += "

" + r.RemoteAddr + "

" resp += "

Proto

" resp += "

" + r.Proto + "

" w.Write([]byte(fmt.Sprintf(html, resp))) } func (h *HttpServer) PermissionCheck(isTls string, w http.ResponseWriter, r *http.Request) bool { checkPath := r.URL.Path if strings.HasSuffix(checkPath, "/") && checkPath != "/" { checkPath = strings.TrimSuffix(checkPath, "/") } if h.blackpath.Leaf != nil { bp := h.blackpath.NearestLeafWithVal(checkPath) if bp != nil { if ppr, ok := bp.Val.(bool); ok { if ppr || (!ppr && bp.FullPath == checkPath) { starlog.Errorf(isTls+"%s %s From %s %s path is in black path, reject request \n", r.Method, checkPath, r.RemoteAddr, r.Header.Get("User-Agent")) h.Page403(w) return false } } } } if h.whitepath.Leaf != nil { bp := h.whitepath.NearestLeafWithVal(checkPath) if bp == nil { starlog.Errorf(isTls+"%s %s From %s %s path is not in white path, reject request \n", r.Method, checkPath, r.RemoteAddr, r.Header.Get("User-Agent")) h.Page403(w) return false } if ppr, ok := bp.Val.(bool); !ok { starlog.Errorf(isTls+"%s %s From %s %s path is not in white path, reject request \n", r.Method, checkPath, r.RemoteAddr, r.Header.Get("User-Agent")) h.Page403(w) return false } else { if !ppr && bp.FullPath != checkPath { starlog.Errorf(isTls+"%s %s From %s %s path is not in white path, reject request \n", r.Method, checkPath, r.RemoteAddr, r.Header.Get("User-Agent")) h.Page403(w) return false } } } return true } func (h *HttpServer) getEnvPath(r *http.Request) (string, string) { if len(h.EnvPath) == 1 { return "/", h.EnvPath[0] } checkPath := r.URL.Path if strings.HasSuffix(checkPath, "/") && checkPath != "/" { checkPath = strings.TrimSuffix(checkPath, "/") } if h.envPath.Leaf != nil { leaf := h.envPath.NearestLeafWithVal(checkPath) if leaf != nil && leaf.Val != nil { if envPath, ok := leaf.Val.(string); ok { return leaf.FullPath, envPath } } } return "", "" } func (h *HttpServer) getStrEnvPath(r string) (string, string) { if len(h.EnvPath) == 1 { return "/", h.EnvPath[0] } checkPath := r if strings.HasSuffix(checkPath, "/") && checkPath != "/" { checkPath = strings.TrimSuffix(checkPath, "/") } if h.envPath.Leaf != nil { leaf := h.envPath.NearestLeafWithVal(checkPath) if leaf != nil && leaf.Val != nil { if envPath, ok := leaf.Val.(string); ok { return leaf.FullPath, envPath } } } return "", "" } func (h *HttpServer) Listen(w http.ResponseWriter, r *http.Request) { log := starlog.Std.NewFlag() log.SetShowFuncName(false) log.SetShowOriginFile(false) w.Header().Set("X-Powered-By", "B612.ME") w.Header().Set("Server", "B612/"+ver) if !h.BasicAuth(log, w, r) { return } isTls := h.isTlsStr(r) if !h.PermissionCheck(isTls, w, r) { return } path := r.URL.Path ua := r.Header.Get("User-Agent") if h.httpDebug { log.Infof("debug mode:%s %s From %s %s\n", r.Method, path, r.RemoteAddr, ua) h.debugMode(w, r) return } if h.uploadFolder != "" && path == "/recv" && len(r.URL.Query()["upload"]) != 0 { h.uploadFile(w, r) return } if h.SetUpload(w, r, path) { return } prefix, envPath := h.getEnvPath(r) if envPath == "" { log.Errorf(isTls+"%s %s From %s %s No EnvPath Found\n", r.Method, path, r.RemoteAddr, ua) h.Page404(w) return } path = "/" + strings.TrimPrefix(path, prefix) fullpath := filepath.Clean(filepath.Join(envPath, path)) { //security check if fullpath != envPath && !strings.HasPrefix(fullpath, envPath) { log.Warningf("Invalid Path %s IP:%s Fullpath:%s\n", path, r.RemoteAddr, fullpath) h.Page403(w) return } } if h.indexFile != "" && staros.IsFolder(fullpath) { if staros.Exists(filepath.Join(fullpath, h.indexFile)) { fullpath = filepath.Join(fullpath, h.indexFile) path = filepath.Join(path, h.indexFile) } } now := time.Now() switch r.Method { case "OPTIONS", "HEAD": err := h.BuildHeader(w, r, fullpath) if err != nil { log.Warningf(isTls+"%s %s From %s %s %.2fs %v\n", r.Method, path, r.RemoteAddr, ua, time.Since(now).Seconds(), err) } else { log.Infof(isTls+"%s %s From %s %s %.2fs \n", r.Method, path, r.RemoteAddr, ua, time.Since(now).Seconds()) } case "GET": err := h.BuildHeader(w, r, fullpath) if err != nil { log.Warningf(isTls+"GET Header Build Failed Path:%s IP:%s Err:%v\n", path, r.RemoteAddr, err) } err = h.ResponseGet(log, w, r, fullpath) if err != nil { log.Warningf(isTls+"%s %s From %s %s %.2fs %v\n", r.Method, path, r.RemoteAddr, ua, time.Since(now).Seconds(), err) return } log.Infof(isTls+"%s %s From %s %s %.2fs\n", r.Method, path, r.RemoteAddr, ua, time.Since(now).Seconds()) default: log.Errorf(isTls+"Invalid %s %s From %s %s %.2fs\n", r.Method, path, r.RemoteAddr, ua, time.Since(now).Seconds()) return } } func (h *HttpServer) CalcRange(r *http.Request) (int64, int64) { var rangeStart, rangeEnd int64 = -1, -1 ranges := r.Header.Get("Range") if ranges == "" { return rangeStart, rangeEnd } if !strings.Contains(ranges, "bytes=") { return rangeStart, rangeEnd } ranges = strings.TrimPrefix(ranges, "bytes=") data := strings.Split(ranges, "-") if len(data) == 0 { return rangeStart, rangeEnd } rangeStart, _ = strconv.ParseInt(data[0], 10, 64) if len(data) > 1 { rangeEnd, _ = strconv.ParseInt(data[1], 10, 64) } if rangeEnd == 0 { rangeEnd = -1 } return rangeStart, rangeEnd } func (h *HttpServer) BuildHeader(w http.ResponseWriter, r *http.Request, fullpath string) error { if r.Method == "OPTIONS" { w.Header().Set("Allow", "OPTIONS,GET,HEAD") w.Header().Set("Content-Length", "0") } w.Header().Set("Date", strings.ReplaceAll(time.Now().UTC().Format("Mon, 2 Jan 2006 15:04:05 MST"), "UTC", "GMT")) if staros.IsFolder(fullpath) { return nil } mime := h.MIME(fullpath) if h.disableMIME || mime == "" { w.Header().Set("Content-Type", "application/download") w.Header().Set("Content-Disposition", "attachment;filename="+filepath.Base(fullpath)) w.Header().Set("Content-Transfer-Encoding", "binary") } else { w.Header().Set("Content-Type", mime) } if staros.Exists(fullpath) { finfo, err := os.Stat(fullpath) if err != nil { w.WriteHeader(502) w.Write([]byte("Failed to Read " + fullpath + ",reason is " + err.Error())) return err } w.Header().Set("Accept-Ranges", "bytes") w.Header().Set("ETag", starcrypto.Md5Str([]byte(finfo.ModTime().String()))) w.Header().Set("Last-Modified", strings.ReplaceAll(finfo.ModTime().UTC().Format("Mon, 2 Jan 2006 15:04:05 MST"), "UTC", "GMT")) if r.Method != "OPTIONS" { if _, ok := h.willHook(fullpath); ok { return nil } start, end := h.CalcRange(r) if start != -1 { if end == -1 { w.Header().Set("Content-Length", strconv.FormatInt(finfo.Size()-start, 10)) w.Header().Set("Content-Range", `bytes `+strconv.FormatInt(start, 10)+"-"+strconv.FormatInt(finfo.Size()-1, 10)+"/"+strconv.FormatInt(finfo.Size(), 10)) //w.Header().Set("Content-Length", strconv.FormatInt(fpinfo.Size()-rangeStart, 10)) } else { w.Header().Set("Content-Length", strconv.FormatInt(end-start+1, 10)) w.Header().Set("Content-Range", `bytes `+strconv.FormatInt(start, 10)+"-"+strconv.FormatInt(end, 10)+"/"+strconv.FormatInt(finfo.Size(), 10)) //w.Header().Set("Content-Length", strconv.FormatInt(1+rangeEnd-rangeStart, 10)) } } else { w.Header().Set("Content-Length", strconv.FormatInt(finfo.Size(), 10)) } } } return nil } func (h *HttpServer) willHook(fullpath string) (ServerHook, bool) { finfo, err := os.Stat(fullpath) if err != nil { return ServerHook{}, false } if finfo.Size() < 1024*1024*10 && len(h.hooks) > 0 { ext := h.GetExt(fullpath) for _, hk := range h.hooks { for _, e := range hk.MatchType { if e == ext { return hk, true } } } } return ServerHook{}, false } func (h *HttpServer) ResponseGet(log *starlog.StarLogger, w http.ResponseWriter, r *http.Request, fullpath string) error { if staros.IsFolder(fullpath) { if len(h.listPwd) != 0 { for k, v := range h.listPwd { if strings.HasPrefix(r.URL.Path, k) { if r.URL.Query().Get("list") == v { return h.getFolder(log, w, r, fullpath) } } } } if len(h.noListPath) != 0 { for _, v := range h.noListPath { if strings.HasPrefix(r.URL.Path, v) { h.Page403(w) return nil } } } return h.getFolder(log, w, r, fullpath) } if !h.listSameForFile { return h.getFile(log, w, r, fullpath) } if len(h.listPwd) != 0 { for k, v := range h.listPwd { if strings.HasPrefix(r.URL.Path, k) { if r.URL.Query().Get("list") == v { return h.getFile(log, w, r, fullpath) } } } } if len(h.noListPath) != 0 { for _, v := range h.noListPath { if strings.HasPrefix(r.URL.Path, v) { h.Page403(w) return nil } } } return h.getFile(log, w, r, fullpath) } type FileData struct { Attr string `json:"attr"` Name string `json:"name"` Modified string `json:"modified"` Size int64 `json:"size"` Type string `json:"type"` } func (h *HttpServer) getFolder(log *starlog.StarLogger, w http.ResponseWriter, r *http.Request, fullpath string) error { dir, err := ioutil.ReadDir(fullpath) if err != nil { log.Errorf("Read Folder %s failed:%v\n", fullpath, err) w.WriteHeader(403) if r.Method == "HEAD" { return err } w.Write([]byte("

Cannot Access!

")) } if r.Method != "GET" { return nil } var upload string if h.uploadFolder != "" { prefix := r.URL.Path if prefix == "/" { prefix = "" } upload = `Upload Web Page Is Openned!` } attr := r.URL.Query().Get("list") if attr != "" { attr = "/?list=" + attr } var fdatas = make([]FileData, 0, len(dir)+1) if r.URL.Path != "/" { p := r.URL.Path if p[len(p)-1:] != "/" { p += "/" } fdatas = append(fdatas, FileData{ Attr: p + ".." + attr, Name: "..", Modified: "-", Size: -1, Type: "上层文件夹", }) } if r.URL.Path == "/" { r.URL.Path = "" } else if r.URL.Path[len(r.URL.Path)-1:] == "/" { r.URL.Path = r.URL.Path[0 : len(r.URL.Path)-1] } for _, v := range dir { if v.Name() != "." || v.Name() != ".." { if !v.IsDir() { fdatas = append(fdatas, FileData{ Name: v.Name(), Attr: r.URL.Path + "/" + v.Name(), Modified: v.ModTime().Format("2006-01-02 15:04:05"), Size: v.Size(), Type: h.FileType(v.Name()), }) } else { fdatas = append(fdatas, FileData{ Name: v.Name() + "/", Attr: r.URL.Path + "/" + v.Name() + attr, Modified: v.ModTime().Format("2006-01-02 15:04:05"), Size: -1, Type: "文件夹", }) } } } tmpt, err := template.New("index").Parse(string(templateHtml)) if err != nil { log.Errorf("Parse Template Error:%v\n", err) w.WriteHeader(502) w.Write([]byte(`B612 Http Server

502 SERVER ERROR


`)) return err } jData, err := json.Marshal(fdatas) if err != nil { log.Errorf("Json Marshal Failed:%v\n", err) w.WriteHeader(502) w.Write([]byte(`B612 Http Server

502 SERVER ERROR


`)) return err } if r.URL.Path == "" { r.URL.Path = "/" } var bk, mbk string if h.background != "" { bk = `background: url('` + h.background + `') no-repeat center center fixed;` } if h.mobildBackground != "" { mbk = `background: url('` + h.mobildBackground + `') no-repeat center center fixed;` } if h.mobildBackground == "" && h.background != "" { mbk = bk } err = tmpt.Execute(w, map[string]interface{}{ "IdxTitle": r.URL.Path, "Version": ver, "Idx": "Index of " + r.URL.Path, "Upload": template.HTML(upload), "Data": template.JS(jData), "Photo": template.CSS(bk), "MobilePhoto": template.CSS(mbk), }) if err != nil { log.Errorf("Template Execute Failed:%v\n", err) w.WriteHeader(502) w.Write([]byte(`B612 Http Server

502 SERVER ERROR


`)) return err } return nil } func (h *HttpServer) getSleepTime() time.Duration { if h.speedlimit == 0 { return 0 } return time.Nanosecond * time.Duration(16384*1000*1000*1000/h.speedlimit) / 2 } func (h *HttpServer) isTls(r *http.Request) bool { if r.Context().Value("istls") != nil { if v, ok := r.Context().Value("istls").(bool); ok { if v { return true } } if v, ok := r.Context().Value("istls").(*starnet.Conn); ok { return v.IsTLS() } } return false } func (h *HttpServer) isTlsStr(r *http.Request) string { if h.isTls(r) { return "TLS " } return "PLN " } func (h *HttpServer) getFile(log *starlog.StarLogger, w http.ResponseWriter, r *http.Request, fullpath string) error { if !staros.Exists(fullpath) { h.Page404(w) return errors.New("File Not Found! 404 ERROR") } isTls := h.isTlsStr(r) var lastCount int64 var lastDate time.Time = time.Now() var currentCount int64 speedControl := func(count int) { if h.speedlimit == 0 { return } currentCount += int64(count) for { if time.Since(lastDate) < time.Second { if uint64(currentCount-lastCount) > h.speedlimit { time.Sleep(h.getSleepTime()) } else { break } } else { lastDate = time.Now() lastCount = currentCount break } } } //starlog.Debugln(r.Header) startRange, endRange := h.CalcRange(r) fp, err := os.Open(fullpath) if err != nil { log.Errorf("Failed to open file %s,reason:%v\n", r.URL.Path, err) w.WriteHeader(502) w.Write([]byte(`B612 Http Server

502 SERVER ERROR


`)) return err } defer fp.Close() var transferData int defer func() { if transferData != 0 { var tani string tani = fmt.Sprintf("%v Byte", transferData) if f64 := float64(transferData) / 1024; f64 > 1 { tani = fmt.Sprintf("%v KiB", f64) if f64 = float64(f64) / 1024; f64 > 1 { tani = fmt.Sprintf("%v MiB", f64) if f64 = float64(f64) / 1024; f64 > 1 { tani = fmt.Sprintf("%v GiB", f64) } } } log.Infof(isTls+"Tranfered File %s %d bytes (%s) to remote %v\n", r.URL.Path, transferData, tani, r.RemoteAddr) } }() if startRange == -1 { hook, needCurl := h.willHook(fullpath) if !needCurl { w.WriteHeader(200) for { buf := make([]byte, 16384) n, err := fp.Read(buf) if n != 0 { speedControl(n) ns, err := w.Write(buf[:n]) transferData += ns if err != nil { log.Errorf(isTls+"Transfer File %s to Remote Failed:%v\n", fullpath, err) return err } } if err != nil { if err == io.EOF { break } log.Errorf("Read File %s Failed:%v\n", fullpath, err) return err } } return nil } data, err := os.ReadFile(fullpath) if err != nil { w.WriteHeader(502) w.Write([]byte(`B612 Http Server

502 SERVER ERROR


`)) log.Errorf("Read File %s Failed:%v\n", fullpath, err) return err } b64 := base64.StdEncoding.EncodeToString(data) req, err := starnet.Curl(starnet.NewSimpleRequest(hook.Url, "POST", starnet.WithBytes(starnet.BuildPostForm(map[string]string{ "data": b64, "ip": r.RemoteAddr, })), starnet.WithTimeout(time.Duration(hook.Timeout)*time.Millisecond))) if err != nil { w.Header().Set("Content-Length", strconv.Itoa(len(data))) w.WriteHeader(200) ns, err := w.Write(data) transferData += ns if err != nil { log.Errorf(isTls+"Transfer File %s to Remote Failed:%v\n", fullpath, err) return err } return nil } recvData := req.Body().Bytes() w.WriteHeader(200) w.Header().Set("Content-Length", strconv.Itoa(len(recvData))) ns, err := w.Write(recvData) transferData += ns if err != nil { log.Errorf(isTls+"Transfer File %s to Remote Failed:%v\n", fullpath, err) return err } return nil } log.Debugf(isTls+"206 transfer mode for %v %v start %v end %v\n", r.URL.Path, r.RemoteAddr, startRange, endRange) w.WriteHeader(206) fp.Seek(int64(startRange), 0) count := startRange for { buf := make([]byte, 16384) n, err := fp.Read(buf) if err != nil { if err == io.EOF { break } log.Errorf(isTls+"Read File %s Failed:%v\n", r.URL.Path, err) return err } speedControl(n) if endRange == -1 { ns, err := w.Write(buf[:n]) transferData += ns if err != nil { log.Errorf(isTls+"Transfer File %s to Remote Failed:%v\n", r.URL.Path, err) return err } } else { if count > endRange { break } writeNum := n if count+int64(n) > endRange { writeNum = int(endRange - count + 1) } ns, err := w.Write(buf[0:writeNum]) if err != nil { log.Errorln("Transfer Error:", err) return err } transferData += ns count += int64(n) } } return nil } func (h *HttpServer) trimSize(size int64) string { var tani string tani = fmt.Sprintf("%v Byte", size) if f64 := float64(size) / 1024; f64 > 1 { tani = fmt.Sprintf("%.3f KiB", math.Trunc(f64*1e3+0.5)*1e-3) if f64 = float64(f64) / 1024; f64 > 1 { tani = fmt.Sprintf("%.3f MiB", math.Trunc(f64*1e3+0.5)*1e-3) if f64 = float64(f64) / 1024; f64 > 1 { tani = fmt.Sprintf("%.3f GiB", math.Trunc(f64*1e3+0.5)*1e-3) } } } return tani } func (h *HttpServer) uploadFile(w http.ResponseWriter, r *http.Request) { if r.Method != "POST" { w.WriteHeader(200) w.Write([]byte("USE POST METHOD!")) return } r.ParseMultipartForm(10485760) file, handler, err := r.FormFile("victorique") if err != nil { starlog.Errorf("Parse File From Form Failed:%v\n", err) w.WriteHeader(502) w.Write([]byte(err.Error())) return } defer file.Close() starlog.Noticef("Uploading %s From %s\n", handler.Filename, r.RemoteAddr) _, envPath := h.getStrEnvPath(r.FormValue("path")) if envPath == "" { starlog.Errorf("No EnvPath Found For Upload File %s From %s\n", handler.Filename, r.RemoteAddr) h.Page404(w) return } os.MkdirAll(filepath.Join(envPath, h.uploadFolder), 0755) f, err := os.OpenFile(filepath.Join(envPath, h.uploadFolder, handler.Filename), os.O_WRONLY|os.O_CREATE, 0755) if err != nil { starlog.Errorf("Open Local File %s Form %v Failed:%v\n", handler.Filename, r.RemoteAddr, err) return } defer f.Close() _, err = io.Copy(f, file) if err != nil { starlog.Errorf("Write File %s Form %v Failed:%v\n", handler.Filename, r.RemoteAddr, err) return } starlog.Infof("Write File %s Form %v Finished\n", handler.Filename, r.RemoteAddr) //fmt.Fprintf(w, `

%v

Return To Web Page

`, handler.Header) }