Skip to content

Commit e50fe20

Browse files
committed
Run the precommit linters against the code to make them operate as expected
1 parent 0b130d2 commit e50fe20

File tree

3 files changed

+57
-211
lines changed

3 files changed

+57
-211
lines changed

cheroot/server.py

Lines changed: 52 additions & 206 deletions
Original file line numberDiff line numberDiff line change
@@ -87,15 +87,14 @@
8787
from six.moves import urllib
8888

8989
from . import connections, errors, __version__
90-
from ._compat import bton, ntou
90+
from ._compat import bton
9191
from ._compat import IS_PPC
9292
from .workers import threadpool
9393
from .makefile import MakeFile, StreamWriter
9494

9595
__all__ = (
9696
'HTTPRequest', 'HTTPConnection', 'HTTPServer',
97-
'HeaderReader', 'DropUnderscoreHeaderReader',
98-
'SizeCheckWrapper', 'KnownLengthRFile', 'ChunkedRFile',
97+
'KnownLengthRFile', 'ChunkedRFile',
9998
'Gateway', 'get_ssl_adapter_class',
10099
)
101100

@@ -166,174 +165,6 @@
166165
logging.statistics = {}
167166

168167

169-
class HeaderReader:
170-
"""Object for reading headers from an HTTP request.
171-
172-
Interface and default implementation.
173-
"""
174-
175-
def __call__(self, rfile, hdict=None):
176-
"""
177-
Read headers from the given stream into the given header dict.
178-
179-
If hdict is None, a new header dict is created. Returns the populated
180-
header dict.
181-
182-
Headers which are repeated are folded together using a comma if their
183-
specification so dictates.
184-
185-
This function raises ValueError when the read bytes violate the HTTP
186-
spec.
187-
You should probably return "400 Bad Request" if this happens.
188-
"""
189-
if hdict is None:
190-
hdict = {}
191-
192-
while True:
193-
line = rfile.readline()
194-
if not line:
195-
# No more data--illegal end of headers
196-
raise ValueError('Illegal end of headers.')
197-
198-
if line == CRLF:
199-
# Normal end of headers
200-
break
201-
if not line.endswith(CRLF):
202-
raise ValueError('HTTP requires CRLF terminators')
203-
204-
if line[0] in (SPACE, TAB):
205-
# It's a continuation line.
206-
v = line.strip()
207-
else:
208-
try:
209-
k, v = line.split(COLON, 1)
210-
except ValueError:
211-
raise ValueError('Illegal header line.')
212-
v = v.strip()
213-
k = self._transform_key(k)
214-
hname = k
215-
216-
if not self._allow_header(k):
217-
continue
218-
219-
if k in comma_separated_headers:
220-
existing = hdict.get(hname)
221-
if existing:
222-
v = b', '.join((existing, v))
223-
hdict[hname] = v
224-
225-
return hdict
226-
227-
def _allow_header(self, key_name):
228-
return True
229-
230-
def _transform_key(self, key_name):
231-
# TODO: what about TE and WWW-Authenticate?
232-
return key_name.strip().title()
233-
234-
235-
class DropUnderscoreHeaderReader(HeaderReader):
236-
"""Custom HeaderReader to exclude any headers with underscores in them."""
237-
238-
def _allow_header(self, key_name):
239-
orig = super(DropUnderscoreHeaderReader, self)._allow_header(key_name)
240-
return orig and '_' not in key_name
241-
242-
243-
class SizeCheckWrapper:
244-
"""Wraps a file-like object, raising MaxSizeExceeded if too large.
245-
246-
:param rfile: ``file`` of a limited size
247-
:param int maxlen: maximum length of the file being read
248-
"""
249-
250-
def __init__(self, rfile, maxlen):
251-
"""Initialize SizeCheckWrapper instance."""
252-
self.rfile = rfile
253-
self.maxlen = maxlen
254-
self.bytes_read = 0
255-
256-
def _check_length(self):
257-
if self.maxlen and self.bytes_read > self.maxlen:
258-
raise errors.MaxSizeExceeded()
259-
260-
def read(self, size=None):
261-
"""Read a chunk from ``rfile`` buffer and return it.
262-
263-
:param int size: amount of data to read
264-
265-
:returns: chunk from ``rfile``, limited by size if specified
266-
:rtype: bytes
267-
"""
268-
data = self.rfile.read(size)
269-
self.bytes_read += len(data)
270-
self._check_length()
271-
return data
272-
273-
def readline(self, size=None):
274-
"""Read a single line from ``rfile`` buffer and return it.
275-
276-
:param int size: minimum amount of data to read
277-
278-
:returns: one line from ``rfile``
279-
:rtype: bytes
280-
"""
281-
if size is not None:
282-
data = self.rfile.readline(size)
283-
self.bytes_read += len(data)
284-
self._check_length()
285-
return data
286-
287-
# User didn't specify a size ...
288-
# We read the line in chunks to make sure it's not a 100MB line !
289-
res = []
290-
while True:
291-
data = self.rfile.readline(256)
292-
self.bytes_read += len(data)
293-
self._check_length()
294-
res.append(data)
295-
# See https://github.com/cherrypy/cherrypy/issues/421
296-
if len(data) < 256 or data[-1:] == LF:
297-
return EMPTY.join(res)
298-
299-
def readlines(self, sizehint=0):
300-
"""Read all lines from ``rfile`` buffer and return them.
301-
302-
:param int sizehint: hint of minimum amount of data to read
303-
304-
:returns: lines of bytes read from ``rfile``
305-
:rtype: list[bytes]
306-
"""
307-
# Shamelessly stolen from StringIO
308-
total = 0
309-
lines = []
310-
line = self.readline(sizehint)
311-
while line:
312-
lines.append(line)
313-
total += len(line)
314-
if 0 < sizehint <= total:
315-
break
316-
line = self.readline(sizehint)
317-
return lines
318-
319-
def close(self):
320-
"""Release resources allocated for ``rfile``."""
321-
self.rfile.close()
322-
323-
def __iter__(self):
324-
"""Return file iterator."""
325-
return self
326-
327-
def __next__(self):
328-
"""Generate next file chunk."""
329-
data = next(self.rfile)
330-
self.bytes_read += len(data)
331-
self._check_length()
332-
return data
333-
334-
next = __next__
335-
336-
337168
class RFile(ABC):
338169
def __init__(self, rfile, wfile, conn):
339170
self.rfile = rfile
@@ -358,7 +189,7 @@ def _handle_input(self, data):
358189
if isinstance(evt, h11.Data):
359190
return bytes(evt.data)
360191
else:
361-
return b""
192+
return b''
362193

