This commit is contained in:
Kovid Goyal 2015-05-25 21:01:06 +05:30
parent aa4c31ef75
commit eb72da611d
3 changed files with 18 additions and 9 deletions

View File

@ -24,6 +24,7 @@ from calibre.srv.errors import HTTP404
from calibre.srv.http_request import HTTPRequest, read_headers
from calibre.srv.sendfile import file_metadata, sendfile_to_socket_async, CannotSendfile, SendfileInterrupted
from calibre.srv.utils import MultiDict, start_cork, stop_cork, http_date, HTTP1, HTTP11, socket_errors_socket_closed
from calibre.utils.monotonic import monotonic
Range = namedtuple('Range', 'start stop size')
MULTIPART_SEPARATOR = uuid.uuid4().hex.decode('ascii')
@ -274,6 +275,8 @@ class HTTPConnection(HTTPRequest):
self.ready = self.use_sendfile = False
return False
raise
finally:
self.last_activity = monotonic()
if sent == 0:
# Something bad happened, was the file modified on disk by
# another process?

View File

@ -80,9 +80,10 @@ if isosx:
err = ctypes.get_errno()
if err in (errno.EBADF, errno.ENOTSUP, errno.ENOTSOCK, errno.EOPNOTSUPP):
raise CannotSendfile()
if err in (errno.EINTR, errno.EAGAIN):
if err == errno.EINTR:
raise SendfileInterrupted()
raise IOError((err, os.strerror(err)))
if err != errno.EAGAIN:
raise IOError((err, os.strerror(err)))
return num_bytes.value
elif islinux:

View File

@ -12,6 +12,7 @@ from tempfile import NamedTemporaryFile
from calibre import guess_type
from calibre.srv.tests.base import BaseTest, TestServer
from calibre.utils.monotonic import monotonic
class TestHTTP(BaseTest):
@ -242,8 +243,8 @@ class TestHTTP(BaseTest):
from calibre.srv.http_response import parse_multipart_byterange
def handler(conn):
return conn.generate_static_output('test', lambda : ''.join(conn.path))
with TestServer(handler, timeout=0.1, compress_min_size=0) as server, \
NamedTemporaryFile(suffix='test.epub') as f, open(P('localization/locales.zip'), 'rb') as lf:
with NamedTemporaryFile(suffix='test.epub') as f, open(P('localization/locales.zip'), 'rb') as lf, \
TestServer(handler, timeout=0.2, compress_min_size=0) as server:
fdata = string.ascii_letters * 100
f.write(fdata), f.seek(0)
@ -280,20 +281,21 @@ class TestHTTP(BaseTest):
conn.request('GET', '/test', headers={'Range':'bytes=2-25'})
r = conn.getresponse()
self.ae(r.status, httplib.PARTIAL_CONTENT)
self.ae(type('')(r.getheader('Accept-Ranges')), 'bytes')
self.ae(type('')(r.getheader('Content-Range')), 'bytes 2-25/%d' % len(fdata))
self.ae(int(r.getheader('Content-Length')), 24)
self.ae(r.status, httplib.PARTIAL_CONTENT), self.ae(r.read(), fdata[2:26])
self.ae(r.read(), fdata[2:26])
conn.request('GET', '/test', headers={'Range':'bytes=100000-'})
r = conn.getresponse()
self.ae(type('')(r.getheader('Content-Range')), 'bytes */%d' % len(fdata))
self.ae(r.status, httplib.REQUESTED_RANGE_NOT_SATISFIABLE)
self.ae(type('')(r.getheader('Content-Range')), 'bytes */%d' % len(fdata))
conn.request('GET', '/test', headers={'Range':'bytes=25-50', 'If-Range':etag})
r = conn.getresponse()
self.ae(int(r.getheader('Content-Length')), 26)
self.ae(r.status, httplib.PARTIAL_CONTENT), self.ae(r.read(), fdata[25:51])
self.ae(int(r.getheader('Content-Length')), 26)
conn.request('GET', '/test', headers={'Range':'bytes=0-1000000'})
r = conn.getresponse()
@ -301,12 +303,13 @@ class TestHTTP(BaseTest):
conn.request('GET', '/test', headers={'Range':'bytes=25-50', 'If-Range':'"nomatch"'})
r = conn.getresponse()
self.ae(r.status, httplib.OK), self.ae(r.read(), fdata)
self.assertFalse(r.getheader('Content-Range'))
self.ae(int(r.getheader('Content-Length')), len(fdata))
self.ae(r.status, httplib.OK), self.ae(r.read(), fdata)
conn.request('GET', '/test', headers={'Range':'bytes=0-25,26-50'})
r = conn.getresponse()
self.ae(r.status, httplib.PARTIAL_CONTENT)
clen = int(r.getheader('Content-Length'))
data = r.read()
self.ae(clen, len(data))
@ -314,16 +317,18 @@ class TestHTTP(BaseTest):
self.ae(parse_multipart_byterange(buf, r.getheader('Content-Type')), [(0, fdata[:26]), (26, fdata[26:51])])
# Test sending of larger file
start_time = monotonic()
lf.seek(0)
data = lf.read()
server.change_handler(lambda conn: lf)
conn = server.connect()
conn.request('GET', '/test')
r = conn.getresponse()
self.ae(r.status, httplib.OK)
rdata = r.read()
self.ae(len(data), len(rdata))
self.ae(hashlib.sha1(data).hexdigest(), hashlib.sha1(rdata).hexdigest())
self.ae(data, rdata)
self.assertLess(monotonic() - start_time, 5, 'Large file transfer took too long')
# Now try it without sendfile
# }}}