| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158 | package mainimport (	"errors"	"log"	"net/http"	"net/url"	"path/filepath"	"strings"	fs "imuslab.com/arozos/mod/filesystem"	"imuslab.com/arozos/mod/network/gzipmiddleware")/*Media ServerThis function serve large file objects like video and audio file via asynchronize go routine :)Example usage:/media/?file=user:/Desktop/test/02.Orchestra- エミール (Addendum version).mp3/media/?file=user:/Desktop/test/02.Orchestra- エミール (Addendum version).mp3&download=trueThis will serve / download the file located at files/users/{username}/Desktop/test/02.Orchestra- エミール (Addendum version).mp3PLEASE ALWAYS USE URLENCODE IN THE LINK PASSED INTO THE /media ENDPOINT*///func mediaServer_init() {	if *enable_gzip {		http.HandleFunc("/media/", gzipmiddleware.CompressFunc(serverMedia))		http.HandleFunc("/media/getMime/", gzipmiddleware.CompressFunc(serveMediaMime))	} else {		http.HandleFunc("/media/", serverMedia)		http.HandleFunc("/media/getMime/", serveMediaMime)	}}//This function validate the incoming media request and return the real path for the targed filefunc media_server_validateSourceFile(w http.ResponseWriter, r *http.Request) (string, error) {	username, err := authAgent.GetUserName(w, r)	if err != nil {		return "", errors.New("User not logged in")	}	userinfo, _ := userHandler.GetUserInfoFromUsername(username)	//Validate url valid	if strings.Count(r.URL.String(), "?") > 1 {		return "", errors.New("Invalid paramters. Multiple ? found")	}	targetfile, _ := mv(r, "file", false)	targetfile, _ = url.QueryUnescape(targetfile)	if targetfile == "" {		return "", errors.New("Missing paramter 'file'")	}	//Translate the virtual directory to realpath	realFilepath, err := userinfo.VirtualPathToRealPath(targetfile)	if fileExists(realFilepath) && IsDir(realFilepath) {		return "", errors.New("Given path is not a file.")	}	if err != nil {		return "", errors.New("Unable to translate the given filepath")	}	if !fileExists(realFilepath) {		//Sometime if url is not URL encoded, this error might be shown as well		//Try to use manual segmentation		originalURL := r.URL.String()		//Must be pre-processed with system special URI Decode function to handle edge cases		originalURL = fs.DecodeURI(originalURL)		if strings.Contains(originalURL, "&download=true") {			originalURL = strings.ReplaceAll(originalURL, "&download=true", "")		} else if strings.Contains(originalURL, "download=true") {			originalURL = strings.ReplaceAll(originalURL, "download=true", "")		}		if strings.Contains(originalURL, "&file=") {			originalURL = strings.ReplaceAll(originalURL, "&file=", "file=")		}		urlInfo := strings.Split(originalURL, "file=")		possibleVirtualFilePath := urlInfo[len(urlInfo)-1]		possibleRealpath, err := userinfo.VirtualPathToRealPath(possibleVirtualFilePath)		if err != nil {			log.Println("Error when trying to serve file in compatibility mode", err.Error())			return "", errors.New("Error when trying to serve file in compatibility mode")		}		if fileExists(possibleRealpath) {			realFilepath = possibleRealpath			log.Println("[Media Server] Serving file " + filepath.Base(possibleRealpath) + " in compatibility mode. Do not to use '&' or '+' sign in filename! ")			return realFilepath, nil		} else {			return "", errors.New("File not exists")		}	}	return realFilepath, nil}func serveMediaMime(w http.ResponseWriter, r *http.Request) {	realFilepath, err := media_server_validateSourceFile(w, r)	if err != nil {		sendErrorResponse(w, err.Error())		return	}	mime := "text/directory"	if !IsDir(realFilepath) {		m, _, err := fs.GetMime(realFilepath)		if err != nil {			mime = ""		}		mime = m	}	sendTextResponse(w, mime)}func serverMedia(w http.ResponseWriter, r *http.Request) {	//Serve normal media files	realFilepath, err := media_server_validateSourceFile(w, r)	if err != nil {		sendErrorResponse(w, err.Error())		return	}	//Check if downloadMode	downloadMode := false	dw, _ := mv(r, "download", false)	if dw == "true" {		downloadMode = true	}	//Serve the file	if downloadMode {		userAgent := r.Header.Get("User-Agent")		filename := strings.ReplaceAll(url.QueryEscape(filepath.Base(realFilepath)), "+", "%20")		log.Println(r.Header.Get("User-Agent"))		if strings.Contains(userAgent, "Safari/") {			//This is Safari. Use speial header			w.Header().Set("Content-Disposition", "attachment; filename="+filepath.Base(realFilepath))			w.Header().Set("Content-Type", r.Header.Get("Content-Type"))		} else {			//Fixing the header issue on Golang url encode lib problems			w.Header().Set("Content-Disposition", "attachment; filename*=UTF-8''"+filename)			w.Header().Set("Content-Type", r.Header.Get("Content-Type"))		}	}	http.ServeFile(w, r, realFilepath)}
 |