From 0fcf0c50527f13b6b2d40d261f5447e863e63046 Mon Sep 17 00:00:00 2001 From: Aditya Bansal Date: Thu, 9 Nov 2017 21:01:57 +0530 Subject: [PATCH] thumbor: Add thumbor on port 9995 in development. For now, this does nothing in a production environment, but it should simplify the process of doing testing on the Thumbor implementation, by integrating a lot of dependency management logic. --- .gitignore | 1 + tools/lib/provision.py | 6 +- tools/run-dev.py | 17 +- tools/setup/setup_venvs.py | 3 + version.py | 2 +- zproject/settings.py | 1 + zthumbor/__init__.py | 0 zthumbor/loaders/__init__.py | 0 zthumbor/loaders/helpers.py | 85 +++++ zthumbor/loaders/zloader.py | 44 +++ zthumbor/thumbor.conf | 695 +++++++++++++++++++++++++++++++++++ 11 files changed, 849 insertions(+), 5 deletions(-) create mode 100644 zthumbor/__init__.py create mode 100644 zthumbor/loaders/__init__.py create mode 100644 zthumbor/loaders/helpers.py create mode 100644 zthumbor/loaders/zloader.py create mode 100644 zthumbor/thumbor.conf diff --git a/.gitignore b/.gitignore index 7d7e2d3471..b3b3f8e5fe 100644 --- a/.gitignore +++ b/.gitignore @@ -66,3 +66,4 @@ zulip.kdev4 ## Miscellaneous # (Ideally this section is empty.) +zthumbor/thumbor_local_settings.py diff --git a/tools/lib/provision.py b/tools/lib/provision.py index 67345e4ffa..d81532547c 100755 --- a/tools/lib/provision.py +++ b/tools/lib/provision.py @@ -15,7 +15,9 @@ ZULIP_PATH = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__f sys.path.append(ZULIP_PATH) from scripts.lib.zulip_tools import run, subprocess_text_output, OKBLUE, ENDC, WARNING, \ get_dev_uuid_var_path -from scripts.lib.setup_venv import VENV_DEPENDENCIES +from scripts.lib.setup_venv import ( + setup_virtualenv, VENV_DEPENDENCIES, THUMBOR_VENV_DEPENDENCIES +) from scripts.lib.node_cache import setup_node_modules, NODE_MODULES_CACHE_PATH from version import PROVISION_VERSION @@ -128,7 +130,7 @@ UBUNTU_COMMON_APT_DEPENDENCIES = [ "curl", # Used for fetching PhantomJS as wget occasionally fails on redirects "netcat", # Used for flushing memcached "moreutils", # Used for sponge command -] + VENV_DEPENDENCIES +] + VENV_DEPENDENCIES + THUMBOR_VENV_DEPENDENCIES APT_DEPENDENCIES = { "stretch": UBUNTU_COMMON_APT_DEPENDENCIES + [ diff --git a/tools/run-dev.py b/tools/run-dev.py index 731c500b98..0924514a59 100755 --- a/tools/run-dev.py +++ b/tools/run-dev.py @@ -112,6 +112,7 @@ proxy_port = base_port django_port = base_port + 1 tornado_port = base_port + 2 webpack_port = base_port + 3 +thumbor_port = base_port + 4 os.chdir(os.path.join(os.path.dirname(__file__), '..')) @@ -152,7 +153,9 @@ cmds = [['./tools/compile-handlebars-templates', 'forever'], ['./tools/run-dev-queue-processors'] + manage_args, ['env', 'PGHOST=127.0.0.1', # Force password authentication using .pgpass './puppet/zulip/files/postgresql/process_fts_updates'], - ['./manage.py', 'deliver_scheduled_messages']] + ['./manage.py', 'deliver_scheduled_messages'], + ['/srv/zulip-thumbor-venv/bin/thumbor', '-c', './zthumbor/thumbor.conf', + '-p', '%s' % (thumbor_port,)]] if options.test: # Webpack doesn't support 2 copies running on the same system, so # in order to support running the Casper tests while a Zulip @@ -176,6 +179,10 @@ def transform_url(protocol, path, query, target_port, target_host): # type: (str, str, str, int, str) -> str # generate url with target host host = ":".join((target_host, str(target_port))) + # Here we are going to rewrite the path a bit so that it is in parity with + # what we will have for production + if path.startswith('/thumbor'): + path = path[len('/thumbor'):] newpath = urlunparse((protocol, host, path, '', query, '')) return newpath @@ -353,6 +360,10 @@ class TornadoHandler(CombineHandler): target_port = tornado_port +class ThumborHandler(CombineHandler): + target_port = thumbor_port + + class Application(web.Application): def __init__(self, enable_logging=False): # type: (bool) -> None @@ -361,6 +372,7 @@ class Application(web.Application): (r"/api/v1/events.*", TornadoHandler), (r"/webpack.*", WebPackHandler), (r"/sockjs.*", TornadoHandler), + (r"/thumbor.*", ThumborHandler), (r"/.*", DjangoHandler) ] super().__init__(handlers, enable_logging=enable_logging) @@ -386,7 +398,8 @@ def shutdown_handler(*args, **kwargs): # log which services/ports will be started print("Starting Zulip services on ports: web proxy: {},".format(proxy_port), - "Django: {}, Tornado: {}".format(django_port, tornado_port), end='') + "Django: {}, Tornado: {}, Thumbor: {}".format(django_port, tornado_port, thumbor_port), + end='') if options.test: print("") # no webpack for --test else: diff --git a/tools/setup/setup_venvs.py b/tools/setup/setup_venvs.py index 52bd100a5f..f43da67bc5 100755 --- a/tools/setup/setup_venvs.py +++ b/tools/setup/setup_venvs.py @@ -13,12 +13,15 @@ from scripts.lib.zulip_tools import run, subprocess_text_output VENV_PATH = "/srv/zulip-py3-venv" DEV_REQS_FILE = os.path.join(ZULIP_PATH, "requirements", "dev.txt") +THUMBOR_REQS_FILE = os.path.join(ZULIP_PATH, "requirements", "thumbor.txt") def main() -> None: # Get the correct Python interpreter. If we don't do this and use # `virtualenv -p python3` to create the venv in Travis, the venv # starts referring to the system Python interpreter. python_interpreter = subprocess_text_output(['which', 'python3']) + setup_virtualenv("/srv/zulip-thumbor-venv", THUMBOR_REQS_FILE, + patch_activate_script=True) setup_virtualenv(VENV_PATH, DEV_REQS_FILE, patch_activate_script=True, virtualenv_args=['-p', python_interpreter]) diff --git a/version.py b/version.py index f13f07edb1..6a4f7fc237 100644 --- a/version.py +++ b/version.py @@ -8,4 +8,4 @@ ZULIP_VERSION = "1.7.1+git" # Typically, adding a dependency only requires a minor version bump, and # removing a dependency requires a major version bump. -PROVISION_VERSION = '14.5' +PROVISION_VERSION = '14.6' diff --git a/zproject/settings.py b/zproject/settings.py index a49dfb279e..e46edd561e 100644 --- a/zproject/settings.py +++ b/zproject/settings.py @@ -179,6 +179,7 @@ DEFAULT_SETTINGS = { 'REDIS_PORT': 6379, 'REMOTE_POSTGRES_HOST': '', 'REMOTE_POSTGRES_SSLMODE': '', + 'THUMBOR_HOST': '', # ToS/Privacy templates 'PRIVACY_POLICY': None, diff --git a/zthumbor/__init__.py b/zthumbor/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/zthumbor/loaders/__init__.py b/zthumbor/loaders/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/zthumbor/loaders/helpers.py b/zthumbor/loaders/helpers.py new file mode 100644 index 0000000000..b7d80cc3e3 --- /dev/null +++ b/zthumbor/loaders/helpers.py @@ -0,0 +1,85 @@ +from __future__ import absolute_import + +import os +import sys +import hmac +import time +import base64 +from hashlib import sha1 +from six.moves.urllib.parse import urlparse, parse_qs +from typing import Any, AnyStr, Dict, List, Optional, Text, Union + +if False: + from thumbor.context import Context + +ZULIP_PATH = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath('__file__')))) +sys.path.append(ZULIP_PATH) + +# Piece of code below relating to secrets conf has been duplicated with that of +# django settings in zproject/settings.py +import six.moves.configparser + +DEPLOY_ROOT = os.path.join(os.path.realpath(os.path.dirname(__file__)), '..', '..') + +config_file = six.moves.configparser.RawConfigParser() +config_file.read("/etc/zulip/zulip.conf") + +# Whether this instance of Zulip is running in a production environment. +PRODUCTION = config_file.has_option('machine', 'deploy_type') +DEVELOPMENT = not PRODUCTION + +secrets_file = six.moves.configparser.RawConfigParser() +if PRODUCTION: + secrets_file.read("/etc/zulip/zulip-secrets.conf") +else: + secrets_file.read(os.path.join(DEPLOY_ROOT, "zproject/dev-secrets.conf")) + +def get_secret(key): + # type: (str) -> Any + if secrets_file.has_option('secrets', key): + return secrets_file.get('secrets', key) + return None + +THUMBOR_EXTERNAL_TYPE = 'external' +THUMBOR_S3_TYPE = 's3' +THUMBOR_LOCAL_FILE_TYPE = 'local_file' + +def force_text(s, encoding='utf-8'): + # type: (Union[Text, bytes], str) -> Text + """converts a string to a text string""" + if isinstance(s, Text): + return s + elif isinstance(s, bytes): + return s.decode(encoding) + else: + raise TypeError("force_text expects a string type") + +def get_sign_hash(raw, key): + # type: (Text, Text) -> Text + hashed = hmac.new(key.encode('utf-8'), raw.encode('utf-8'), sha1) + return base64.b64encode(hashed.digest()).decode() + +def get_url_params(url): + # type: (Text) -> Dict[str, Any] + data = parse_qs(urlparse(url).query) + return {k: v[0] for k, v in data.items() if v} + +def sign_is_valid(url, context): + # type: (str, Context) -> bool + size = '{0}x{1}'.format(context.request.width, context.request.height) + data = parse_qs(urlparse(url).query) + source_type = data.get('source_type', [''])[0] + sign = data.get('sign', [''])[0] + if not source_type or not sign: + return False + url_path = url.rsplit('?', 1)[0] + if url_path.startswith('files/'): + url_path = url_path.split('/', 1)[1] + raw = u'_'.join([ + force_text(url_path), + force_text(size), + force_text(source_type), + ]) + if sign == get_sign_hash(raw, get_secret('thumbor_key')): + return True + return False diff --git a/zthumbor/loaders/zloader.py b/zthumbor/loaders/zloader.py new file mode 100644 index 0000000000..d107601d3d --- /dev/null +++ b/zthumbor/loaders/zloader.py @@ -0,0 +1,44 @@ +from __future__ import absolute_import + +from six.moves import urllib +from tornado.concurrent import return_future +from thumbor.loaders import LoaderResult, file_loader, http_loader +from tc_aws.loaders import s3_loader +from thumbor.context import Context +from .helpers import ( + get_url_params, sign_is_valid, THUMBOR_S3_TYPE, THUMBOR_LOCAL_FILE_TYPE, + THUMBOR_EXTERNAL_TYPE +) + +from typing import Any, Callable + +def get_not_found_result(): + # type: () -> LoaderResult + result = LoaderResult() + result.error = LoaderResult.ERROR_NOT_FOUND + result.successful = False + return result + +@return_future # type: ignore # This was giving mypy error for missing generic datatype? +def load(context, url, callback): + # type: (Context, str, Callable) -> None + url = urllib.parse.unquote(url) + url_params = get_url_params(url) + source_type = url_params.get('source_type') + + if not sign_is_valid(url, context) or source_type not in ( + THUMBOR_S3_TYPE, THUMBOR_LOCAL_FILE_TYPE, THUMBOR_EXTERNAL_TYPE): + callback(get_not_found_result()) + return + + url = url.rsplit('?', 1)[0] + if source_type == THUMBOR_S3_TYPE: + s3_loader.load(context, url, callback) + elif source_type == THUMBOR_LOCAL_FILE_TYPE: + file_loader.load(context, url, callback) + elif source_type == THUMBOR_EXTERNAL_TYPE: + http_loader.load_sync( + context, + url, + callback, + normalize_url_func=http_loader._normalize_url) diff --git a/zthumbor/thumbor.conf b/zthumbor/thumbor.conf new file mode 100644 index 0000000000..ad657d6777 --- /dev/null +++ b/zthumbor/thumbor.conf @@ -0,0 +1,695 @@ +import os +import sys +import subprocess + + +ZULIP_PATH = os.path.dirname(os.path.abspath('__file__')) + +sys.path.append(ZULIP_PATH) + +os.environ['AWS_ACCESS_KEY_ID'] = os.environ.get('S3_KEY') or '' +os.environ['AWS_SECRET_ACCESS_KEY'] = os.environ.get('S3_SECRET_KEY') or '' + +def read_zulip_settings_variable(variable_name): + # This is a very expensive function since this results in loading entire + # web app to get the settings. We currently use it to only once get the + # LOCAL_UPLOADS_DIR setting from django on thumbor startup. + # In future, we should be careful to use this else where and try to remove + # this use as well. + script = os.path.join(ZULIP_PATH, 'scripts', 'get-django-setting') + proc = subprocess.Popen([script, variable_name], stdout=subprocess.PIPE) + output = proc.stdout.read() + try: + return eval(output) + except Exception: + return output.strip() + + +################################# File Loader ################################## + +## The root path where the File Loader will try to find images +LOCAL_UPLOADS_DIR = read_zulip_settings_variable('LOCAL_UPLOADS_DIR') +if os.path.isabs(LOCAL_UPLOADS_DIR): + FILE_LOADER_ROOT_PATH = LOCAL_UPLOADS_DIR +else: + FILE_LOADER_ROOT_PATH = os.path.join(ZULIP_PATH, LOCAL_UPLOADS_DIR) + +################################################################################ + +IS_LOCAL_STORAGE = bool(LOCAL_UPLOADS_DIR) + +################################### Logging #################################### + +## Logging configuration as json +## Defaults to: None +#THUMBOR_LOG_CONFIG = None + +## Log Format to be used by thumbor when writing log messages. +## Defaults to: '%(asctime)s %(name)s:%(levelname)s %(message)s' +#THUMBOR_LOG_FORMAT = '%(asctime)s %(name)s:%(levelname)s %(message)s' + +## Date Format to be used by thumbor when writing log messages. +## Defaults to: '%Y-%m-%d %H:%M:%S' +#THUMBOR_LOG_DATE_FORMAT = '%Y-%m-%d %H:%M:%S' + +################################################################################ + + +################################### Imaging #################################### + +## Max width in pixels for images read or generated by thumbor +## Defaults to: 0 +#MAX_WIDTH = 0 + +## Max height in pixels for images read or generated by thumbor +## Defaults to: 0 +#MAX_HEIGHT = 0 + +## Max pixel count for images read by thumbor +## Defaults to: 75000000.0 +#MAX_PIXELS = 75000000.0 + +## Min width in pixels for images read or generated by thumbor +## Defaults to: 1 +#MIN_WIDTH = 1 + +## Min width in pixels for images read or generated by thumbor +## Defaults to: 1 +#MIN_HEIGHT = 1 + +## Allowed domains for the http loader to download. These are regular +## expressions. +## Defaults to: # [ +# ] + +#ALLOWED_SOURCES = # [ +# ] + + +## Quality index used for generated JPEG images +## Defaults to: 80 +#QUALITY = 80 + +## Exports JPEG images with the `progressive` flag set. +## Defaults to: True +#PROGRESSIVE_JPEG = True + +## Specify subsampling behavior for Pillow (see `subsampling` in +## http://pillow.readthedocs.org/en/latest/handbook/image-file- +## formats.html#jpeg).Be careful to use int for 0,1,2 and string for "4:4:4" +## notation. Will ignore `quality`. Using `keep` will copy the original file's +## subsampling. +## Defaults to: None +#PILLOW_JPEG_SUBSAMPLING = None + +## Specify quantization tables for Pillow (see `qtables` in +## http://pillow.readthedocs.org/en/latest/handbook/image-file- +## formats.html#jpeg). Will ignore `quality`. Using `keep` will copy the +## original file's qtables. +## Defaults to: None +#PILLOW_JPEG_QTABLES = None + +## Quality index used for generated WebP images. If not set (None) the same level +## of JPEG quality will be used. +## Defaults to: None +#WEBP_QUALITY = None + +## Specifies whether WebP format should be used automatically if the request +## accepts it (via Accept header) +## Defaults to: False +#AUTO_WEBP = False + +## Specify the ratio between 1in and 1px for SVG images. This is only used +## whenrasterizing SVG images having their size units in cm or inches. +## Defaults to: 150 +#SVG_DPI = 150 + +## Max AGE sent as a header for the image served by thumbor in seconds +## Defaults to: 86400 +#MAX_AGE = 86400 + +## Indicates the Max AGE header in seconds for temporary images (images with +## failed smart detection) +## Defaults to: 0 +#MAX_AGE_TEMP_IMAGE = 0 + +## Indicates whether thumbor should rotate images that have an Orientation EXIF +## header +## Defaults to: False +#RESPECT_ORIENTATION = False + +## Ignore errors during smart detections and return image as a temp image (not +## saved in result storage and with MAX_AGE_TEMP_IMAGE age) +## Defaults to: False +#IGNORE_SMART_ERRORS = False + +## Sends If-Modified-Since & Last-Modified headers; requires support from result +## storage +## Defaults to: False +#SEND_IF_MODIFIED_LAST_MODIFIED_HEADERS = False + +## Preserves exif information in generated images. Increases image size in +## kbytes, use with caution. +## Defaults to: False +#PRESERVE_EXIF_INFO = False + +## Indicates whether thumbor should enable the EXPERIMENTAL support for animated +## gifs. +## Defaults to: True +#ALLOW_ANIMATED_GIFS = True + +## Indicates whether thumbor should use gifsicle engine. Please note that smart +## cropping and filters are not supported for gifs using gifsicle (but won't +## give an error). +## Defaults to: False +USE_GIFSICLE_ENGINE = True + +## Indicates whether thumbor should enable blacklist functionality to prevent +## processing certain images. +## Defaults to: False +#USE_BLACKLIST = False + +## Size of the thread pool used for image transformations. The default value is +## 0 (don't use a threadpoool. Increase this if you are seeing your IOLoop +## getting blocked (often indicated by your upstream HTTP requests timing out) +## Defaults to: 0 +#ENGINE_THREADPOOL_SIZE = 0 + +################################################################################ + + +################################ Extensibility ################################# + +## The metrics backend thumbor should use to measure internal actions. This must +## be the full name of a python module (python must be able to import it) +## Defaults to: 'thumbor.metrics.logger_metrics' +#METRICS = 'thumbor.metrics.logger_metrics' + +## The loader thumbor should use to load the original image. This must be the +## full name of a python module (python must be able to import it) +## Defaults to: 'thumbor.loaders.http_loader' +LOADER = 'zthumbor.loaders.zloader' + +## The file storage thumbor should use to store original images. This must be the +## full name of a python module (python must be able to import it) +## Defaults to: 'thumbor.storages.file_storage' +if IS_LOCAL_STORAGE: + STORAGE = 'thumbor.storages.file_storage' +else: + STORAGE = 'tc_aws.storages.s3_storage' + +## The result storage thumbor should use to store generated images. This must be +## the full name of a python module (python must be able to import it) +## Defaults to: None +if IS_LOCAL_STORAGE: + RESULT_STORAGE = 'thumbor.result_storages.file_storage' +else: + RESULT_STORAGE = 'tc_aws.result_storages.s3_storage' + +## The imaging engine thumbor should use to perform image operations. This must +## be the full name of a python module (python must be able to import it) +## Defaults to: 'thumbor.engines.pil' +#ENGINE = 'thumbor.engines.pil' + +## The gif engine thumbor should use to perform image operations. This must be +## the full name of a python module (python must be able to import it) +## Defaults to: 'thumbor.engines.gif' +#GIF_ENGINE = 'thumbor.engines.gif' + +## The url signer thumbor should use to verify url signatures.This must be the +## full name of a python module (python must be able to import it) +## Defaults to: 'thumbor.url_signers.base64_hmac_sha1' +#URL_SIGNER = 'thumbor.url_signers.base64_hmac_sha1' + +################################################################################ + + +################################### Security ################################### + +## The security key thumbor uses to sign image URLs +## Defaults to: 'MY_SECURE_KEY' +#SECURITY_KEY = 'MY_SECURE_KEY' + +## Indicates if the /unsafe URL should be available +## Defaults to: True +#ALLOW_UNSAFE_URL = True + +## Indicates if encrypted (old style) URLs should be allowed +## Defaults to: True +#ALLOW_OLD_URLS = True + +################################################################################ + + +##################################### HTTP ##################################### + +## Enables automatically generated etags +## Defaults to: True +#ENABLE_ETAGS = True + +################################################################################ + + +################################### Storage #################################### + +## Set maximum id length for images when stored +## Defaults to: 32 +#MAX_ID_LENGTH = 32 + +################################################################################ + + +################################### Metrics #################################### + +## Host to send statsd instrumentation to +## Defaults to: None +#STATSD_HOST = None + +## Port to send statsd instrumentation to +## Defaults to: 8125 +#STATSD_PORT = 8125 + +## Prefix for statsd +## Defaults to: None +#STATSD_PREFIX = None + +################################################################################ + +################################# HTTP Loader ################################## + +## The maximum number of seconds libcurl can take to connect to an image being +## loaded +## Defaults to: 5 +#HTTP_LOADER_CONNECT_TIMEOUT = 5 + +## The maximum number of seconds libcurl can take to download an image +## Defaults to: 20 +#HTTP_LOADER_REQUEST_TIMEOUT = 20 + +## Indicates whether libcurl should follow redirects when downloading an image +## Defaults to: True +#HTTP_LOADER_FOLLOW_REDIRECTS = True + +## Indicates the number of redirects libcurl should follow when downloading an +## image +## Defaults to: 5 +#HTTP_LOADER_MAX_REDIRECTS = 5 + +## The maximum number of simultaneous HTTP connections the loader can make before +## queuing +## Defaults to: 10 +#HTTP_LOADER_MAX_CLIENTS = 10 + +## Indicates whether thumbor should forward the user agent of the requesting user +## Defaults to: False +#HTTP_LOADER_FORWARD_USER_AGENT = False + +## Default user agent for thumbor http loader requests +## Defaults to: 'Thumbor/6.1.5' +#HTTP_LOADER_DEFAULT_USER_AGENT = 'Thumbor/6.1.5' + +## The proxy host needed to load images through +## Defaults to: None +#HTTP_LOADER_PROXY_HOST = None + +## The proxy port for the proxy host +## Defaults to: None +#HTTP_LOADER_PROXY_PORT = None + +## The proxy username for the proxy host +## Defaults to: None +#HTTP_LOADER_PROXY_USERNAME = None + +## The proxy password for the proxy host +## Defaults to: None +#HTTP_LOADER_PROXY_PASSWORD = None + +## The filename of CA certificates in PEM format +## Defaults to: None +#HTTP_LOADER_CA_CERTS = None + +## The filename for client SSL key +## Defaults to: None +#HTTP_LOADER_CLIENT_KEY = None + +## The filename for client SSL certificate +## Defaults to: None +#HTTP_LOADER_CLIENT_CERT = None + +## If the CurlAsyncHTTPClient should be used +## Defaults to: False +#HTTP_LOADER_CURL_ASYNC_HTTP_CLIENT = False + +################################################################################ + + +################################# File Storage ################################# + +## Expiration in seconds for the images in the File Storage. Defaults to one +## month +## Defaults to: 2592000 +#STORAGE_EXPIRATION_SECONDS = 2592000 + +## Indicates whether thumbor should store the signing key for each image in the +## file storage. This allows the key to be changed and old images to still be +## properly found +## Defaults to: False +#STORES_CRYPTO_KEY_FOR_EACH_IMAGE = False + +## The root path where the File Storage will try to find images +## Defaults to: '/tmp/thumbor/storage' +#FILE_STORAGE_ROOT_PATH = '/tmp/thumbor/storage' + +################################################################################ + + +#################################### Upload #################################### + +## Max size in Kb for images uploaded to thumbor +## Aliases: MAX_SIZE +## Defaults to: 0 +#UPLOAD_MAX_SIZE = 0 + +## Indicates whether thumbor should enable File uploads +## Aliases: ENABLE_ORIGINAL_PHOTO_UPLOAD +## Defaults to: False +#UPLOAD_ENABLED = False + +## The type of storage to store uploaded images with +## Aliases: ORIGINAL_PHOTO_STORAGE +## Defaults to: 'thumbor.storages.file_storage' +#UPLOAD_PHOTO_STORAGE = 'thumbor.storages.file_storage' + +## Indicates whether image deletion should be allowed +## Aliases: ALLOW_ORIGINAL_PHOTO_DELETION +## Defaults to: False +#UPLOAD_DELETE_ALLOWED = False + +## Indicates whether image overwrite should be allowed +## Aliases: ALLOW_ORIGINAL_PHOTO_PUTTING +## Defaults to: False +#UPLOAD_PUT_ALLOWED = False + +## Default filename for image uploaded +## Defaults to: 'image' +#UPLOAD_DEFAULT_FILENAME = 'image' + +################################################################################ + + +############################### Memcache Storage ############################### + +## List of Memcache storage server hosts +## Defaults to: # [ +# 'localhost:11211', +# ] + +#MEMCACHE_STORAGE_SERVERS = # [ +# 'localhost:11211', +# ] + + +################################################################################ + + +################################ Mixed Storage ################################# + +## Mixed Storage file storage. This must be the full name of a python module +## (python must be able to import it) +## Defaults to: 'thumbor.storages.no_storage' +#MIXED_STORAGE_FILE_STORAGE = 'thumbor.storages.no_storage' + +## Mixed Storage signing key storage. This must be the full name of a python +## module (python must be able to import it) +## Defaults to: 'thumbor.storages.no_storage' +#MIXED_STORAGE_CRYPTO_STORAGE = 'thumbor.storages.no_storage' + +## Mixed Storage detector information storage. This must be the full name of a +## python module (python must be able to import it) +## Defaults to: 'thumbor.storages.no_storage' +#MIXED_STORAGE_DETECTOR_STORAGE = 'thumbor.storages.no_storage' + +################################################################################ + + +##################################### Meta ##################################### + +## The callback function name that should be used by the META route for JSONP +## access +## Defaults to: None +#META_CALLBACK_NAME = None + +################################################################################ + + +################################## Detection ################################### + +## List of detectors that thumbor should use to find faces and/or features. All +## of them must be full names of python modules (python must be able to import +## it) +## Defaults to: # [ +# ] + +#DETECTORS = # [ +# ] + + +## The cascade file that opencv will use to detect faces. +## Defaults to: 'haarcascade_frontalface_alt.xml' +#FACE_DETECTOR_CASCADE_FILE = 'haarcascade_frontalface_alt.xml' + +## The cascade file that opencv will use to detect glasses. +## Defaults to: 'haarcascade_eye_tree_eyeglasses.xml' +#GLASSES_DETECTOR_CASCADE_FILE = 'haarcascade_eye_tree_eyeglasses.xml' + +## The cascade file that opencv will use to detect profile faces. +## Defaults to: 'haarcascade_profileface.xml' +#PROFILE_DETECTOR_CASCADE_FILE = 'haarcascade_profileface.xml' + +################################################################################ + + +################################## Optimizers ################################## + +## List of optimizers that thumbor will use to optimize images +## Defaults to: # [ +# ] + +#OPTIMIZERS = # [ +# ] + + +## Path for the jpegtran binary +## Defaults to: '/usr/bin/jpegtran' +#JPEGTRAN_PATH = '/usr/bin/jpegtran' + +## Path for the ffmpeg binary used to generate gifv(h.264) +## Defaults to: '/usr/local/bin/ffmpeg' +#FFMPEG_PATH = '/usr/local/bin/ffmpeg' + +################################################################################ + + +################################### Filters #################################### + +## List of filters that thumbor will allow to be used in generated images. All of +## them must be full names of python modules (python must be able to import +## it) +## Defaults to: # [ +# 'thumbor.filters.brightness', +# 'thumbor.filters.colorize', +# 'thumbor.filters.contrast', +# 'thumbor.filters.rgb', +# 'thumbor.filters.round_corner', +# 'thumbor.filters.quality', +# 'thumbor.filters.noise', +# 'thumbor.filters.watermark', +# 'thumbor.filters.equalize', +# 'thumbor.filters.fill', +# 'thumbor.filters.sharpen', +# 'thumbor.filters.strip_icc', +# 'thumbor.filters.frame', +# 'thumbor.filters.grayscale', +# 'thumbor.filters.rotate', +# 'thumbor.filters.format', +# 'thumbor.filters.max_bytes', +# 'thumbor.filters.convolution', +# 'thumbor.filters.blur', +# 'thumbor.filters.extract_focal', +# 'thumbor.filters.focal', +# 'thumbor.filters.no_upscale', +# 'thumbor.filters.saturation', +# 'thumbor.filters.max_age', +# 'thumbor.filters.curve', +# ] + +#FILTERS = # [ +# 'thumbor.filters.brightness', +# 'thumbor.filters.colorize', +# 'thumbor.filters.contrast', +# 'thumbor.filters.rgb', +# 'thumbor.filters.round_corner', +# 'thumbor.filters.quality', +# 'thumbor.filters.noise', +# 'thumbor.filters.watermark', +# 'thumbor.filters.equalize', +# 'thumbor.filters.fill', +# 'thumbor.filters.sharpen', +# 'thumbor.filters.strip_icc', +# 'thumbor.filters.frame', +# 'thumbor.filters.grayscale', +# 'thumbor.filters.rotate', +# 'thumbor.filters.format', +# 'thumbor.filters.max_bytes', +# 'thumbor.filters.convolution', +# 'thumbor.filters.blur', +# 'thumbor.filters.extract_focal', +# 'thumbor.filters.focal', +# 'thumbor.filters.no_upscale', +# 'thumbor.filters.saturation', +# 'thumbor.filters.max_age', +# 'thumbor.filters.curve', +# ] + + +################################################################################ + + +################################ Result Storage ################################ + +## Expiration in seconds of generated images in the result storage +## Defaults to: 0 +#RESULT_STORAGE_EXPIRATION_SECONDS = 0 + +## Path where the Result storage will store generated images +## Defaults to: '/tmp/thumbor/result_storage' +RESULT_STORAGE_FILE_STORAGE_ROOT_PATH = os.path.join(FILE_LOADER_ROOT_PATH, 'thumbnails') + +## Indicates whether unsafe requests should also be stored in the Result Storage +## Defaults to: False +RESULT_STORAGE_STORES_UNSAFE = True + +################################################################################ + + +############################ Queued Redis Detector ############################# + +## Server host for the queued redis detector +## Defaults to: 'localhost' +#REDIS_QUEUE_SERVER_HOST = 'localhost' + +## Server port for the queued redis detector +## Defaults to: 6379 +#REDIS_QUEUE_SERVER_PORT = 6379 + +## Server database index for the queued redis detector +## Defaults to: 0 +#REDIS_QUEUE_SERVER_DB = 0 + +## Server password for the queued redis detector +## Defaults to: None +#REDIS_QUEUE_SERVER_PASSWORD = None + +################################################################################ + + +############################# Queued SQS Detector ############################## + +## AWS key id +## Defaults to: None +#SQS_QUEUE_KEY_ID = None + +## AWS key secret +## Defaults to: None +#SQS_QUEUE_KEY_SECRET = None + +## AWS SQS region +## Defaults to: 'us-east-1' +#SQS_QUEUE_REGION = 'us-east-1' + +################################################################################ + + +#################################### Errors #################################### + +## This configuration indicates whether thumbor should use a custom error +## handler. +## Defaults to: False +#USE_CUSTOM_ERROR_HANDLING = False + +## Error reporting module. Needs to contain a class called ErrorHandler with a +## handle_error(context, handler, exception) method. +## Defaults to: 'thumbor.error_handlers.sentry' +#ERROR_HANDLER_MODULE = 'thumbor.error_handlers.sentry' + +## File of error log as json +## Defaults to: None +#ERROR_FILE_LOGGER = None + +## File of error log name is parametrized with context attribute +## Defaults to: False +#ERROR_FILE_NAME_USE_CONTEXT = False + +################################################################################ + + +############################### Errors - Sentry ################################ + +## Sentry thumbor project dsn. i.e.: http://5a63d58ae7b94f1dab3dee740b301d6a:73ee +## a45d3e8649239a973087e8f21f98@localhost:9000/2 +## Defaults to: '' +#SENTRY_DSN_URL = '' + +################################################################################ + + +################################### General #################################### + +## Custom app class to override ThumborServiceApp. This config value is +## overridden by the -a command-line parameter. +## Defaults to: 'thumbor.app.ThumborServiceApp' +#APP_CLASS = 'thumbor.app.ThumborServiceApp' + +################################################################################ + + +################################### AWS S3 settings ############################ +# TC_AWS_REGION= # AWS Region + +# TC_AWS_STORAGE_BUCKET= # S3 bucket for Storage +# TC_AWS_STORAGE_ROOT_PATH= # S3 path prefix for Storage bucket + +# TC_AWS_LOADER_BUCKET= #S3 bucket for loader +# TC_AWS_LOADER_ROOT_PATH= # S3 path prefix for Loader bucket + +# TC_AWS_RESULT_STORAGE_BUCKET= # S3 bucket for result Storage +# TC_AWS_RESULT_STORAGE_ROOT_PATH= # S3 path prefix for Result storage bucket + +TC_AWS_MAX_RETRY=0 # Max retries for get image from S3 Bucket. Default is 0 + +# put data into S3 using the Server Side Encryption functionality to +# encrypt data at rest in S3 +# https://aws.amazon.com/about-aws/whats-new/2011/10/04/amazon-s3-announces-server-side-encryption-support/ +TC_AWS_STORAGE_SSE=False + +# put data into S3 with Reduced Redundancy +# https://aws.amazon.com/about-aws/whats-new/2010/05/19/announcing-amazon-s3-reduced-redundancy-storage/ +TC_AWS_STORAGE_RRS=False + + +# Enable HTTP Loader as well? +# This would allow you to load watermarks in over your images dynamically through a URI +# E.g. +# http://your-thumbor.com/unsafe/filters:watermark(http://example.com/watermark.png,0,0,50)/s3_bucket/photo.jpg +TC_AWS_ENABLE_HTTP_LOADER=False + +TC_AWS_ALLOWED_BUCKETS=False # List of allowed bucket to be requested +TC_AWS_STORE_METADATA=False # Store result with metadata (for instance content-type) +################################################################################ + + +# You can override settings in zthumbor/thumbor_local_settings.py +try: + from zthumbor.thumbor_local_settings import * +except ImportError: + pass