31
34
log_request = lambda *args, **kwargs: None
32
35
log_error = lambda *args, **kwargs: None
37
def _gzip_compress(self, f):
39
gz = gzip.GzipFile(mode='wb', fileobj=gz_out)
45
def is_gzip_accepted(self):
47
for header in self.headers.getallmatchingheaders('Accept-Encoding'):
48
# getallmatchingheaders returns the whole line, so first we have to
49
# split off the header definition
50
_, content = header.split(':', 1)
51
content = content.strip()
52
# Then, you are allowed to specify a comma separated list of
53
# acceptable encodings. You are also allowed to specify
54
# 'encoding;q=XXX' to specify what encodings you would prefer.
55
# We'll allow it to be set, but just ignore it.
56
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
57
encodings = [encoding.strip().split(';', )[0]
58
for encoding in content.split(',')]
59
accepted.update(encodings)
60
if 'gzip' in accepted:
64
# This is a copy & paste and minor modification of
65
# SimpleHTTPRequestHandler's send_head code. Because to support
66
# Content-Encoding gzip, we have to change what headers get returned (as it
67
# affects Content-Length headers.
69
"""Common code for GET and HEAD commands.
71
This sends the response code and MIME headers.
73
Return value is either a file object (which has to be copied
74
to the outputfile by the caller unless the command was HEAD,
75
and must be closed by the caller under all circumstances), or
76
None, in which case the caller has nothing further to do.
79
path = self.translate_path(self.path)
81
if os.path.isdir(path):
82
if not self.path.endswith('/'):
83
# redirect browser - doing basically what apache does
84
self.send_response(301)
85
self.send_header("Location", self.path + "/")
88
for index in "index.html", "index.htm":
89
index = os.path.join(path, index)
90
if os.path.exists(index):
94
return self.list_directory(path)
95
ctype = self.guess_type(path)
97
# Always read in binary mode. Opening files in text mode may cause
98
# newline translations, making the actual size of the content
99
# transmitted *less* than the content-length!
102
self.send_error(404, "File not found")
104
if self.is_gzip_accepted():
105
return self.start_gz_response(ctype, f)
107
return self.start_response(ctype, f)
109
def start_gz_response(self, ctype, f):
110
self.send_response(200)
111
self.send_header("Content-type", ctype)
112
self.send_header("Content-Encoding", 'gzip')
113
gz_out = self._gzip_compress(f)
114
self.send_header("Content-Length", str(gz_out.tell()))
119
def start_response(self, ctype, f):
120
self.send_response(200)
121
self.send_header("Content-type", ctype)
122
fs = os.fstat(f.fileno())
123
self.send_header("Content-Length", str(fs[6]))
124
self.send_header("Last-Modified", self.date_time_string(fs.st_mtime))
35
129
class HTTPServerFixture(Fixture):
36
130
"""Bring up a very simple, threaded, web server.