diff --git a/src/calibre/srv/http_request.py b/src/calibre/srv/http_request.py index e6684c2079..c020e5bdc2 100644 --- a/src/calibre/srv/http_request.py +++ b/src/calibre/srv/http_request.py @@ -154,7 +154,6 @@ class HTTPRequest(Connection): def __init__(self, *args, **kwargs): Connection.__init__(self, *args, **kwargs) - self.corked = False self.max_header_line_size = int(1024 * self.opts.max_header_line_size) self.max_request_body_size = int(1024 * 1024 * self.opts.max_request_body_size) diff --git a/src/calibre/srv/http_response.py b/src/calibre/srv/http_response.py index afbd11fe2a..aa2d3313be 100644 --- a/src/calibre/srv/http_response.py +++ b/src/calibre/srv/http_response.py @@ -7,10 +7,6 @@ __license__ = 'GPL v3' __copyright__ = '2015, Kovid Goyal ' import os, httplib, hashlib, uuid, zlib, time, struct, repr as reprlib -try: - from select import PIPE_BUF -except ImportError: - PIPE_BUF = 512 # windows from collections import namedtuple from io import BytesIO, DEFAULT_BUFFER_SIZE from itertools import chain, repeat, izip_longest @@ -23,7 +19,7 @@ from calibre.srv.loop import WRITE 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.srv.utils import MultiDict, http_date, HTTP1, HTTP11, socket_errors_socket_closed from calibre.utils.monotonic import monotonic Range = namedtuple('Range', 'start stop size') @@ -283,7 +279,7 @@ class HTTPConnection(HTTPRequest): self.use_sendfile = self.ready = False raise IOError('sendfile() failed to write any bytes to the socket') else: - sent = self.send(buf.read(min(limit, PIPE_BUF))) + sent = self.send(buf.read(min(limit, self.send_bufsize))) buf.seek(pos + sent) return buf.tell() == end @@ -367,8 +363,7 @@ class HTTPConnection(HTTPRequest): def response_ready(self, header_file, output=None): self.response_started = True - start_cork(self.socket) - self.corked = True + self.optimize_for_sending_packet() self.use_sendfile = False self.set_state(WRITE, self.write_response_headers, header_file, output) @@ -437,8 +432,7 @@ class HTTPConnection(HTTPRequest): def reset_state(self): self.connection_ready() self.ready = not self.close_after_response - stop_cork(self.socket) - self.corked = False + self.end_send_optimization() def report_unhandled_exception(self, e, formatted_traceback): self.simple_response(httplib.INTERNAL_SERVER_ERROR) diff --git a/src/calibre/srv/loop.py b/src/calibre/srv/loop.py index 05ae578950..95993c16cc 100644 --- a/src/calibre/srv/loop.py +++ b/src/calibre/srv/loop.py @@ -14,17 +14,20 @@ from calibre import as_unicode from calibre.ptempfile import TemporaryDirectory from calibre.srv.opts import Options from calibre.srv.utils import ( - socket_errors_socket_closed, socket_errors_nonblocking, HandleInterrupt, socket_errors_eintr) + socket_errors_socket_closed, socket_errors_nonblocking, HandleInterrupt, + socket_errors_eintr, start_cork, stop_cork) from calibre.utils.socket_inheritance import set_socket_inherit from calibre.utils.logging import ThreadSafeLog from calibre.utils.monotonic import monotonic READ, WRITE, RDWR = 'READ', 'WRITE', 'RDWR' +DESIRED_SEND_BUFFER_SIZE = 16 * 1024 class Connection(object): def __init__(self, socket, opts, ssl_context, tdir): self.opts = opts + self.orig_send_bufsize = self.send_bufsize = 4096 self.tdir = tdir self.ssl_context = ssl_context self.wait_for = READ @@ -39,6 +42,22 @@ class Connection(object): self.connection_ready() self.last_activity = monotonic() + def optimize_for_sending_packet(self): + start_cork(self.socket) + self.orig_send_bufsize = self.send_bufsize = self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF) + if self.send_bufsize < DESIRED_SEND_BUFFER_SIZE: + try: + self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, DESIRED_SEND_BUFFER_SIZE) + except socket.error: + pass + else: + self.send_bufsize = self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF) + + def end_send_optimization(self): + stop_cork(self.socket) + if self.send_bufsize != self.orig_send_bufsize: + self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, self.orig_send_bufsize) + def set_state(self, wait_for, func, *args, **kwargs): self.wait_for = wait_for if args or kwargs: diff --git a/src/calibre/srv/tests/http.py b/src/calibre/srv/tests/http.py index 02bc2e96a8..c4e4d6daaf 100644 --- a/src/calibre/srv/tests/http.py +++ b/src/calibre/srv/tests/http.py @@ -329,6 +329,6 @@ class TestHTTP(BaseTest): 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') + self.assertLess(monotonic() - start_time, 1, 'Large file transfer took too long') # }}}