github.com/ashishbhate/mattermost-server@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  }