mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Content server: When sending ebook files, respect the If-Modified-Since header and send the file as a stream, to reduce memory consumption when sending very large files. Fixes #897343 (Bad memory leak when accessing library over network)
This commit is contained in:
parent
29041f74a7
commit
9fe0080692
@ -8,6 +8,7 @@ __docformat__ = 'restructuredtext en'
|
|||||||
import re, os, posixpath
|
import re, os, posixpath
|
||||||
|
|
||||||
import cherrypy
|
import cherrypy
|
||||||
|
from cherrypy.lib import cptools
|
||||||
|
|
||||||
from calibre import fit_image, guess_type
|
from calibre import fit_image, guess_type
|
||||||
from calibre.utils.date import fromtimestamp
|
from calibre.utils.date import fromtimestamp
|
||||||
@ -195,13 +196,26 @@ class ContentServer(object):
|
|||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
def get_format(self, id, format):
|
def get_format(self, id, format):
|
||||||
format = format.upper()
|
format = format.upper()
|
||||||
|
fm = self.db.format_metadata(id, format, allow_cache=False)
|
||||||
|
if not fm:
|
||||||
|
raise cherrypy.HTTPError(404, 'book: %d does not have format: %s'%(id, format))
|
||||||
|
cherrypy.response.headers['Last-Modified'] = \
|
||||||
|
self.last_modified(fm['mtime'])
|
||||||
|
# Check the If-Modified-Since request header. Returns appropriate HTTP
|
||||||
|
# response
|
||||||
|
cptools.validate_since()
|
||||||
|
|
||||||
fmt = self.db.format(id, format, index_is_id=True, as_file=True,
|
fmt = self.db.format(id, format, index_is_id=True, as_file=True,
|
||||||
mode='rb')
|
mode='rb')
|
||||||
if fmt is None:
|
if fmt is None:
|
||||||
raise cherrypy.HTTPError(404, 'book: %d does not have format: %s'%(id, format))
|
raise cherrypy.HTTPError(404, 'book: %d does not have format: %s'%(id, format))
|
||||||
|
mt = guess_type('dummy.'+format.lower())[0]
|
||||||
|
if mt is None:
|
||||||
|
mt = 'application/octet-stream'
|
||||||
|
cherrypy.response.headers['Content-Type'] = mt
|
||||||
|
|
||||||
mi = newmi = self.db.get_metadata(id, index_is_id=True)
|
mi = newmi = self.db.get_metadata(id, index_is_id=True)
|
||||||
if format == 'EPUB':
|
if format == 'EPUB':
|
||||||
# Get the original metadata
|
# Get the original metadata
|
||||||
@ -221,19 +235,19 @@ class ContentServer(object):
|
|||||||
set_metadata(fmt, newmi, format.lower())
|
set_metadata(fmt, newmi, format.lower())
|
||||||
fmt.seek(0)
|
fmt.seek(0)
|
||||||
|
|
||||||
mt = guess_type('dummy.'+format.lower())[0]
|
fmt.seek(0, 2)
|
||||||
if mt is None:
|
cherrypy.response.headers['Content-Length'] = fmt.tell()
|
||||||
mt = 'application/octet-stream'
|
fmt.seek(0)
|
||||||
au = authors_to_string(mi.authors if mi.authors else [_('Unknown')])
|
|
||||||
title = mi.title if mi.title else _('Unknown')
|
au = authors_to_string(newmi.authors if newmi.authors else
|
||||||
|
[_('Unknown')])
|
||||||
|
title = newmi.title if newmi.title else _('Unknown')
|
||||||
fname = u'%s - %s_%s.%s'%(title[:30], au[:30], id, format.lower())
|
fname = u'%s - %s_%s.%s'%(title[:30], au[:30], id, format.lower())
|
||||||
fname = ascii_filename(fname).replace('"', '_')
|
fname = ascii_filename(fname).replace('"', '_')
|
||||||
cherrypy.response.headers['Content-Type'] = mt
|
|
||||||
cherrypy.response.headers['Content-Disposition'] = \
|
cherrypy.response.headers['Content-Disposition'] = \
|
||||||
b'attachment; filename="%s"'%fname
|
b'attachment; filename="%s"'%fname
|
||||||
|
cherrypy.response.body = fmt
|
||||||
cherrypy.response.timeout = 3600
|
cherrypy.response.timeout = 3600
|
||||||
cherrypy.response.headers['Last-Modified'] = \
|
|
||||||
self.last_modified(self.db.format_last_modified(id, format))
|
|
||||||
return fmt
|
return fmt
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user