package httpserver import ( "encoding/base64" "errors" "fmt" "io" "io/ioutil" "net/http" "os" "path/filepath" "strconv" "strings" "b612.me/starcrypto" "b612.me/starlog" "b612.me/staros" ) type VtqeHttpServer struct { basicAuth string path string upload bool version string indexFile string stopMime bool } func RunHttpServer(listenIp, port, auth, folderPath, certKey, version, indexFile string, doUpload, stopMime bool) error { var err error var vtqe VtqeHttpServer = VtqeHttpServer{auth, folderPath, doUpload, version, indexFile, stopMime} http.HandleFunc("/", vtqe.httpListen) starlog.Noticeln("Listening On " + listenIp + ":" + port) if doUpload { starlog.Noticeln("upload is openned,path is /vtqeupload1127") http.HandleFunc("/vtqeupload1127", vtqe.uploadFile) } if certKey == "" { err = http.ListenAndServe(listenIp+":"+port, nil) } else { certs := strings.Split(certKey, ":") if len(certs) != 2 { starlog.Criticalln("证书不正确!") return errors.New("ZSBZQ") } err = http.ListenAndServeTLS(listenIp+":"+port, certs[0], certs[1], nil) } if err != nil { starlog.Criticalln("Error:" + err.Error()) return err } return nil } func (v VtqeHttpServer) httpListen(w http.ResponseWriter, r *http.Request) { log := starlog.Std.NewFlag() w.Header().Set("Server", "Victorique") w.Header().Set("Powered", "B612.ME") write401 := func() { w.Header().Set("WWW-Authenticate", ` Basic realm="Please Enter Passwd"`) w.WriteHeader(401) w.Write([]byte(` 401 Authorization Required

401 Authorization Required


B612 HTTP SERVER
`)) } if v.basicAuth != "" { authHeader := strings.TrimSpace(r.Header.Get("Authorization")) if len(authHeader) == 0 { log.Noticeln("No Authed! Get Path is", r.URL.Path, r.RemoteAddr) write401() return } else { userAuth := base64.StdEncoding.EncodeToString([]byte(v.basicAuth)) authStr := strings.Split(authHeader, " ") if strings.TrimSpace(authStr[1]) != userAuth { log.Noticeln("Auth Failed! Get Path is", r.URL.Path, r.RemoteAddr, "pwd enter is", authHeader) write401() return } } } p := r.URL.Path cmd := r.URL.Query()["cmd"] fullpath, _ := filepath.Abs(v.path + p) if p == "/" && v.indexFile != "" { tmppath, _ := filepath.Abs(v.path + "/" + v.indexFile) if staros.Exists(tmppath) { fullpath = tmppath p = "/" + v.indexFile } } log.Noticeln("Get " + p + " " + r.RemoteAddr) if p == "/" { v.readFolder(w, r, fullpath, true) return } if v.upload { if p == "/vtqeupload1127/web" { w.Write([]byte(`

B612 File Upload Page

上传文件:

Copyright@b612.me

`)) return } } if !staros.Exists(fullpath) { w.WriteHeader(404) if len(cmd) != 0 { if cmd[0] == "header" { for k, v := range r.Header { for _, v2 := range v { fmt.Fprintf(w, "%s:%s\n", k, v2) } } } } w.Write([]byte("

404 NOT FOUND

")) return } if staros.IsFolder(fullpath) { v.readFolder(w, r, fullpath, false) return } fpdst, err := os.Open(fullpath) if err != nil { log.Errorln(err) w.WriteHeader(403) w.Write([]byte("

403 NO ACCESS

")) return } fpinfo, _ := os.Stat(fullpath) name := filepath.Base(fullpath) ext := filepath.Ext(name) mime := GetMIME(ext) if mime == "" || v.stopMime { w.Header().Set("Content-Type", "application/download") w.Header().Set("Content-Disposition", "attachment;filename="+name) w.Header().Set("Content-Transfer-Encoding", "binary") } else { w.Header().Set("Content-Type", mime) } etag := starcrypto.Md5Str([]byte(fpinfo.ModTime().String())) w.Header().Set("Accept-Ranges", "bytes") w.Header().Set("ETag", etag) w.Header().Set("Last-Modified", strings.ReplaceAll(fpinfo.ModTime().UTC().Format("Mon, 2 Jan 2006 15:04:05 MST"), "UTC", "GMT")) isRange := false var rangeStart, rangeEnd int64 rangeEnd = -1 for k, v := range r.Header { if strings.ToLower(k) == "range" { if strings.Index(v[0], "bytes=") < 0 { break } v[0] = strings.Replace(v[0], "bytes=", "", -1) data := strings.Split(v[0], "-") if len(data) == 0 { break } rangeStart, _ = strconv.ParseInt(data[0], 10, 64) if len(data) == 2 { rangeEnd, _ = strconv.ParseInt(data[1], 10, 64) } //w.WriteHeader(206) //206 支持断点续传 isRange = true break } } defer fpdst.Close() var transferData int if !isRange { w.Header().Set("Content-Length", strconv.FormatInt(fpinfo.Size(), 10)) w.WriteHeader(200) for { buf := make([]byte, 1048576) n, err := fpdst.Read(buf) if n != 0 { ns, err := w.Write(buf[0:n]) transferData += ns if err != nil { starlog.Errorln("Transfer Error:", err) } } if err != nil { if err == io.EOF { break } break } } } else { w.Header().Set("Content-Length", strconv.FormatInt(fpinfo.Size(), 10)) if rangeEnd == -1 { w.Header().Set("Content-Range", `bytes `+strconv.FormatInt(rangeStart, 10)+"-"+strconv.FormatInt(fpinfo.Size(), 10)+"/"+strconv.FormatInt(fpinfo.Size(), 10)) //w.Header().Set("Content-Length", strconv.FormatInt(fpinfo.Size()-rangeStart, 10)) } else { w.Header().Set("Content-Range", `bytes `+strconv.FormatInt(rangeStart, 10)+"-"+strconv.FormatInt(rangeEnd, 10)+"/"+strconv.FormatInt(fpinfo.Size(), 10)) //w.Header().Set("Content-Length", strconv.FormatInt(1+rangeEnd-rangeStart, 10)) } w.WriteHeader(206) fpdst.Seek(int64(rangeStart), 0) count := rangeStart for { buf := make([]byte, 1048576) n, err := fpdst.Read(buf) if err != nil { if err == io.EOF { break } return } if rangeEnd == -1 { ns, err := w.Write(buf[0:n]) transferData += ns if err != nil { starlog.Errorln("Transfer Error:", err) } } else { if count > rangeEnd { break } if count+int64(n) > rangeEnd { w.Write(buf[0 : rangeEnd-count+1]) break } else { ns, err := w.Write(buf[0:n]) transferData += ns if err != nil { starlog.Errorln("Transfer Error:", err) } count += int64(n) } } } } var tani string tani = fmt.Sprintf("%v Byte", transferData) if f64 := float64(transferData) / 1024; f64 > 1 { tani = fmt.Sprintf("%v KB", f64) if f64 = float64(f64) / 1024; f64 > 1 { tani = fmt.Sprintf("%v MB", f64) if f64 = float64(f64) / 1024; f64 > 1 { tani = fmt.Sprintf("%v GB", f64) } } } log.Infoln(fpinfo.Name(), "客户端下载已结束,共传输大小:"+tani) } func (v VtqeHttpServer) readFolder(w http.ResponseWriter, r *http.Request, fullpath string, isroot bool) { dir, err := ioutil.ReadDir(fullpath) if err != nil { starlog.Errorln(err) w.WriteHeader(403) w.Write([]byte("

May Cannot Access!

")) } w.Write([]byte("\n\n

B612 Http Server - " + v.version + "

")) if v.upload { w.Write([]byte("Upload Web Page Is Openned!

")) } w.Write([]byte("
\n"))
	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]
	}
	if !isroot {
		w.Write([]byte(fmt.Sprintf("

%s %s

\n", r.URL.Path+"/..", "..", "上层文件夹"))) } for _, v := range dir { if v.Name() != "." || v.Name() != ".." { if !v.IsDir() { w.Write([]byte(fmt.Sprintf("

%s %d %s

\n", r.URL.Path+"/"+v.Name(), v.Name(), int(v.Size()), v.ModTime().Format("2006-01-02 15:04:05")))) } else { w.Write([]byte(fmt.Sprintf("

%s %s %s

\n", r.URL.Path+"/"+v.Name(), v.Name(), "文件夹", v.ModTime().Format("2006-01-02 15:04:05")))) } } } w.Write([]byte("
\n")) return } func (v VtqeHttpServer) uploadFile(w http.ResponseWriter, r *http.Request) { if r.Method != "POST" { w.Write([]byte("USE POST METHOD!")) return } r.ParseMultipartForm(10485760) file, handler, err := r.FormFile("victorique") if err != nil { starlog.Errorln(err) w.WriteHeader(502) w.Write([]byte(err.Error())) return } defer file.Close() starlog.Noticef("Upload %s From %s\n", handler.Filename, r.RemoteAddr) fmt.Fprintf(w, `

%v

Return To Web Page

`, handler.Header) os.Mkdir("./vtqeupload1127", 0755) f, err := os.OpenFile("./vtqeupload1127/"+handler.Filename, os.O_WRONLY|os.O_CREATE, 0755) if err != nil { starlog.Errorln(err) return } defer f.Close() io.Copy(f, file) }