Ejemplo n.º 1
0
 def test_mimetype_svg(self):
     content = base64.b64decode(SVG)
     mimetype = guess_mimetype(content, default='test')
     self.assertTrue(mimetype.startswith('image/svg'))
     # Tests that whitespace padded SVG are not detected as SVG
     mimetype = guess_mimetype(b"   " + content, default='test')
     self.assertNotIn("svg", mimetype)
Ejemplo n.º 2
0
 def _compute_mimetype(self, values):
     """ compute the mimetype of the given values
         :param values : dict of values to create or write an ir_attachment
         :return mime : string indicating the mimetype, or application/octet-stream by default
     """
     mimetype = None
     if values.get('mimetype'):
         mimetype = values['mimetype']
     if not mimetype and values.get('datas_fname'):
         mimetype = mimetypes.guess_type(values['datas_fname'])[0]
     if not mimetype and values.get('url'):
         mimetype = mimetypes.guess_type(values['url'])[0]
     if values.get('datas') and (not mimetype
                                 or mimetype == 'application/octet-stream'):
         mimetype = guess_mimetype(base64.b64decode(values['datas']))
     return mimetype or 'application/octet-stream'
Ejemplo n.º 3
0
    def _read_file(self, options):
        """ Dispatch to specific method to read file content, according to its mimetype or file type
            :param options : dict of reading options (quoting, separator, ...)
        """
        self.ensure_one()
        # guess mimetype from file content
        mimetype = guess_mimetype(self.file or b'')
        (file_extension, handler, req) = FILE_TYPE_DICT.get(mimetype, (None, None, None))
        if handler:
            try:
                return getattr(self, '_read_' + file_extension)(options)
            except Exception:
                _logger.warn("Failed to read file '%s' (transient id %d) using guessed mimetype %s", self.file_name or '<unknown>', self.id, mimetype)

        # try reading with user-provided mimetype
        (file_extension, handler, req) = FILE_TYPE_DICT.get(self.file_type, (None, None, None))
        if handler:
            try:
                return getattr(self, '_read_' + file_extension)(options)
            except Exception:
                _logger.warn("Failed to read file '%s' (transient id %d) using user-provided mimetype %s", self.file_name or '<unknown>', self.id, self.file_type)

        # fallback on file extensions as mime types can be unreliable (e.g.
        # software setting incorrect mime types, or non-installed software
        # leading to browser not sending mime types)
        if self.file_name:
            p, ext = os.path.splitext(self.file_name)
            if ext in EXTENSIONS:
                try:
                    return getattr(self, '_read_' + ext[1:])(options)
                except Exception:
                    _logger.warn("Failed to read file '%s' (transient id %s) using file extension", self.file_name, self.id)

        if req:
            raise ImportError(_("Unable to load \"{extension}\" file: requires Python module \"{modname}\"").format(extension=file_extension, modname=req))
        raise ValueError(_("Unsupported file format \"{}\", import only supports CSV, ODS, XLS and XLSX").format(self.file_type))
