mediaServer.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. package main
  2. import (
  3. "net/http"
  4. "path/filepath"
  5. "net/url"
  6. "log"
  7. "strings"
  8. "errors"
  9. fs "imuslab.com/arozos/mod/filesystem"
  10. )
  11. /*
  12. Media Server
  13. This function serve large file objects like video and audio file via asynchronize go routine :)
  14. Example usage:
  15. /media/?file=user:/Desktop/test/02.Orchestra- エミール (Addendum version).mp3
  16. /media/?file=user:/Desktop/test/02.Orchestra- エミール (Addendum version).mp3&download=true
  17. This will serve / download the file located at files/users/{username}/Desktop/test/02.Orchestra- エミール (Addendum version).mp3
  18. >>> PLEASE ALWAYS USE URLENCODE IN THE LINK PASSED INTO THE /media ENDPOINT <<<
  19. */
  20. func mediaServer_init(){
  21. http.HandleFunc("/media/", serverMedia);
  22. http.HandleFunc("/media/getMime/", serveMediaMime);
  23. }
  24. //This function validate the incoming media request and return the real path for the targed file
  25. func media_server_validateSourceFile(w http.ResponseWriter, r *http.Request) (string, error){
  26. username, err := authAgent.GetUserName(w,r);
  27. if (err != nil){
  28. return "", errors.New("User not logged in");
  29. }
  30. userinfo, _ := userHandler.GetUserInfoFromUsername(username);
  31. //Validate url valid
  32. if (strings.Count(r.URL.String(), "?") > 1){
  33. return "", errors.New("Invalid paramters. Multiple ? found")
  34. }
  35. targetfile, _ := mv(r,"file",false)
  36. targetfile, _ = url.QueryUnescape(targetfile)
  37. if (targetfile == ""){
  38. return "", errors.New("Missing paramter 'file'");
  39. }
  40. //Translate the virtual directory to realpath
  41. realFilepath, err := userinfo.VirtualPathToRealPath(targetfile);
  42. if (fileExists(realFilepath) && IsDir(realFilepath)){
  43. return "", errors.New("Given path is not a file.")
  44. }
  45. if (err != nil){
  46. return "", errors.New("Unable to translate the given filepath")
  47. }
  48. if (!fileExists(realFilepath)){
  49. //Sometime if url is not URL encoded, this error might be shown as well
  50. //Try to use manual segmentation
  51. originalURL := r.URL.String();
  52. //Must be pre-processed with system special URI Decode function to handle edge cases
  53. originalURL = fs.DecodeURI(originalURL);
  54. if (strings.Contains(originalURL, "&download=true")){
  55. originalURL = strings.ReplaceAll(originalURL, "&download=true", "")
  56. }else if (strings.Contains(originalURL, "download=true")){
  57. originalURL = strings.ReplaceAll(originalURL, "download=true", "")
  58. }
  59. if (strings.Contains(originalURL, "&file=")){
  60. originalURL = strings.ReplaceAll(originalURL, "&file=", "file=")
  61. }
  62. urlInfo := strings.Split(originalURL, "file=")
  63. possibleVirtualFilePath := urlInfo[len(urlInfo) - 1]
  64. possibleRealpath, err := userinfo.VirtualPathToRealPath(possibleVirtualFilePath);
  65. if (err != nil){
  66. log.Println("Error when trying to serve file in compatibility mode", err.Error());
  67. return "", errors.New("Error when trying to serve file in compatibility mode");
  68. }
  69. if (fileExists(possibleRealpath)){
  70. realFilepath = possibleRealpath;
  71. log.Println("[Media Server] Serving file " + filepath.Base(possibleRealpath) + " in compatibility mode. Do not to use '&' or '+' sign in filename! ")
  72. return realFilepath, nil
  73. }else{
  74. return "", errors.New("File not exists")
  75. }
  76. }
  77. return realFilepath, nil
  78. }
  79. func serveMediaMime(w http.ResponseWriter, r *http.Request){
  80. realFilepath, err := media_server_validateSourceFile(w,r)
  81. if (err != nil){
  82. sendErrorResponse(w, err.Error())
  83. return
  84. }
  85. mime := "text/directory"
  86. if !IsDir(realFilepath){
  87. m, _, err := fs.GetMime(realFilepath)
  88. if (err != nil){
  89. mime = ""
  90. }
  91. mime = m
  92. }
  93. sendTextResponse(w, mime);
  94. }
  95. func serverMedia(w http.ResponseWriter, r *http.Request) {
  96. //Serve normal media files
  97. realFilepath, err := media_server_validateSourceFile(w,r)
  98. if (err != nil){
  99. sendErrorResponse(w, err.Error())
  100. return
  101. }
  102. //Check if downloadMode
  103. downloadMode := false
  104. dw, _ := mv(r, "download",false)
  105. if (dw == "true"){
  106. downloadMode = true;
  107. }
  108. //Serve the file
  109. if (downloadMode){
  110. //Fixing the header issue on Golang url encode lib problems
  111. w.Header().Set("Content-Disposition", "attachment; filename*=UTF-8''" + strings.ReplaceAll(url.QueryEscape(filepath.Base(realFilepath)),"+","%20"))
  112. w.Header().Set("Content-Type", r.Header.Get("Content-Type"))
  113. }
  114. http.ServeFile(w, r, realFilepath)
  115. }