363194
@abstractmethod
364195
def read(self, size=None):
@@ -704,11 +535,6 @@ class HTTPRequest:
704535
705536
This value is set automatically inside send_headers."""
706537

707-
header_reader = HeaderReader()
708-
"""
709-
A HeaderReader instance or compatible reader.
710-
"""
711-
712538
def __init__(self, server, conn, proxy_mode=False, strict_mode=True):
713539
"""Initialize HTTP request container instance.
714540
@@ -745,7 +571,7 @@ def __init__(self, server, conn, proxy_mode=False, strict_mode=True):
745571
self.strict_mode = strict_mode
746572

747573
def _process_next_h11_event(self, read_new=True):
748-
"""Instruct h11 to process data in its buffer and return any events it has available
574+
"""Instruct h11 to process data in its buffer and return any events it has available.
749575
750576
:param read_new: If the method should attempt to read new lines to find an event
751577
:type read_new: bool
@@ -771,20 +597,22 @@ def parse_request(self):
771597
if isinstance(req_line, h11.Request):
772598
self.started_request = True
773599
self.uri = req_line.target
774-
scheme, authority, path, query, fragment = urllib.parse.urlsplit(self.uri)
775-
self.qs = query
600+
scheme, authority, path, qs, fragment = urllib.parse.urlsplit(self.uri) # noqa
601+
self.qs = qs
776602
self.method = req_line.method
777-
self.request_protocol = b"HTTP/%s" % req_line.http_version
603+
self.request_protocol = b'HTTP/%s' % req_line.http_version
778604
if req_line.http_version > b'1.1':
779-
self.simple_response(505, "Cannot fulfill request")
780-
self.response_protocol = b"HTTP/1.1"
605+
self.simple_response(505, 'Cannot fulfill request')
606+
self.response_protocol = b'HTTP/1.1'
781607
# TODO: oneliner-ify this
782608
self.inheaders = {}
783609
for header in req_line.headers:
784610
self.inheaders[header[0]] = header[1]
785611

786-
if (b'transfer-encoding' in self.inheaders and
787-
self.inheaders[b'transfer-encoding'].lower() == b"chunked"):
612+
if (
613+
b'transfer-encoding' in self.inheaders and
614+
self.inheaders[b'transfer-encoding'].lower() == b'chunked'
615+
):
788616
self.chunked_read = True
789617

790618
uri_is_absolute_form = scheme or authority
@@ -803,8 +631,9 @@ def parse_request(self):
803631
self.simple_response(405)
804632
return False
805633

806-
# `urlsplit()` above parses "example.com:3128" as path part of URI.
807-
# this is a workaround, which makes it detect netloc correctly
634+
# `urlsplit()` above parses "example.com:3128" as path part
635+
# of URI. This is a workaround, which makes it detect
636+
# netloc correctly
808637
uri_split = urllib.parse.urlsplit(b''.join((b'//', self.uri)))
809638
_scheme, _authority, _path, _qs, _fragment = uri_split
810639
_port = EMPTY
@@ -844,7 +673,8 @@ def parse_request(self):
844673
"""Absolute URI is only allowed within proxies."""
845674
self.simple_response(
846675
400,
847-
'Absolute URI not allowed if server is not a proxy.',
676+
'Absolute URI not allowed'
677+
' if server is not a proxy.',
848678
)
849679
return False
850680

@@ -876,7 +706,10 @@ def parse_request(self):
876706
return False
877707
path = QUOTED_SLASH.join(atoms)
878708
if fragment:
879-
self.simple_response(400, "Illegal #fragment in Request-URI.")
709+
self.simple_response(
710+
400,
711+
'Illegal #fragment in Request-URI.',
712+
)
880713

