[IMP] conditional GET for concatenated JS and CSS files

bzr revid: xmo@openerp.com-20120210140021-uh5t5egr00dxdwr8
This commit is contained in:
Xavier Morel 2012-02-10 15:00:21 +01:00
parent af8864d571
commit 10f215ef35
1 changed files with 82 additions and 32 deletions

View File

@ -8,6 +8,7 @@ import itertools
import logging
import operator
import datetime
import hashlib
import os
import re
import simplejson
@ -20,6 +21,7 @@ from cStringIO import StringIO
import babel.messages.pofile
import werkzeug.utils
import werkzeug.wrappers
try:
import xlwt
except ImportError:
@ -35,21 +37,22 @@ openerpweb = common.http
def concat_xml(file_list):
"""Concatenate xml files
return (concat,timestamp)
concat: concatenation of file content
timestamp: max(os.path.getmtime of file_list)
:param list(str) file_list: list of files to check
:returns: (concatenation_result, checksum)
:rtype: (str, str)
"""
checksum = hashlib.new('sha1')
if not file_list:
return '', None
return '', checksum.hexdigest()
root = None
files_timestamp = 0
for fname in file_list:
ftime = os.path.getmtime(fname)
if ftime > files_timestamp:
files_timestamp = ftime
xml = ElementTree.parse(fname).getroot()
with open(fname, 'rb') as fp:
contents = fp.read()
checksum.update(contents)
fp.seek(0)
xml = ElementTree.parse(fp).getroot()
if root is None:
root = ElementTree.Element(xml.tag)
@ -58,17 +61,21 @@ def concat_xml(file_list):
for child in xml.getchildren():
root.append(child)
return ElementTree.tostring(root, 'utf-8'), files_timestamp
return ElementTree.tostring(root, 'utf-8'), checksum.hexdigest()
def concat_files(file_list, reader=None, intersperse=""):
""" Concatenate file content
return (concat,timestamp)
concat: concatenation of file content, read by `reader`
timestamp: max(os.path.getmtime of file_list)
""" Concatenates contents of all provided files
:param list(str) file_list: list of files to check
:param function reader: reading procedure for each file
:param str intersperse: string to intersperse between file contents
:returns: (concatenation_result, checksum)
:rtype: (str, str)
"""
checksum = hashlib.new('sha1')
if not file_list:
return '', None
return '', checksum.hexdigest()
if reader is None:
def reader(f):
@ -76,15 +83,13 @@ def concat_files(file_list, reader=None, intersperse=""):
return fp.read()
files_content = []
files_timestamp = 0
for fname in file_list:
ftime = os.path.getmtime(fname)
if ftime > files_timestamp:
files_timestamp = ftime
contents = reader(fname)
checksum.update(contents)
files_content.append(contents)
files_content.append(reader(fname))
files_concat = intersperse.join(files_content)
return files_concat,files_timestamp
return files_concat, checksum.hexdigest()
html_template = """<!DOCTYPE html>
<html style="height: 100%%">
@ -150,10 +155,24 @@ class WebClient(openerpweb.Controller):
def qweblist(self, req, mods=None):
return self.manifest_list(req, mods, 'qweb')
def get_last_modified(self, files):
""" Returns the modification time of the most recently modified
file provided
:param list(str) files: names of files to check
:return: most recent modification time amongst the fileset
:rtype: datetime.datetime
"""
return max(datetime.datetime.fromtimestamp(os.path.getmtime(f))
for f in files)
@openerpweb.httprequest
def css(self, req, mods=None):
files = list(self.manifest_glob(req, mods, 'css'))
last_modified = self.get_last_modified(f[0] for f in files)
if req.httprequest.if_modified_since and req.httprequest.if_modified_since >= last_modified:
return werkzeug.wrappers.Response(status=304)
file_map = dict(files)
rx_import = re.compile(r"""@import\s+('|")(?!'|"|/|https?://)""", re.U)
@ -182,23 +201,54 @@ class WebClient(openerpweb.Controller):
)
return data
content,timestamp = concat_files((f[0] for f in files), reader)
# TODO use timestamp to set Last mofified date and E-tag
return req.make_response(content, [('Content-Type', 'text/css')])
content, checksum = concat_files((f[0] for f in files), reader)
if req.httprequest.if_none_match and checksum in req.httprequest.if_none_match:
return werkzeug.wrappers.Response(status=304)
response = req.make_response(content, [('Content-Type', 'text/css')])
response.cache_control.must_revalidate = True
response.cache_control.max_age = 0
response.last_modified = last_modified
response.set_etag(checksum)
return response
@openerpweb.httprequest
def js(self, req, mods=None):
files = [f[0] for f in self.manifest_glob(req, mods, 'js')]
content, timestamp = concat_files(files, intersperse=';')
# TODO use timestamp to set Last mofified date and E-tag
return req.make_response(content, [('Content-Type', 'application/javascript')])
last_modified = self.get_last_modified(files)
print 'last modified', last_modified
print 'if modified since', req.httprequest.if_modified_since
if req.httprequest.if_modified_since and req.httprequest.if_modified_since >= last_modified:
return werkzeug.wrappers.Response(status=304)
content, checksum = concat_files(files, intersperse=';')
if req.httprequest.if_none_match and checksum in req.httprequest.if_none_match:
return werkzeug.wrappers.Response(status=304)
resp = req.make_response(content, [('Content-Type', 'application/javascript')])
resp.cache_control.must_revalidate = True
resp.cache_control.max_age = 0
resp.last_modified = last_modified
resp.set_etag(checksum)
return resp
@openerpweb.httprequest
def qweb(self, req, mods=None):
files = [f[0] for f in self.manifest_glob(req, mods, 'qweb')]
content,timestamp = concat_xml(files)
# TODO use timestamp to set Last mofified date and E-tag
return req.make_response(content, [('Content-Type', 'text/xml')])
last_modified = self.get_last_modified(files)
if req.httprequest.if_modified_since and req.httprequest.if_modified_since >= last_modified:
return werkzeug.wrappers.Response(status=304)
content,checksum = concat_xml(files)
if req.httprequest.if_none_match and checksum in req.httprequest.if_none_match:
return werkzeug.wrappers.Response(status=304)
response = req.make_response(content, [('Content-Type', 'text/xml')])
response.cache_control.must_revalidate = True
response.cache_control.max_age = 0
response.last_modified = last_modified
response.set_etag(checksum)
return response
@openerpweb.httprequest