fix download route sending headers too early, improve when file not found on download, other minor related changes

This commit is contained in:
Cyberes 2024-05-05 12:00:59 -06:00
parent 51d6f2dbf2
commit 4f2fe0b015
7 changed files with 51 additions and 41 deletions

View File

@ -23,7 +23,7 @@ func HandleFileNotFound(relPath string, fullPath string, w http.ResponseWriter)
//info, err := os.Lstat(fullPath) //info, err := os.Lstat(fullPath)
//if err != nil { //if err != nil {
// log.Errorf("HELPERS:HandleFileNotFound - os.Lstat failed: %s", err) // log.Errorf("HELPERS:HandleFileNotFound - os.Lstat failed: %s", err)
// Return500Msg(w) // Return500(w)
// return nil // return nil
//} //}
//if !config.FollowSymlinks && info.Mode()&os.ModeSymlink > 0 { //if !config.FollowSymlinks && info.Mode()&os.ModeSymlink > 0 {
@ -35,14 +35,14 @@ func HandleFileNotFound(relPath string, fullPath string, w http.ResponseWriter)
start := time.Now() start := time.Now()
item, err := dc.CrawlNoRecursion(fullPath, nil) item, err := dc.CrawlNoRecursion(fullPath, nil)
if err == nil && (os.IsNotExist(err) || item == nil) { if err == nil && (os.IsNotExist(err) || item == nil) {
ReturnFake404Msg("path not found", w) ReturnFake404Msg("file not found", w)
return nil return nil
} else if err != nil { } else if err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
ReturnFake404Msg("path not found", w) ReturnFake404Msg("file not found", w)
} else { } else {
log.Errorf("HELPERS:HandleFileNotFound:Crawl - Crawl failed: %s", err) log.Errorf("HELPERS:HandleFileNotFound:Crawl - Crawl failed: %s", err)
Return500Msg(w) Return500(w)
} }
return nil return nil
} }
@ -51,7 +51,7 @@ func HandleFileNotFound(relPath string, fullPath string, w http.ResponseWriter)
item, found := sharedcache.Cache.Get(relPath) item, found := sharedcache.Cache.Get(relPath)
if !found { if !found {
// Assume that it doesn't exist. // Assume that it doesn't exist.
ReturnFake404Msg("path not found", w) ReturnFake404Msg("file not found", w)
return nil return nil
} }

View File

@ -32,10 +32,14 @@ func HandleRejectDuringInitialCrawl(w http.ResponseWriter) {
WriteErrorResponse(http.StatusServiceUnavailable, http.StatusServiceUnavailable, "initial file system crawl in progress", w) WriteErrorResponse(http.StatusServiceUnavailable, http.StatusServiceUnavailable, "initial file system crawl in progress", w)
} }
func Return500Msg(w http.ResponseWriter) { func Return500(w http.ResponseWriter) {
WriteErrorResponse(http.StatusInternalServerError, http.StatusInternalServerError, "internal server error", w) WriteErrorResponse(http.StatusInternalServerError, http.StatusInternalServerError, "internal server error", w)
} }
func Return500Msg(msg string, w http.ResponseWriter) {
WriteErrorResponse(500, http.StatusInternalServerError, msg, w)
}
func Return403Msg(msg string, w http.ResponseWriter) { func Return403Msg(msg string, w http.ResponseWriter) {
WriteErrorResponse(http.StatusForbidden, http.StatusForbidden, msg, w) WriteErrorResponse(http.StatusForbidden, http.StatusForbidden, msg, w)
} }

View File

