Skip to content

Commit 918aefe

Browse files
Nhat Vo VanNhat Vo Van
authored andcommitted
simple support
1 parent 7c64764 commit 918aefe

File tree

3 files changed

+73
-104
lines changed

3 files changed

+73
-104
lines changed

CHANGES.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
- 2016/04/28 -- Initial project
2-
- 2016/12/20 -- Support optimize all response
2+
- 2016/12/20 -- Support optimize all response
3+
- 2018/06/24 -- Remove unnecessary code

flask_optimize/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
__author__ = 'sunary'
22

33

4-
VERSION = '0.2.7'
4+
VERSION = '0.2.8'
55

66
from .optimize import FlaskOptimize

flask_optimize/optimize.py

Lines changed: 70 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
import sys
55
from htmlmin.main import minify
6-
from flask import request, Response, make_response, current_app, redirect, json, wrappers, url_for
6+
from flask import request, Response, make_response, current_app, json, wrappers
77
from functools import update_wrapper
88
import gzip
99
import time
@@ -22,120 +22,83 @@ class FlaskOptimize(object):
2222
_cache = {}
2323
_timestamp = {}
2424

25-
def __init__(self, app=None, config=None, config_update={}, redis=None):
26-
''' Global config for flask optimize foreach respond return type
25+
def __init__(self,
26+
app=None,
27+
config=None):
28+
"""
29+
Global config for flask optimize foreach respond return type
2730
Args:
2831
app: flask app object
2932
config: global configure values
30-
config_update: update into default configure
31-
redis: redis client store limit requests if you enable it
32-
'''
33+
"""
3334
if config is None:
34-
config = {'html': {'htmlmin': True, 'izip': True, 'cache': 'GET-84600'},
35-
'json': {'htmlmin': False, 'izip': True, 'cache': False},
36-
'text': {'htmlmin': False, 'izip': True, 'cache': 84600},
37-
'limit': [100, 60, 84600],
38-
'redirect_host': [],
39-
'exceed_msg': None}
40-
config.update(config_update)
35+
config = {
36+
'html': {'htmlmin': True, 'compress': True, 'cache': 'GET-84600'},
37+
'json': {'htmlmin': False, 'compress': True, 'cache': False},
38+
'text': {'htmlmin': False, 'compress': True, 'cache': 84600}
39+
}
4140

4241
self.config = config
43-
self.redis = redis
4442
self.app = app or current_app
4543

4644
def optimize(self,
4745
dtype='html',
4846
htmlmin=None,
49-
izip=None,
50-
cache=None,
51-
limit=False,
52-
redirect_host=True,
53-
exceed_msg=True):
54-
''' Flask optimize respond using minify html, zip content and mem cache.
47+
compress=None,
48+
cache=None):
49+
"""
50+
Flask optimize respond using minify html, zip content and mem cache.
5551
Elastic optimization and create Cross-site HTTP requests if respond is json
5652
Args:
57-
dtype: data type of response:
53+
dtype: response type:
5854
- `html` (default)
5955
- `text`
6056
- `json`
6157
htmlmin: minify html
62-
None is using global config, True is enable minify html
63-
izip: send content in zip format
64-
None is using global config, True is enable zip respond
58+
None (default): using global config,
59+
False: disable minify html
60+
True: enable minify html
61+
compress: send content in compress (gzip) format
62+
None (default): using global config,
63+
False: disable compress response,
64+
True: enable compress response
6565
cache: cache content in RAM
66-
None is using global config, False or 0 to disable cache,
67-
integer value to set time cache (seconds),
68-
or string format: 'METHOD-seconds' to select METHOD cache, eg: 'GET-3600'
69-
limit: limit requests for each windows and set time temporary ban
70-
True if you want using default value,
71-
using this format [requests, window, ban expire] to set value,
72-
False is disable it
73-
redirect_host: you have 2 or more domains and want redirect all to one
74-
True if you want using default value,
75-
using this format [['host1', 'host2], 'host_redirect'] to set value,
76-
False is disable it
77-
exceed_msg: return temporary ban content
78-
True if you want using default value,
66+
None (default): using global config,
67+
False: disable cache,
68+
string value: 'METHOD-seconds' to select METHOD and period cache, eg: 'GET-3600', 'GET|POST-600', ...
7969
Examples:
80-
@optimize(dtype='html', htmlmin=True, zip=True, cache='GET-84600')
81-
'''
70+
@optimize(dtype='html', htmlmin=True, compress=True, cache='GET-84600')
71+
"""
8272

8373
def _decorating_wrapper(func):
8474

8575
def _optimize_wrapper(*args, **kwargs):
86-
try:
87-
load_config = self.config[dtype]
88-
89-
htmlmin_arg = load_config['htmlmin'] if (htmlmin is None) else htmlmin
90-
izip_arg = load_config['izip'] if (izip is None) else izip
91-
cache_arg = load_config['cache'] if (cache is None) else cache
92-
93-
if isinstance(cache_arg, str) and request.method in cache_arg:
94-
cache_arg = int(cache_arg.split('-')[1])
95-
elif not isinstance(cache_arg, int):
96-
cache_arg = 0
97-
98-
limit_arg = self.config['limit'] if (limit is True) else limit
99-
redirect_host_arg = self.config['redirect_host'] if (redirect_host is True) else redirect_host
100-
exceed_msg_arg = self.config['exceed_msg'] if (exceed_msg is True) else exceed_msg
101-
except:
102-
raise Exception('Wrong input format')
103-
104-
# limit by ip
105-
if limit_arg and self.redis:
106-
limit_key = 'limitip-{}'.format(request.remote_addr)
107-
ban_key = 'banip-{}'.format(request.remote_addr)
108-
109-
times_requested = int(self.redis.get(limit_key) or '0')
110-
if times_requested >= limit_arg[0] or self.redis.get(ban_key):
111-
if times_requested >= limit_arg[0]:
112-
self.redis.delete(limit_key)
113-
self.redis.set(ban_key, 1)
114-
self.redis.expire(ban_key, limit_arg[2])
115-
116-
if self.config['exceed_msg']:
117-
return redirect(url_for(exceed_msg_arg))
118-
else:
119-
return self.crossdomain({'status_code': 429})
76+
# default values:
77+
is_htmlmin = False
78+
is_comress = False
79+
period_cache = 0
80+
81+
if self.config.get(dtype):
82+
is_htmlmin = self.config.get(dtype)['htmlmin'] if (htmlmin is None) else htmlmin
83+
is_comress = self.config.get(dtype)['compress'] if (compress is None) else compress
84+
cache_agrs = self.config.get(dtype)['cache'] if (cache is None) else cache
85+
86+
if cache is False or cache == 0:
87+
period_cache = 0
88+
elif isinstance(cache_agrs, (str, basestring)) and len(cache_agrs.split('-')) == 2:
89+
try:
90+
period_cache = int(cache_agrs.split('-')[1]) if (request.method in cache_agrs) else 0
91+
except (KeyError, ValueError):
92+
raise ValueError('Cache must be string with method and period cache split by "-"')
12093
else:
121-
self.redis.incr(limit_key, 1)
122-
self.redis.expire(limit_key, limit_arg[1])
94+
raise ValueError('Cache must be False or string with method and period cache split by "-"')
12395

124-
# redirect new host
125-
if redirect_host_arg:
126-
for host in redirect_host_arg[0]:
127-
if host in request.url_root:
128-
redirect_url = request.url
129-
redirect_url = redirect_url.replace(host, redirect_host_arg[1])
130-
return redirect(redirect_url)
96+
# init cached data
97+
now = time.time()
98+
key_cache = request.url
13199

132-
# find cached value
133-
if cache_arg:
134-
now = time.time()
135-
key_cache = request.url
136-
137-
if self._timestamp.get(key_cache, now) > now:
138-
return self._cache[key_cache]
100+
if self._timestamp.get(key_cache) > now:
101+
return self._cache[key_cache]
139102

140103
resp = func(*args, **kwargs)
141104

@@ -145,17 +108,17 @@ def _optimize_wrapper(*args, **kwargs):
145108
resp = self.crossdomain(resp)
146109

147110
# min html
148-
if htmlmin_arg:
111+
if is_htmlmin:
149112
resp = self.validate(self.minifier, resp)
150113

151-
# gzip
152-
if izip_arg:
153-
resp = self.validate(self.zipper, resp)
114+
# compress
115+
if is_comress:
116+
resp = self.validate(self.compress, resp)
154117

155118
# cache
156-
if cache_arg:
119+
if period_cache > 0:
157120
self._cache[key_cache] = resp
158-
self._timestamp[key_cache] = now + cache_arg
121+
self._timestamp[key_cache] = now + period_cache
159122

160123
return resp
161124

@@ -170,7 +133,7 @@ def validate(method, content):
170133
return method(content)
171134
elif isinstance(content, tuple):
172135
if len(content) < 2:
173-
raise Exception('Content must have larger 2 elements')
136+
raise TypeError('Content must have larger than 2 elements')
174137

175138
return method(content[0]), content[1]
176139

@@ -182,12 +145,15 @@ def minifier(content):
182145
content = unicode(content, 'utf-8')
183146

184147
return minify(content,
185-
remove_comments=True, reduce_empty_attributes=True, remove_optional_attribute_quotes=False)
148+
remove_comments=True,
149+
reduce_empty_attributes=True,
150+
remove_optional_attribute_quotes=False)
186151

187152
@staticmethod
188-
def zipper(content):
189-
''' Zip str, unicode content
190-
'''
153+
def compress(content):
154+
"""
155+
Compress str, unicode content using gzip
156+
"""
191157
resp = Response()
192158
if isinstance(content, Response):
193159
resp = content
@@ -216,8 +182,10 @@ def zipper(content):
216182

217183
@staticmethod
218184
def crossdomain(content):
219-
''' create Cross-site HTTP requests
220-
'''
185+
"""
186+
Create decorator Cross-site HTTP requests
187+
see more at: http://flask.pocoo.org/snippets/56/
188+
"""
221189
if isinstance(content, (dict, Response)):
222190
if isinstance(content, dict):
223191
content = json.jsonify(content)

0 commit comments

Comments
 (0)