mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-08 10:44:09 -04:00
Tests for ETag and gzip
This commit is contained in:
parent
8cc8d83a38
commit
b4e02f6bc3
@ -543,7 +543,9 @@ class HTTPPair(object):
|
|||||||
self.status_code = httplib.CREATED if self.method == 'POST' else httplib.OK
|
self.status_code = httplib.CREATED if self.method == 'POST' else httplib.OK
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.status_code, output = finalize_output(output, self.inheaders, self.outheaders, self.status_code, self.response_protocol is HTTP1, self.method)
|
self.status_code, output = finalize_output(
|
||||||
|
output, self.inheaders, self.outheaders, self.status_code,
|
||||||
|
self.response_protocol is HTTP1, self.method, self.server_loop.opts.compress_min_size)
|
||||||
except IfNoneMatch as e:
|
except IfNoneMatch as e:
|
||||||
if self.method in ('GET', 'HEAD'):
|
if self.method in ('GET', 'HEAD'):
|
||||||
self.send_not_modified(e.etag)
|
self.send_not_modified(e.etag)
|
||||||
|
@ -59,6 +59,10 @@ raw_options = (
|
|||||||
'max_request_body_size', 500.0,
|
'max_request_body_size', 500.0,
|
||||||
None,
|
None,
|
||||||
|
|
||||||
|
'Minimum size for which responses use data compression (in bytes)',
|
||||||
|
'compress_min_size', 1024,
|
||||||
|
None,
|
||||||
|
|
||||||
'Decrease latency by using the TCP_NODELAY feature',
|
'Decrease latency by using the TCP_NODELAY feature',
|
||||||
'no_delay', True,
|
'no_delay', True,
|
||||||
'no_delay turns on TCP_NODELAY which decreases latency at the cost of'
|
'no_delay turns on TCP_NODELAY which decreases latency at the cost of'
|
||||||
|
@ -124,6 +124,8 @@ class GeneratedOutput(object):
|
|||||||
class StaticGeneratedOutput(object):
|
class StaticGeneratedOutput(object):
|
||||||
|
|
||||||
def __init__(self, data):
|
def __init__(self, data):
|
||||||
|
if isinstance(data, type('')):
|
||||||
|
data = data.encode('utf-8')
|
||||||
self.data = data
|
self.data = data
|
||||||
self.etag = '"%s"' % hashlib.sha1(data).hexdigest()
|
self.etag = '"%s"' % hashlib.sha1(data).hexdigest()
|
||||||
self.content_length = len(data)
|
self.content_length = len(data)
|
||||||
@ -145,7 +147,7 @@ def generate_static_output(cache, gso_lock, name, generator):
|
|||||||
def parse_if_none_match(val):
|
def parse_if_none_match(val):
|
||||||
return {x.strip() for x in val.split(',')}
|
return {x.strip() for x in val.split(',')}
|
||||||
|
|
||||||
def finalize_output(output, inheaders, outheaders, status_code, is_http1, method):
|
def finalize_output(output, inheaders, outheaders, status_code, is_http1, method, compress_min_size):
|
||||||
ct = outheaders.get('Content-Type', '')
|
ct = outheaders.get('Content-Type', '')
|
||||||
compressible = not ct or ct.startswith('text/') or ct.startswith('image/svg') or ct.startswith('application/json')
|
compressible = not ct or ct.startswith('text/') or ct.startswith('image/svg') or ct.startswith('application/json')
|
||||||
if isinstance(output, file):
|
if isinstance(output, file):
|
||||||
@ -156,7 +158,8 @@ def finalize_output(output, inheaders, outheaders, status_code, is_http1, method
|
|||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
output = GeneratedOutput(output, outheaders)
|
output = GeneratedOutput(output, outheaders)
|
||||||
compressible = (status_code == httplib.OK and compressible and output.content_length > 1024 and
|
compressible = (status_code == httplib.OK and compressible and
|
||||||
|
(compress_min_size > -1 and output.content_length >= compress_min_size) and
|
||||||
acceptable_encoding(inheaders.get('Accept-Encoding', '')) and not is_http1)
|
acceptable_encoding(inheaders.get('Accept-Encoding', '')) and not is_http1)
|
||||||
accept_ranges = (not compressible and output.accept_ranges is not None and status_code == httplib.OK and
|
accept_ranges = (not compressible and output.accept_ranges is not None and status_code == httplib.OK and
|
||||||
not is_http1)
|
not is_http1)
|
||||||
|
@ -61,7 +61,9 @@ class TestServer(Thread):
|
|||||||
def __exit__(self, *args):
|
def __exit__(self, *args):
|
||||||
self.loop.stop()
|
self.loop.stop()
|
||||||
|
|
||||||
def connect(self, timeout=0.1):
|
def connect(self, timeout=None):
|
||||||
|
if timeout is None:
|
||||||
|
timeout = self.loop.opts.timeout
|
||||||
return httplib.HTTPConnection(self.address[0], self.address[1], strict=True, timeout=timeout)
|
return httplib.HTTPConnection(self.address[0], self.address[1], strict=True, timeout=timeout)
|
||||||
|
|
||||||
def change_handler(self, handler):
|
def change_handler(self, handler):
|
||||||
|
@ -6,7 +6,7 @@ from __future__ import (unicode_literals, division, absolute_import,
|
|||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2015, Kovid Goyal <kovid at kovidgoyal.net>'
|
__copyright__ = '2015, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||||
|
|
||||||
import textwrap, httplib
|
import textwrap, httplib, hashlib, zlib
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
from calibre.srv.tests.base import BaseTest, TestServer
|
from calibre.srv.tests.base import BaseTest, TestServer
|
||||||
@ -159,3 +159,28 @@ class TestHTTP(BaseTest):
|
|||||||
self.ae(server.loop.requests.idle, 10)
|
self.ae(server.loop.requests.idle, 10)
|
||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
def test_http_response(self): # {{{
|
||||||
|
'Test HTTP protocol responses'
|
||||||
|
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:
|
||||||
|
# Test ETag
|
||||||
|
conn = server.connect()
|
||||||
|
conn.request('GET', '/an_etagged_path')
|
||||||
|
r = conn.getresponse()
|
||||||
|
self.ae(r.status, httplib.OK), self.ae(r.read(), b'an_etagged_path')
|
||||||
|
etag = r.getheader('ETag')
|
||||||
|
self.ae(etag, '"%s"' % hashlib.sha1('an_etagged_path').hexdigest())
|
||||||
|
conn.request('GET', '/an_etagged_path', headers={'If-None-Match':etag})
|
||||||
|
r = conn.getresponse()
|
||||||
|
self.ae(r.status, httplib.NOT_MODIFIED)
|
||||||
|
self.ae(r.read(), b'')
|
||||||
|
|
||||||
|
# Test gzip
|
||||||
|
conn.request('GET', '/an_etagged_path', headers={'Accept-Encoding':'gzip'})
|
||||||
|
r = conn.getresponse()
|
||||||
|
self.ae(r.status, httplib.OK), self.ae(zlib.decompress(r.read(), 16+zlib.MAX_WBITS), b'an_etagged_path')
|
||||||
|
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user