Skip to content

Commit e8f38dc

Browse files
authored
Merge pull request python-hyper#42 from jeamland/prospector
Prospector
2 parents f982a59 + 5167a90 commit e8f38dc

File tree

9 files changed

+82
-66
lines changed

9 files changed

+82
-66
lines changed

Diff for: .prospector.yml

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
pylint:
2+
disable:
3+
- unused-argument
4+
5+
options:
6+
max-args: 6

Diff for: .travis.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ matrix:
3131
- python: 3.6
3232
env: MODE=docs
3333
- python: 3.6
34-
env: MODE=flake8
34+
env: MODE=prospector
3535

3636
cache: pip
3737

Diff for: .travis/run.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ install_wsproto() {
4040
}
4141

4242
case "$MODE" in
43-
flake8)
43+
prospector)
4444
pip install flake8
4545
flake8 --max-complexity 12 wsproto
4646
;;

Diff for: Pipfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ pytest = "*"
77
pytest-cov = "*"
88
coverage = "*"
99
tox = "*"
10-
flake8 = "*"
10+
prospector = "*"
1111

1212
[packages]
1313
h11 = "*"

Diff for: compliance/run-autobahn-tests.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,11 @@ def wait_for_listener(port):
9090
def coverage(command, coverage_settings):
9191
if not coverage_settings["enabled"]:
9292
return [sys.executable] + command
93-
else:
94-
return ([sys.executable, "-m", "coverage", "run",
95-
"--include", coverage_settings["wsproto-path"],
96-
"--rcfile", coverage_settings["coveragerc"]]
97-
+ command)
93+
94+
return ([sys.executable, "-m", "coverage", "run",
95+
"--include", coverage_settings["wsproto-path"],
96+
"--rcfile", coverage_settings["coveragerc"]]
97+
+ command)
9898

9999
def summarize(report_path):
100100
with open(os.path.join(report_path, "index.json")) as f:

Diff for: tox.ini

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ deps = -r{toxinidir}/test_requirements.txt
66
passenv = COVERAGE_FILE
77
commands = pytest --cov {envsitepackagesdir}/wsproto --cov-report term-missing --cov-config {toxinidir}/.coveragerc {toxinidir}/test/
88

9-
[testenv:lint]
9+
[testenv:prospector]
1010
basepython = python3.6
11-
deps = flake8==3.4.1
12-
commands = flake8 --max-complexity 12 wsproto test
11+
deps = prospector
12+
commands = prospector
1313

1414
[testenv:docs]
1515
basepython = python3.6

Diff for: wsproto/connection.py

