~alexaubin/unifield-web/US-2937

« back to all changes in this revision

Viewing changes to addons/openerp/utils/serve_file.py

  • Committer: jf
  • Date: 2017-06-01 14:43:04 UTC
  • mfrom: (4842.4.14 web-py27)
  • Revision ID: jfb@tempo-consulting.fr-20170601144304-zcyc468fwjf5l2w8
Python 2.7 

Show diffs side-by-side

added added

removed removed

Lines of Context:
4
4
mimetypes.types_map['.ico']='image/x-icon'
5
5
 
6
6
import os
7
 
import re
8
7
import stat
9
 
import time
10
 
import urllib
11
 
import tempfile
12
8
import cherrypy
13
 
from cherrypy.lib import cptools, http, file_generator_limited
 
9
from cherrypy.lib import cptools, httputil, file_generator_limited
14
10
 
15
11
def serve_file(path, content_type=None, disposition=None, name=None, delete=False):
16
12
    """Set status, headers, and body in order to serve the given file.
17
 
    
 
13
 
18
14
    The Content-Type header will be set to the content_type arg, if provided.
19
15
    If not provided, the Content-Type will be guessed by the file extension
20
16
    of the 'path' argument.
21
 
    
 
17
 
22
18
    If disposition is not None, the Content-Disposition header will be set
23
19
    to "<disposition>; filename=<name>". If name is None, it will be set
24
20
    to the basename of path. If disposition is None, no Content-Disposition
25
21
    header will be written.
26
22
    """
27
 
    
 
23
 
28
24
    response = cherrypy.response
29
 
    
 
25
 
30
26
    # If path is relative, users should fix it by making path absolute.
31
27
    # That is, CherryPy should not guess where the application root is.
32
28
    # It certainly should *not* use cwd (since CP may be invoked from a
34
30
    # paths become absolute by supplying a value for "tools.static.root".
35
31
    if not os.path.isabs(path):
36
32
        raise ValueError("'%s' is not an absolute path." % path)
37
 
    
 
33
 
38
34
    try:
39
35
        st = os.stat(path)
40
36
    except OSError:
41
37
        raise cherrypy.NotFound()
42
 
    
 
38
 
43
39
    # Check if path is a directory.
44
40
    if stat.S_ISDIR(st.st_mode):
45
41
        # Let the caller deal with it as they like.
46
42
        raise cherrypy.NotFound()
47
 
    
 
43
 
48
44
    # Set the Last-Modified response header, so that
49
45
    # modified-since validation code can work.
50
 
    response.headers['Last-Modified'] = http.HTTPDate(st.st_mtime)
 
46
    response.headers['Last-Modified'] = httputil.HTTPDate(st.st_mtime)
51
47
    cptools.validate_since()
52
 
    
 
48
 
53
49
    if content_type is None:
54
50
        # Set content-type based on filename extension
55
51
        ext = ""
58
54
            ext = path[i:].lower()
59
55
        content_type = mimetypes.types_map.get(ext, "text/plain")
60
56
    response.headers['Content-Type'] = content_type
61
 
    
 
57
 
62
58
    if disposition is not None:
63
59
        if name is None:
64
60
            name = os.path.basename(path)
65
61
        cd = '%s; filename="%s"' % (disposition, name)
66
62
        response.headers["Content-Disposition"] = cd
67
 
    
 
63
 
68
64
    # Set Content-Length and use an iterable (file object)
69
65
    #   this way CP won't load the whole file in memory
70
66
    c_len = st.st_size
79
75
        bodyfile = file
80
76
    else:
81
77
        bodyfile = open(path, 'rb')
82
 
    
 
78
 
83
79
    # HTTP/1.0 didn't have Range/Accept-Ranges headers, or the 206 code
84
80
    if cherrypy.request.protocol >= (1, 1):
85
81
        response.headers["Accept-Ranges"] = "bytes"
86
 
        r = http.get_ranges(cherrypy.request.headers.get('Range'), c_len)
 
82
        r = httputil.get_ranges(cherrypy.request.headers.get('Range'), c_len)
87
83
        if r == []:
88
84
            response.headers['Content-Range'] = "bytes */%s" % c_len
89
85
            message = "Invalid Range (first-byte-pos greater than Content-Length)"
97
93
                r_len = stop - start
98
94
                response.status = "206 Partial Content"
99
95
                response.headers['Content-Range'] = ("bytes %s-%s/%s" %
100
 
                                                       (start, stop - 1, c_len))
 
96
                                                     (start, stop - 1, c_len))
101
97
                response.headers['Content-Length'] = r_len
102
98
                bodyfile.seek(start)
103
99
                response.body = file_generator_limited(bodyfile, r_len)
111
107
                if response.headers.has_key("Content-Length"):
112
108
                    # Delete Content-Length header so finalize() recalcs it.
113
109
                    del response.headers["Content-Length"]
114
 
                
 
110
 
115
111
                def file_ranges():
116
112
                    # Apache compatibility:
117
113
                    yield "\r\n"
118
 
                    
 
114
 
119
115
                    for start, stop in r:
120
116
                        yield "--" + boundary
121
117
                        yield "\r\nContent-type: %s" % content_type
127
123
                        yield "\r\n"
128
124
                    # Final boundary
129
125
                    yield "--" + boundary + "--"
130
 
                    
 
126
 
131
127
                    # Apache compatibility:
132
128
                    yield "\r\n"
133
129
                response.body = file_ranges()