Ejemplo n.º 4
0
    def binary_content(cls, xmlid=None, model='ir.attachment', id=None, field='datas',
                       unique=False, filename=None, filename_field='datas_fname', download=False,
                       mimetype=None, default_mimetype='application/octet-stream',
                       access_token=None, related_id=None, access_mode=None, env=None):
        """ Get file, attachment or downloadable content

        If the ``xmlid`` and ``id`` parameter is omitted, fetches the default value for the
        binary field (via ``default_get``), otherwise fetches the field for
        that precise record.

        :param str xmlid: xmlid of the record
        :param str model: name of the model to fetch the binary from
        :param int id: id of the record from which to fetch the binary
        :param str field: binary field
        :param bool unique: add a max-age for the cache control
        :param str filename: choose a filename
        :param str filename_field: if not create an filename with model-id-field
        :param bool download: apply headers to download the file
        :param str mimetype: mintype of the field (for headers)
        :param related_id: the id of another record used for custom_check
        :param  access_mode: if truthy, will call custom_check to fetch the object that contains the binary.
        :param str default_mimetype: default mintype if no mintype found
        :param str access_token: optional token for unauthenticated access
                                 only available  for ir.attachment
        :param Environment env: by default use request.env
        :returns: (status, headers, content)
        """
        env = env or request.env
        # get object and content
        obj = None
        if xmlid:
            obj = cls._xmlid_to_obj(env, xmlid)
        elif id and model in env.registry:
            obj = env[model].browse(int(id))
        # obj exists
        if not obj or not obj.exists() or field not in obj:
            return (404, [], None)

        # access token grant access
        if model == 'ir.attachment' and access_token:
            obj = obj.sudo()
            if access_mode:
                if not cls._check_access_mode(env, id, access_mode, model, access_token=access_token,
                                             related_id=related_id):
                    return (403, [], None)
            elif not consteq(obj.access_token or u'', access_token):
                return (403, [], None)

        # check read access
        try:
            last_update = obj['__last_update']
        except AccessError:
            return (403, [], None)

        status, headers, content = None, [], None

        # attachment by url check
        module_resource_path = None
        if model == 'ir.attachment' and obj.type == 'url' and obj.url:
            url_match = re.match("^/(\w+)/(.+)$", obj.url)
            if url_match:
                module = url_match.group(1)
                module_path = get_module_path(module)
                module_resource_path = get_resource_path(module, url_match.group(2))
                if module_path and module_resource_path:
                    module_path = os.path.join(os.path.normpath(module_path), '')  # join ensures the path ends with '/'
                    module_resource_path = os.path.normpath(module_resource_path)
                    if module_resource_path.startswith(module_path):
                        with open(module_resource_path, 'rb') as f:
                            content = base64.b64encode(f.read())
                        last_update = pycompat.text_type(os.path.getmtime(module_resource_path))

            if not module_resource_path:
                module_resource_path = obj.url

            if not content:
                status = 301
                content = module_resource_path
        else:
            content = obj[field] or ''

        # filename
        default_filename = False
        if not filename:
            if filename_field in obj:
                filename = obj[filename_field]
            if not filename and module_resource_path:
                filename = os.path.basename(module_resource_path)
            if not filename:
                default_filename = True
                filename = "%s-%s-%s" % (obj._name, obj.id, field)

        # mimetype
        mimetype = 'mimetype' in obj and obj.mimetype or False
        if not mimetype:
            if filename:
                mimetype = mimetypes.guess_type(filename)[0]
            if not mimetype and getattr(env[model]._fields[field], 'attachment', False):
                # for binary fields, fetch the ir_attachement for mimetype check
                attach_mimetype = env['ir.attachment'].search_read(domain=[('res_model', '=', model), ('res_id', '=', id), ('res_field', '=', field)], fields=['mimetype'], limit=1)
                mimetype = attach_mimetype and attach_mimetype[0]['mimetype']
            if not mimetype:
                try:
                    decoded_content = base64.b64decode(content)
                except base64.binascii.Error:  # if we could not decode it, no need to pass it down: it would crash elsewhere...
                    return (404, [], None)
                mimetype = guess_mimetype(decoded_content, default=default_mimetype)

        # extension
        _, existing_extension = os.path.splitext(filename)
        if not existing_extension or default_filename:
            extension = mimetypes.guess_extension(mimetype)
            if extension:
                filename = "%s%s" % (filename, extension)

        headers += [('Content-Type', mimetype), ('X-Content-Type-Options', 'nosniff')]

        # cache
        etag = bool(request) and request.httprequest.headers.get('If-None-Match')
        retag = '"%s"' % hashlib.md5(pycompat.to_text(content).encode('utf-8')).hexdigest()
        status = status or (304 if etag == retag else 200)
        headers.append(('ETag', retag))
        headers.append(('Cache-Control', 'max-age=%s' % (STATIC_CACHE if unique else 0)))

        # content-disposition default name
        if download:
            headers.append(('Content-Disposition', cls.content_disposition(filename)))
        return (status, headers, content)
Ejemplo n.º 5
0
 def test_mimetype_gif(self):
     content = base64.b64decode(GIF)
     mimetype = guess_mimetype(content, default='test')
     self.assertEqual(mimetype, 'image/gif')
Ejemplo n.º 6
0
 def test_mimetype_jpg(self):
     content = base64.b64decode(JPG)
     mimetype = guess_mimetype(content, default='test')
     self.assertEqual(mimetype, 'image/jpeg')
Ejemplo n.º 7
0
 def test_mimetype_bmp(self):
     content = base64.b64decode(BMP)
     mimetype = guess_mimetype(content, default='test')
     # mimetype should match image/bmp, image/x-ms-bmp, ...
     self.assertRegexpMatches(mimetype, r'image/.*\bbmp')
Ejemplo n.º 8
0
 def test_mimetype_octet_stream(self):
     mimetype = guess_mimetype(b'\0')
     self.assertEqual(mimetype, 'application/octet-stream')
Ejemplo n.º 9
0
 def test_default_mimetype(self):
     mimetype = guess_mimetype(b'', default='test')
     # if available, python-magic returns application/x-empty
     self.assertIn(mimetype, ('test', 'application/x-empty'))
Ejemplo n.º 10
0
 def test_default_mimetype_empty(self):
     mimetype = guess_mimetype(b'')
     # swerp implementation returns application/octet-stream by default
     # if available, python-magic returns application/x-empty
     self.assertIn(mimetype,
                   ('application/octet-stream', 'application/x-empty'))