@ -66,20 +66,20 @@ func ZipHandlerCompressMultiple(paths []string, w http.ResponseWriter, r *http.R
if !item.IsDir { if !item.IsDir {
writer, err := zipWriter.Create(relPath) writer, err := zipWriter.Create(relPath)
if err != nil { if err != nil {
Return500Msg(w) Return500(w)
return return
} }
file, err := os.Open(fullPath) file, err := os.Open(fullPath)
if err != nil { if err != nil {
Return500Msg(w) Return500(w)
return return
} }
defer file.Close() defer file.Close()
_, err = io.Copy(writer, file) _, err = io.Copy(writer, file)
if err != nil { if err != nil {
Return500Msg(w) Return500(w)
return return
} }
} else { } else {

View File

@ -79,7 +79,7 @@ func APISearch(w http.ResponseWriter, r *http.Request) {
resp, err := elastic.SimpleQuery(queryString, excludeElements, queryFields) resp, err := elastic.SimpleQuery(queryString, excludeElements, queryFields)
if err != nil { if err != nil {
log.Errorf(`ROUTES:Search - Failed to perform Elasticsearch query "%s" - %s`, queryString, err) log.Errorf(`ROUTES:Search - Failed to perform Elasticsearch query "%s" - %s`, queryString, err)
helpers.Return500Msg(w) helpers.Return500(w)
return return
} }
@ -88,7 +88,7 @@ func APISearch(w http.ResponseWriter, r *http.Request) {
err = json.NewDecoder(resp.Body).Decode(&respData) err = json.NewDecoder(resp.Body).Decode(&respData)
if err != nil { if err != nil {
log.Errorf(`ROUTES:Search - Failed to parse Elasticsearch response for query "%s" - %s`, queryString, err) log.Errorf(`ROUTES:Search - Failed to parse Elasticsearch response for query "%s" - %s`, queryString, err)
helpers.Return500Msg(w) helpers.Return500(w)
return return
} }

View File

@ -82,6 +82,24 @@ func APIDownload(w http.ResponseWriter, r *http.Request) {
} }
if !item.IsDir { if !item.IsDir {
var err error
// Open the file
openFile, err := os.Open(fullPath)
if err != nil {
if os.IsNotExist(err) {
sharedcache.Cache.Remove(relPath) // Remove item from the cache
helpers.ReturnFake404Msg("cache out of date, file missing from disk", w)
} else {
log.Errorf(`Failed to open file for download: "%s" - "%s"`, fullPath, err)
helpers.Return500Msg("internal server error accessing file", w)
}
return
}
defer openFile.Close()
// =============================================================================================================
// Get the file info
// Only files can have inline disposition, zip archives cannot // Only files can have inline disposition, zip archives cannot
// https://stackoverflow.com/a/57994289 // https://stackoverflow.com/a/57994289
contentDownload := r.URL.Query().Get("download") contentDownload := r.URL.Query().Get("download")
@ -95,27 +113,24 @@ func APIDownload(w http.ResponseWriter, r *http.Request) {
// Get the MIME type of the file // Get the MIME type of the file
var mimeType string var mimeType string
var err error if item.MimeType == nil { // Only if the MIME type of this item has not been set yet
if item.MimeType == nil { // only if the MIME type of this item has not been set yet
_, mimeType, _, err = file.GetMimeType(fullPath, true) _, mimeType, _, err = file.GetMimeType(fullPath, true)
if err != nil { if err != nil {
log.Errorf("ROUTES:Download - Error detecting MIME type: %v", err) log.Errorf("ROUTES:Download - Error detecting MIME type: %v", err)
} else if mimeType != "" { } else if mimeType != "" {
// GetMimeType() returns an empty string if it was a directory. // GetMimeType() returns an empty string if it was a directory.
// Update the cacheitem's MIME in the sharedCache.
item.MimeType = &mimeType item.MimeType = &mimeType
sharedcache.Cache.Add(relPath, item) sharedcache.Cache.Add(relPath, item) // Update the cacheitem's MIME in the sharedCache.
} else { } else {
log.Errorf("ROUTES:Download - Failed to match a condition when checking a file's MIME - %s", fullPath) log.Errorf("ROUTES:Download - Failed to match a condition when checking a file's MIME - %s", fullPath)
helpers.Return500Msg(w) helpers.Return500(w)
} }
} else { } else {
mimeType = *item.MimeType mimeType = *item.MimeType
} }
// Get the encoding of this file // Get the encoding of this file
var encoding string encoding := "utf-8" // fall back to utf-8
encoding = "utf-8" // fall back to utf-8
if item.Encoding == nil || *item.Encoding == "" { // only if the encoding of this item has not been set yet if item.Encoding == nil || *item.Encoding == "" { // only if the encoding of this item has not been set yet
encoding, err = file.DetectFileEncoding(fullPath) encoding, err = file.DetectFileEncoding(fullPath)
if err != nil { if err != nil {
@ -128,6 +143,11 @@ func APIDownload(w http.ResponseWriter, r *http.Request) {
encoding = *item.Encoding encoding = *item.Encoding
} }
// =============================================================================================================
// Send the file to the client.
// We are using `http.ServeContent()` since this allows us to catch and handle any missing files. `http.ServeFile()` returns
// the default 404 page if the file is missing from the disk.
if config.GetConfig().HTTPNoMimeSniffHeader { if config.GetConfig().HTTPNoMimeSniffHeader {
w.Header().Set("X-Content-Type-Options", "nosniff") w.Header().Set("X-Content-Type-Options", "nosniff")
mimeType = file.CastTextMimes(mimeType) mimeType = file.CastTextMimes(mimeType)
@ -138,32 +158,18 @@ func APIDownload(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", mimeType+"; charset="+encoding) w.Header().Set("Content-Type", mimeType+"; charset="+encoding)
} }
// =============================================================================================================
// Send the file to the client.
// We are using `http.ServeContent()` since this allows us to catch and handle any missing files. `http.ServeFile()` returns
// the default 404 page if the file is missing from the disk.
// Open the file
openFile, err := os.Open(fullPath)
if err != nil {
sharedcache.Cache.Remove(relPath) // remove it from the cache
helpers.ReturnFake404Msg("file missing from disk, cache out of date", w)
return
}
defer openFile.Close()
// Get the file info // Get the file info
fileInfo, err := openFile.Stat() fileInfo, err := openFile.Stat()
if err != nil { if err != nil {
log.Errorf(`ROUTES:Download - Failed to stat file "%s" - %s`, fullPath, err) log.Errorf(`ROUTES:Download - Failed to stat file "%s" - %s`, fullPath, err)
helpers.Return500Msg(w) helpers.Return500(w)
return return
} }
// If the file exists, serve it // If the file exists, serve it.
http.ServeContent(w, r, fileInfo.Name(), fileInfo.ModTime(), openFile) http.ServeContent(w, r, fileInfo.Name(), fileInfo.ModTime(), openFile)
} else { } else {
// Stream archive of the directory here // Stream archive of the directory.
w.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s.zip"`, item.Name)) w.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s.zip"`, item.Name))
helpers.ZipHandlerCompress(fullPath, w, r) helpers.ZipHandlerCompress(fullPath, w, r)
} }

View File

@ -72,7 +72,7 @@ func APIList(w http.ResponseWriter, r *http.Request) {
fileExists, mimeType, ext, err := file.GetMimeType(fullPath, true) fileExists, mimeType, ext, err := file.GetMimeType(fullPath, true)
if err != nil { if err != nil {
log.Warnf("ROUTES:List - Error detecting MIME type: %v", err) log.Warnf("ROUTES:List - Error detecting MIME type: %v", err)
helpers.Return500Msg(w) helpers.Return500(w)
return return
} }
if !fileExists { if !fileExists {

View File

@ -94,7 +94,7 @@ func APIThumbnail(w http.ResponseWriter, r *http.Request) {
} }
if err != nil { if err != nil {
log.Warnf(`ROUTES:Thumb - Error detecting MIME type for "%s". %v`, fullPath, err) log.Warnf(`ROUTES:Thumb - Error detecting MIME type for "%s". %v`, fullPath, err)
helpers.Return500Msg(w) helpers.Return500(w)
return return
} }
// Update the item's MIME in the cache. // Update the item's MIME in the cache.
@ -112,7 +112,7 @@ func APIThumbnail(w http.ResponseWriter, r *http.Request) {
imageBytes, err := file.ConvertToPNG(fullPath, mimeType) imageBytes, err := file.ConvertToPNG(fullPath, mimeType)
if err != nil { if err != nil {
log.Warnf(`ROUTES:Thumb - Error converting "%s". %v`, fullPath, err) log.Warnf(`ROUTES:Thumb - Error converting "%s". %v`, fullPath, err)
helpers.Return500Msg(w) helpers.Return500(w)
return return
} }
@ -121,7 +121,7 @@ func APIThumbnail(w http.ResponseWriter, r *http.Request) {
img, err = png.Decode(bytes.NewReader(imageBytes)) img, err = png.Decode(bytes.NewReader(imageBytes))
if err != nil { if err != nil {
log.Warnf(`ROUTES:Thumb - Error decoding "%s". %v`, fullPath, err) log.Warnf(`ROUTES:Thumb - Error decoding "%s". %v`, fullPath, err)
helpers.Return500Msg(w) helpers.Return500(w)
return return
} }
@ -129,14 +129,14 @@ func APIThumbnail(w http.ResponseWriter, r *http.Request) {
img, err = resizeImage(img, width, height, square, autoScale) img, err = resizeImage(img, width, height, square, autoScale)
if err != nil { if err != nil {
log.Warnf(`ROUTES:Thumb - Error resizing "%s". %v`, fullPath, err) log.Warnf(`ROUTES:Thumb - Error resizing "%s". %v`, fullPath, err)
helpers.Return500Msg(w) helpers.Return500(w)
return return
} }
buf, err := file.CompressPNGFile(img, pngQuality) buf, err := file.CompressPNGFile(img, pngQuality)
if err != nil { if err != nil {
log.Warnf(`ROUTES:Thumb - Error compressing "%s". %v`, fullPath, err) log.Warnf(`ROUTES:Thumb - Error compressing "%s". %v`, fullPath, err)
helpers.Return500Msg(w) helpers.Return500(w)
return return
} }