+34-27
Original file line numberDiff line numberDiff line change
@@ -100,13 +100,13 @@ class WSConnection(object):
100100
"""
101101

102102
def __init__(self, conn_type, host=None, resource=None, extensions=None,
103-
subprotocols=[]):
103+
subprotocols=None):
104104
self.client = conn_type is ConnectionType.CLIENT
105105

106106
self.host = host
107107
self.resource = resource
108108

109-
self.subprotocols = subprotocols
109+
self.subprotocols = subprotocols or []
110110
self.extensions = extensions or []
111111

112112
self.version = b'13'
@@ -393,6 +393,34 @@ def _process_connection_request(self, event):
393393

394394
return ConnectionRequested(proposed_subprotocols, event)
395395

396+
def _extension_accept(self, extensions_header):
397+
accepts = {}
398+
offers = _split_comma_header(extensions_header)
399+
400+
for offer in offers:
401+
name = offer.split(';', 1)[0].strip()
402+
for extension in self.extensions:
403+
if extension.name == name:
404+
accept = extension.accept(self, offer)
405+
if accept is True:
406+
accepts[extension.name] = True
407+
elif accept is not False and accept is not None:
408+
accepts[extension.name] = accept.encode('ascii')
409+
410+
if accepts:
411+
extensions = []
412+
for name, params in accepts.items():
413+
if params is True:
414+
extensions.append(name.encode('ascii'))
415+
else:
416+
# py34 annoyance: doesn't support bytestring formatting
417+
params = params.decode("ascii")
418+
extensions.append(('%s; %s' % (name, params))
419+
.encode("ascii"))
420+
return b', '.join(extensions)
421+
422+
return None
423+
396424
def accept(self, event, subprotocol=None):
397425
request = event.h11request
398426
request_headers = _normed_header_dict(request.headers)
@@ -413,31 +441,10 @@ def accept(self, event, subprotocol=None):
413441
headers[b'Sec-WebSocket-Protocol'] = subprotocol
414442

415443
extensions = request_headers.get(b'sec-websocket-extensions', None)
416-
accepts = {}
417-
if extensions is not None:
418-
offers = _split_comma_header(extensions)
419-
420-
for offer in offers:
421-
name = offer.split(';', 1)[0].strip()
422-
for extension in self.extensions:
423-
if extension.name == name:
424-
accept = extension.accept(self, offer)
425-
if accept is True:
426-
accepts[extension.name] = True
427-
elif accept is not False and accept is not None:
428-
accepts[extension.name] = accept.encode('ascii')
429-
430-
if accepts:
431-
extensions = []
432-
for name, params in accepts.items():
433-
if params is True:
434-
extensions.append(name.encode('ascii'))
435-
else:
436-
# py34 annoyance: doesn't support bytestring formatting
437-
params = params.decode("ascii")
438-
extensions.append(('%s; %s' % (name, params))
439-
.encode("ascii"))
440-
headers[b"Sec-WebSocket-Extensions"] = b', '.join(extensions)
444+
if extensions:
445+
accepts = self._extension_accept(extensions)
446+
if accepts:
447+
headers[b"Sec-WebSocket-Extensions"] = accepts
441448

442449
response = h11.InformationalResponse(status_code=101,
443450
headers=headers.items())

Diff for: wsproto/extensions.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@ def enabled(self):
1818
return False
1919

2020
def offer(self, connection):
21-
return None
21+
pass
2222

2323
def accept(self, connection, offer):
24-
return None
24+
pass
2525

2626
def finalize(self, connection, offer):
27-
return None
27+
pass
2828

2929
def frame_inbound_header(self, proto, opcode, rsv, payload_length):
3030
return RsvBits(False, False, False)
@@ -33,7 +33,7 @@ def frame_inbound_payload_data(self, proto, data):
3333
return data
3434

3535
def frame_inbound_complete(self, proto, fin):
36-
return None
36+
pass
3737

3838
def frame_outbound(self, proto, opcode, rsv, data, fin):
3939
return (rsv, data)
@@ -164,7 +164,7 @@ def frame_inbound_header(self, proto, opcode, rsv, payload_length):
164164
else:
165165
bits = self.client_max_window_bits
166166
if self._decompressor is None:
167-
self._decompressor = zlib.decompressobj(-bits)
167+
self._decompressor = zlib.decompressobj(-int(bits))
168168

169169
return RsvBits(True, False, False)
170170

@@ -217,7 +217,7 @@ def frame_outbound(self, proto, opcode, rsv, data, fin):
217217
else:
218218
bits = self.server_max_window_bits
219219
self._compressor = zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION,
220-
zlib.DEFLATED, -bits)
220+
zlib.DEFLATED, -int(bits))
221221

222222
data = self._compressor.compress(bytes(data))
223223

Diff for: wsproto/frame_protocol.py

+25-22
Original file line numberDiff line numberDiff line change
@@ -131,17 +131,17 @@ def __init__(self, msg, code=CloseReason.PROTOCOL_ERROR):
131131
def _truncate_utf8(data, nbytes):
132132
if len(data) <= nbytes:
133133
return data
134-
else:
135-
# Truncate
136-
data = data[:nbytes]
137-
# But we might have cut a codepoint in half, in which case we want to
138-
# discard the partial character so the data is at least
139-
# well-formed. This is a little inefficient since it processes the
140-
# whole message twice when in theory we could just peek at the last
141-
# few characters, but since this is only used for close messages (max
142-
# length = 125 bytes) it really doesn't matter.
143-
data = data.decode("utf-8", errors="ignore").encode("utf-8")
144-
return data
134+
135+
# Truncate
136+
data = data[:nbytes]
137+
# But we might have cut a codepoint in half, in which case we want to
138+
# discard the partial character so the data is at least
139+
# well-formed. This is a little inefficient since it processes the
140+
# whole message twice when in theory we could just peek at the last
141+
# few characters, but since this is only used for close messages (max
142+
# length = 125 bytes) it really doesn't matter.
143+
data = data.decode("utf-8", errors="ignore").encode("utf-8")
144+
return data
145145

146146

147147
class Buffer(object):
@@ -231,9 +231,9 @@ def decode_payload(self, data, finished):
231231

232232

233233
class FrameDecoder(object):
234-
def __init__(self, client, extensions=[]):
234+
def __init__(self, client, extensions=None):
235235
self.client = client
236-
self.extensions = extensions
236+
self.extensions = extensions or []
237237

238238
self.buffer = Buffer()
239239

@@ -406,7 +406,7 @@ def __init__(self, client, extensions):
406406
def _process_close(self, frame):
407407
data = frame.payload
408408

409-
if len(data) == 0:
409+
if not data:
410410
# "If this Close control frame contains no status code, _The
411411
# WebSocket Connection Close Code_ is considered to be 1005"
412412
data = (CloseReason.NO_STATUS_RCVD, "")
@@ -519,18 +519,21 @@ def send_data(self, payload=b'', fin=True):
519519

520520
return self._serialize_frame(opcode, payload, fin)
521521

522+
def _make_fin_rsv_opcode(self, fin, rsv, opcode):
523+
fin = int(fin) << 7
524+
rsv = (int(rsv.rsv1) << 6) + (int(rsv.rsv2) << 5) + \
525+
(int(rsv.rsv3) << 4)
526+
opcode = int(opcode)
527+
528+
return fin | rsv | opcode
529+
522530
def _serialize_frame(self, opcode, payload=b'', fin=True):
523531
rsv = RsvBits(False, False, False)
524532
for extension in reversed(self.extensions):
525533
rsv, payload = extension.frame_outbound(self, opcode, rsv, payload,
526534
fin)
527535

528-
fin_rsv = 0
529-
for bit in rsv:
530-
fin_rsv <<= 1
531-
fin_rsv |= int(bit)
532-
fin_rsv |= (int(fin) << 3)
533-
fin_rsv_opcode = fin_rsv << 4 | opcode
536+
fin_rsv_opcode = self._make_fin_rsv_opcode(fin, rsv, opcode)
534537

535538
payload_length = len(payload)
536539
quad_payload = False
@@ -572,5 +575,5 @@ def _serialize_frame(self, opcode, payload=b'', fin=True):
572575
masking_key = os.urandom(4)
573576
masker = XorMaskerSimple(masking_key)
574577
return header + masking_key + masker.process(payload)
575-
else:
576-
return header + payload
578+
579+
return header + payload

0 commit comments

Comments
 (0)