package tools import ( "encoding/base64" "fmt" "io" "io/ioutil" "net/http" "os" "path/filepath" "strconv" "strings" "b612.me/starainrt" "b612.me/starlog" "github.com/spf13/cobra" ) var port, ip, path string var up bool var basicAuth, certKey string type TraceHandler struct { h http.Handler } func init() { httpcmd.Flags().StringVarP(&port, "port", "p", "80", "监听端口") httpcmd.Flags().StringVarP(&ip, "ip", "i", "0.0.0.0", "监听ip") httpcmd.Flags().StringVarP(&path, "folder", "f", "./", "本地文件地址") httpcmd.Flags().BoolVarP(&up, "upload", "u", false, "是否开启文件上传") httpcmd.Flags().StringVarP(&basicAuth, "auth", "a", "", "HTTP BASIC AUTH认证(用户名:密码)") httpcmd.Flags().StringVarP(&certKey, "cert", "c", "", "TLS证书路径,用:分割证书与密钥") Maincmd.AddCommand(httpcmd) } // httpCmd represents the http command var httpcmd = &cobra.Command{ Use: "http", Short: "HTTP文件服务器", Long: `HTTP文件服务器`, Run: func(cmd *cobra.Command, args []string) { var err error http.HandleFunc("/", httplisten) path, _ = filepath.Abs(path) starlog.Infoln("Listening On Port:" + port) if up { starlog.Infoln("upload is openned,path is /vtqeupload1127") http.HandleFunc("/vtqeupload1127", uploadfile) } if certKey == "" { err = http.ListenAndServe(ip+":"+port, nil) } else { certs := strings.Split(certKey, ":") if len(certs) != 2 { starlog.Criticalln("证书不正确!") return } err = http.ListenAndServeTLS(ip+":"+port, certs[0], certs[1], nil) } if err != nil { starlog.Criticalln("Error:" + err.Error()) } }, } func 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) } func httplisten(w http.ResponseWriter, r *http.Request) { log := starlog.Std.NewFlag() w.Header().Set("Server", "Vicorique") 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 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(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"] log.Noticeln("Get " + p + " " + r.RemoteAddr) fullpath, _ := filepath.Abs(path + p) if p == "/" { ReadFolder(w, r, fullpath, true) return } if up { if p == "/vtqeupload1127/web" { w.Write([]byte(`

B612 File Upload Page

上传文件:

Copyright@b612.me

`)) return } } if !starainrt.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 starainrt.IsFolder(fullpath) { 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) tmp := strings.Split(name, ".") ext := "" if len(tmp) >= 2 { ext = strings.ToLower(tmp[len(tmp)-1]) } switch ext { case "jpeg", "jpg", "jpe": w.Header().Set("Content-Type", "image/jpeg") case "mpeg", "mpg", "mkv": w.Header().Set("Content-Type", "video/mpeg") case "mp4": w.Header().Set("Content-Type", "video/mp4") case "pdf": w.Header().Set("Content-Type", "application/pdf") default: w.Header().Set("Content-Type", "application/download") w.Header().Set("Content-Disposition", "attachment;filename="+name) } etag := new(starainrt.StarCrypto).MD5([]byte(fpinfo.ModTime().String())) w.Header().Set("Content-Transfer-Encoding", "binary") 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 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 - " + Version + "

")) if up { 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 }