| 
									
										
										
										
											2020-06-25 07:37:13 +00:00
										 |  |  | package http | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"image" | 
					
						
							|  |  |  | 	"net/http" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/disintegration/imaging" | 
					
						
							|  |  |  | 	"github.com/gorilla/mux" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/filebrowser/filebrowser/v2/files" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const ( | 
					
						
							|  |  |  | 	sizeThumb = "thumb" | 
					
						
							|  |  |  | 	sizeBig   = "big" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type imageProcessor func(src image.Image) (image.Image, error) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var previewHandler = withUser(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) { | 
					
						
							|  |  |  | 	if !d.user.Perm.Download { | 
					
						
							|  |  |  | 		return http.StatusAccepted, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	vars := mux.Vars(r) | 
					
						
							|  |  |  | 	size := vars["size"] | 
					
						
							|  |  |  | 	if size != sizeBig && size != sizeThumb { | 
					
						
							|  |  |  | 		return http.StatusNotImplemented, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	file, err := files.NewFileInfo(files.FileOptions{ | 
					
						
							|  |  |  | 		Fs:      d.user.Fs, | 
					
						
							|  |  |  | 		Path:    "/" + vars["path"], | 
					
						
							|  |  |  | 		Modify:  d.user.Perm.Modify, | 
					
						
							|  |  |  | 		Expand:  true, | 
					
						
							|  |  |  | 		Checker: d, | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return errToStatus(err), err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	setContentDisposition(w, r, file) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch file.Type { | 
					
						
							|  |  |  | 	case "image": | 
					
						
							|  |  |  | 		return handleImagePreview(w, r, file, size) | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		return http.StatusNotImplemented, fmt.Errorf("can't create preview for %s type", file.Type) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func handleImagePreview(w http.ResponseWriter, r *http.Request, file *files.FileInfo, size string) (int, error) { | 
					
						
							|  |  |  | 	format, err := imaging.FormatFromExtension(file.Extension) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		// Unsupported extensions directly return the raw data
 | 
					
						
							|  |  |  | 		if err == imaging.ErrUnsupportedFormat { | 
					
						
							|  |  |  | 			return rawFileHandler(w, r, file) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return errToStatus(err), err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-07 14:47:11 +00:00
										 |  |  | 	fd, err := file.Fs.Open(file.Path) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return errToStatus(err), err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer fd.Close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if format == imaging.GIF && size == sizeBig { | 
					
						
							|  |  |  | 		if _, err := rawFileHandler(w, r, file); err != nil { //nolint: govet
 | 
					
						
							|  |  |  | 			return errToStatus(err), err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return 0, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-25 07:37:13 +00:00
										 |  |  | 	var imgProcessor imageProcessor | 
					
						
							|  |  |  | 	switch size { | 
					
						
							|  |  |  | 	case sizeBig: | 
					
						
							|  |  |  | 		imgProcessor = func(img image.Image) (image.Image, error) { | 
					
						
							|  |  |  | 			return imaging.Fit(img, 1080, 1080, imaging.Lanczos), nil | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	case sizeThumb: | 
					
						
							|  |  |  | 		imgProcessor = func(img image.Image) (image.Image, error) { | 
					
						
							|  |  |  | 			return imaging.Thumbnail(img, 128, 128, imaging.Box), nil | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		return http.StatusBadRequest, fmt.Errorf("unsupported preview size %s", size) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	img, err := imaging.Decode(fd, imaging.AutoOrientation(true)) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return errToStatus(err), err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	img, err = imgProcessor(img) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return errToStatus(err), err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if imaging.Encode(w, img, format) != nil { | 
					
						
							|  |  |  | 		return errToStatus(err), err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 0, nil | 
					
						
							|  |  |  | } |