881714
if not path.startswith(FORWARD_SLASH):
882715
path = FORWARD_SLASH + path
@@ -887,10 +720,8 @@ def parse_request(self):
887720
self.close_connection = True
888721
else:
889722
# TODO
890-
raise NotImplementedError("Only expecting Request object here")
723+
raise NotImplementedError('Only expecting Request object here')
891724
except h11.RemoteProtocolError as e:
892-
# NEED INFO: Should we adjust the tests to match h11's exception text
893-
# Or should we continue to shim like this:
894725
err_map = {
895726
'bad Content-Length': 'Malformed Content-Length Header.',
896727
'illegal request line': 'Malformed Request-Line.',
@@ -904,7 +735,10 @@ def respond(self):
904735
"""Call the gateway and write its iterable output."""
905736
mrbs = self.server.max_request_body_size
906737
if self.chunked_read:
907-
self.rfile = ChunkedRFile(self.h_conn, self.conn.rfile, self.conn.wfile, mrbs)
738+
self.rfile = ChunkedRFile(
739+
self.h_conn,
740+
self.conn.rfile, self.conn.wfile, mrbs,
741+
)
908742
else:
909743
cl = int(self.inheaders.get(b'content-length', 0))
910744
if mrbs and mrbs < cl:
@@ -915,29 +749,36 @@ def respond(self):
915749
'maximum allowed bytes.',
916750
)
917751
return
918-
self.rfile = KnownLengthRFile(self.h_conn, self.conn.rfile, self.conn.wfile, cl)
752+
self.rfile = KnownLengthRFile(
753+
self.h_conn,
754+
self.conn.rfile, self.conn.wfile, cl,
755+
)
919756

920-
# client may still be in send body, lets find out and figure out what to do with that
921-
# if self.h_conn.their_state == h11.SEND_BODY:
922757
if self.h_conn.client_is_waiting_for_100_continue:
923758
mini_headers = ()
924-
go_ahead = h11.InformationalResponse(status_code=100, headers=mini_headers)
759+
go_ahead = h11.InformationalResponse(
760+
status_code=100,
761+
headers=mini_headers,
762+
)
925763
bytes_out = self.h_conn.send(go_ahead)
926764
self.conn.wfile.write(bytes_out)
927765
try:
928766
self.server.gateway(self).respond()
929767
self.ready and self.ensure_headers_sent()
930768
except errors.MaxSizeExceeded as e:
931-
self.simple_response(413, "Request Entity Too Large")
769+
self.simple_response(413, 'Request Entity Too Large')
932770
self.close_connection = True
933771
return
934772

935-
while self.h_conn.their_state is h11.SEND_BODY and self.h_conn.our_state is not h11.ERROR:
936-
# empty their buffer ?
773+
while (
774+
self.h_conn.their_state is h11.SEND_BODY
775+
and self.h_conn.our_state is not h11.ERROR
776+
):
937777
data = self.rfile.read()
938778
self._process_next_h11_event(read_new=False)
939779
if data == EMPTY and self.h_conn.their_state is h11.SEND_BODY:
940-
# they didn't send a full body, kill connection, set our state to ERROR
780+
# they didn't send a full body, kill connection,
781+
# set our state to ERROR
941782
self.h_conn.send_failed()
942783

943784
# If we haven't sent our end-of-message data, send it now
@@ -946,7 +787,10 @@ def respond(self):
946787
self.conn.wfile.write(bytes_out)
947788

948789
# prep for next req cycle if it's available
949-
if self.h_conn.our_state is h11.DONE and self.h_conn.their_state is h11.DONE:
790+
if (
791+
self.h_conn.our_state is h11.DONE
792+
and self.h_conn.their_state is h11.DONE
793+
):
950794
self.h_conn.start_next_cycle()
951795
self.close_connection = False
952796
else:
@@ -959,14 +803,14 @@ def simple_response(self, status, msg=None):
959803
msg = ''
960804
status = str(status)
961805
headers = [
962-
('Content-Type', 'text/plain')
806+
('Content-Type', 'text/plain'),
963807
]
964808

965809
self.outheaders = headers
966810
self.status = status
967811
self.send_headers()
968812
if msg:
969-
self.write(bytes(msg, encoding="ascii"))
813+
self.write(bytes(msg, encoding='ascii'))
970814

971815
evt = h11.EndOfMessage()
972816
bytes_out = self.h_conn.send(evt)
@@ -1005,8 +849,10 @@ def send_headers(self):
1005849
self.server.server_name.encode('ISO-8859-1'),
1006850
))
1007851

1008-
res = h11.Response(status_code=status, headers=self.outheaders,
1009-
http_version=self.response_protocol[5:], reason=self.status[3:])
852+
res = h11.Response(
853+
status_code=status, headers=self.outheaders,
854+
http_version=self.response_protocol[5:], reason=self.status[3:],
855+
)
1010856
res_bytes = self.h_conn.send(res)
1011857
self.conn.wfile.write(res_bytes)
1012858

0 commit comments

Comments
 (0)