github.com/cjdelisle/matterfoss@v5.11.1+incompatible/services/imageproxy/imageproxy.go (about) 1 // Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. 2 // See License.txt for license information. 3 4 package imageproxy 5 6 import ( 7 "errors" 8 "io" 9 "net/http" 10 "sync" 11 12 "github.com/mattermost/mattermost-server/model" 13 "github.com/mattermost/mattermost-server/services/configservice" 14 "github.com/mattermost/mattermost-server/services/httpservice" 15 ) 16 17 var ErrNotEnabled = Error{errors.New("imageproxy.ImageProxy: image proxy not enabled")} 18 19 // An ImageProxy is the public interface for Mattermost's image proxy. An instance of ImageProxy should be created 20 // using MakeImageProxy which requires a configService and an HTTPService provided by the server. 21 type ImageProxy struct { 22 ConfigService configservice.ConfigService 23 configListenerId string 24 25 HTTPService httpservice.HTTPService 26 27 lock sync.RWMutex 28 backend ImageProxyBackend 29 } 30 31 // An ImageProxyBackend provides the functionality for different types of image proxies. An ImageProxy will construct 32 // the required backend depending on the ImageProxySettings provided by the ConfigService. 33 type ImageProxyBackend interface { 34 // GetImage provides a proxied image in response to an HTTP request. 35 GetImage(w http.ResponseWriter, r *http.Request, imageURL string) 36 37 // GetImageDirect returns a proxied image along with its content type. 38 GetImageDirect(imageURL string) (io.ReadCloser, string, error) 39 40 // GetProxiedImageURL returns the URL to access a given image through the image proxy, whether the image proxy is 41 // running externally or as part of the Mattermost server itself. 42 GetProxiedImageURL(imageURL string) string 43 44 // GetUnproxiedImageURL returns the original URL of an image from one that has been directed at the image proxy. 45 GetUnproxiedImageURL(proxiedURL string) string 46 } 47 48 func MakeImageProxy(configService configservice.ConfigService, httpService httpservice.HTTPService) *ImageProxy { 49 proxy := &ImageProxy{ 50 ConfigService: configService, 51 HTTPService: httpService, 52 } 53 54 proxy.configListenerId = proxy.ConfigService.AddConfigListener(proxy.OnConfigChange) 55 56 config := proxy.ConfigService.Config() 57 proxy.backend = proxy.makeBackend(*config.ImageProxySettings.Enable, *config.ImageProxySettings.ImageProxyType) 58 59 return proxy 60 } 61 62 func (proxy *ImageProxy) makeBackend(enable bool, proxyType string) ImageProxyBackend { 63 if !enable { 64 return nil 65 } 66 67 switch proxyType { 68 case model.IMAGE_PROXY_TYPE_LOCAL: 69 return makeLocalBackend(proxy) 70 case model.IMAGE_PROXY_TYPE_ATMOS_CAMO: 71 return makeAtmosCamoBackend(proxy) 72 default: 73 return nil 74 } 75 } 76 77 func (proxy *ImageProxy) Close() { 78 proxy.lock.Lock() 79 defer proxy.lock.Unlock() 80 81 proxy.ConfigService.RemoveConfigListener(proxy.configListenerId) 82 } 83 84 func (proxy *ImageProxy) OnConfigChange(oldConfig, newConfig *model.Config) { 85 if *oldConfig.ImageProxySettings.Enable != *newConfig.ImageProxySettings.Enable || 86 *oldConfig.ImageProxySettings.ImageProxyType != *newConfig.ImageProxySettings.ImageProxyType { 87 proxy.lock.Lock() 88 defer proxy.lock.Unlock() 89 90 proxy.backend = proxy.makeBackend(*newConfig.ImageProxySettings.Enable, *newConfig.ImageProxySettings.ImageProxyType) 91 } 92 } 93 94 // GetImage takes an HTTP request for an image and requests that image using the image proxy. 95 func (proxy *ImageProxy) GetImage(w http.ResponseWriter, r *http.Request, imageURL string) { 96 proxy.lock.RLock() 97 defer proxy.lock.RUnlock() 98 99 if proxy.backend == nil { 100 w.WriteHeader(http.StatusNotImplemented) 101 return 102 } 103 104 proxy.backend.GetImage(w, r, imageURL) 105 } 106 107 // GetImageDirect takes the URL of an image and returns the image along with its content type. 108 func (proxy *ImageProxy) GetImageDirect(imageURL string) (io.ReadCloser, string, error) { 109 proxy.lock.RLock() 110 defer proxy.lock.RUnlock() 111 112 if proxy.backend == nil { 113 return nil, "", ErrNotEnabled 114 } 115 116 return proxy.backend.GetImageDirect(imageURL) 117 } 118 119 // GetProxiedImageURL takes the URL of an image and returns a URL that can be used to view that image through the 120 // image proxy. 121 func (proxy *ImageProxy) GetProxiedImageURL(imageURL string) string { 122 proxy.lock.RLock() 123 defer proxy.lock.RUnlock() 124 125 if proxy.backend == nil { 126 return imageURL 127 } 128 129 return proxy.backend.GetProxiedImageURL(imageURL) 130 } 131 132 // GetUnproxiedImageURL takes the URL of an image on the image proxy and returns the original URL of the image. 133 func (proxy *ImageProxy) GetUnproxiedImageURL(proxiedURL string) string { 134 proxy.lock.RLock() 135 defer proxy.lock.RUnlock() 136 137 if proxy.backend == nil { 138 return proxiedURL 139 } 140 141 return proxy.backend.GetUnproxiedImageURL(proxiedURL) 142 }