[FIX] website: move support for ir.attachment resources to web module

Commit 540b753bf8 introduced
support for resources stored as ir.attachment records in
asset bundles too.
This is specifically useful for customizations.

However the HTTP route for reaching those resources
when they are *not* in a bundle was originally created
in the `website` module (as a special handling for
404 requests)

This means that these dynamic resources would only
be partially supported when `website` is not installed,
causing various problems:
 - missing resources in debug mode where bundles are skipped
 - errors when trying to define new client-side Qweb templates
   via XML resources - which are loaded with a direct request
 - ...

This commit moves back the supporting code to the web module.

The `mimetype` column is not present in ir.attachment without
the `website` module, but sniffing it based on the attachment
name works fine at serving time too.

Closes #6002
This commit is contained in:
FalcoBolger 2015-03-26 11:44:01 +01:00 committed by Olivier Dony
parent c58121e8f1
commit 95b921d0f7
2 changed files with 39 additions and 34 deletions

View File

@ -1,6 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import datetime
import hashlib
import logging import logging
import os import os
import re import re
@ -76,7 +74,7 @@ class ir_http(orm.AbstractModel):
if self.geo_ip_resolver and request.httprequest.remote_addr: if self.geo_ip_resolver and request.httprequest.remote_addr:
record = self.geo_ip_resolver.record_by_addr(request.httprequest.remote_addr) or {} record = self.geo_ip_resolver.record_by_addr(request.httprequest.remote_addr) or {}
request.session['geoip'] = record request.session['geoip'] = record
if request.website_enabled: if request.website_enabled:
try: try:
if func: if func:
@ -163,38 +161,7 @@ class ir_http(orm.AbstractModel):
path += '?' + request.httprequest.query_string path += '?' + request.httprequest.query_string
return werkzeug.utils.redirect(path, code=301) return werkzeug.utils.redirect(path, code=301)
def _serve_attachment(self):
domain = [('type', '=', 'binary'), ('url', '=', request.httprequest.path)]
attach = self.pool['ir.attachment'].search_read(request.cr, openerp.SUPERUSER_ID, domain, ['__last_update', 'datas', 'mimetype'], context=request.context)
if attach:
wdate = attach[0]['__last_update']
datas = attach[0]['datas']
response = werkzeug.wrappers.Response()
server_format = openerp.tools.misc.DEFAULT_SERVER_DATETIME_FORMAT
try:
response.last_modified = datetime.datetime.strptime(wdate, server_format + '.%f')
except ValueError:
# just in case we have a timestamp without microseconds
response.last_modified = datetime.datetime.strptime(wdate, server_format)
response.set_etag(hashlib.sha1(datas).hexdigest())
response.make_conditional(request.httprequest)
if response.status_code == 304:
return response
response.mimetype = attach[0]['mimetype'] or 'application/octet-stream'
response.data = datas.decode('base64')
return response
def _handle_exception(self, exception, code=500): def _handle_exception(self, exception, code=500):
# This is done first as the attachment path may
# not match any HTTP controller, so the request
# may not be website-enabled.
attach = self._serve_attachment()
if attach:
return attach
is_website_request = bool(getattr(request, 'website_enabled', False) and request.website) is_website_request = bool(getattr(request, 'website_enabled', False) and request.website)
if not is_website_request: if not is_website_request:
# Don't touch non website requests exception handling # Don't touch non website requests exception handling

View File

@ -1,10 +1,14 @@
#---------------------------------------------------------- #----------------------------------------------------------
# ir_http modular http routing # ir_http modular http routing
#---------------------------------------------------------- #----------------------------------------------------------
import datetime
import hashlib
import logging import logging
import mimetypes
import re import re
import sys import sys
import werkzeug
import werkzeug.exceptions import werkzeug.exceptions
import werkzeug.routing import werkzeug.routing
import werkzeug.urls import werkzeug.urls
@ -94,7 +98,41 @@ class ir_http(osv.AbstractModel):
raise openerp.exceptions.AccessDenied() raise openerp.exceptions.AccessDenied()
return auth_method return auth_method
def _serve_attachment(self):
domain = [('type', '=', 'binary'), ('url', '=', request.httprequest.path)]
attach = self.pool['ir.attachment'].search_read(
request.cr, openerp.SUPERUSER_ID, domain,
['__last_update', 'datas', 'datas_fname'],
context=request.context)
if attach:
wdate = attach[0]['__last_update']
datas = attach[0]['datas']
response = werkzeug.wrappers.Response()
server_format = openerp.tools.misc.DEFAULT_SERVER_DATETIME_FORMAT
try:
response.last_modified = datetime.datetime.strptime(wdate, server_format + '.%f')
except ValueError:
# just in case we have a timestamp without microseconds
response.last_modified = datetime.datetime.strptime(wdate, server_format)
response.set_etag(hashlib.sha1(datas).hexdigest())
response.make_conditional(request.httprequest)
if response.status_code == 304:
return response
response.mimetype = (mimetypes.guess_type(attach[0]['datas_fname'])[0] or
'application/octet-stream')
response.data = datas.decode('base64')
return response
def _handle_exception(self, exception): def _handle_exception(self, exception):
# This is done first as the attachment path may
# not match any HTTP controller.
attach = self._serve_attachment()
if attach:
return attach
# If handle_exception returns something different than None, it will be used as a response # If handle_exception returns something different than None, it will be used as a response
try: try:
return request._handle_exception(exception) return request._handle_exception(exception)