Commit 2985fbce authored by Vincent Pelletier's avatar Vincent Pelletier

Avoid parsing packet header multiple times when there is not enough data.

git-svn-id: https://svn.erp5.org/repos/neo/trunk@2001 71dcc9de-d417-0410-9af5-da40c76e7ee4
parent c1101e85
...@@ -20,7 +20,7 @@ from time import time ...@@ -20,7 +20,7 @@ from time import time
from neo import logging from neo import logging
from neo.locking import RLock from neo.locking import RLock
from neo.protocol import PacketMalformedError, Packets from neo.protocol import PacketMalformedError, Packets, ParserState
from neo.connector import ConnectorException, ConnectorTryAgainException, \ from neo.connector import ConnectorException, ConnectorTryAgainException, \
ConnectorInProgressException, ConnectorConnectionRefusedException, \ ConnectorInProgressException, ConnectorConnectionRefusedException, \
ConnectorConnectionClosedException ConnectorConnectionClosedException
...@@ -293,6 +293,7 @@ class Connection(BaseConnection): ...@@ -293,6 +293,7 @@ class Connection(BaseConnection):
self.uuid = None self.uuid = None
self._queue = [] self._queue = []
self._on_close = None self._on_close = None
self._parser_state = ParserState()
event_manager.addReader(self) event_manager.addReader(self)
def setOnClose(self, callback): def setOnClose(self, callback):
...@@ -359,7 +360,7 @@ class Connection(BaseConnection): ...@@ -359,7 +360,7 @@ class Connection(BaseConnection):
while True: while True:
# parse a packet # parse a packet
try: try:
packet = Packets.parse(self.read_buf) packet = Packets.parse(self.read_buf, self._parser_state)
if packet is None: if packet is None:
break break
except PacketMalformedError, msg: except PacketMalformedError, msg:
......
...@@ -1575,6 +1575,21 @@ def register(code, request, answer=None): ...@@ -1575,6 +1575,21 @@ def register(code, request, answer=None):
return (request, answer) return (request, answer)
return request return request
class ParserState(object):
"""
Parser internal state.
To be considered opaque datatype outside of PacketRegistry.parse .
"""
payload = None
def set(self, payload):
self.payload = payload
def get(self):
return self.payload
def clear(self):
self.payload = None
class PacketRegistry(dict): class PacketRegistry(dict):
""" """
...@@ -1586,11 +1601,12 @@ class PacketRegistry(dict): ...@@ -1586,11 +1601,12 @@ class PacketRegistry(dict):
# load packet classes # load packet classes
self.update(StaticRegistry) self.update(StaticRegistry)
def parse(self, buf): def parse(self, buf, state_container):
if len(buf) < PACKET_HEADER_SIZE: state = state_container.get()
if state is None:
header = buf.read(PACKET_HEADER_SIZE)
if header is None:
return None return None
header = buf.peek(PACKET_HEADER_SIZE)
assert header is not None
msg_id, msg_type, msg_len = unpack(PACKET_HEADER_FORMAT, header) msg_id, msg_type, msg_len = unpack(PACKET_HEADER_FORMAT, header)
try: try:
packet_klass = self[msg_type] packet_klass = self[msg_type]
...@@ -1600,14 +1616,17 @@ class PacketRegistry(dict): ...@@ -1600,14 +1616,17 @@ class PacketRegistry(dict):
raise PacketMalformedError('message too big (%d)' % msg_len) raise PacketMalformedError('message too big (%d)' % msg_len)
if msg_len < MIN_PACKET_SIZE: if msg_len < MIN_PACKET_SIZE:
raise PacketMalformedError('message too small (%d)' % msg_len) raise PacketMalformedError('message too small (%d)' % msg_len)
if len(buf) < msg_len: msg_len -= PACKET_HEADER_SIZE
else:
msg_id, packet_klass, msg_len = state
data = buf.read(msg_len)
if data is None:
# Not enough. # Not enough.
state_container.set((msg_id, packet_klass, msg_len))
return None return None
buf.skip(PACKET_HEADER_SIZE) if state:
msg_len -= PACKET_HEADER_SIZE state_container.clear()
packet = packet_klass() packet = packet_klass()
data = buf.read(msg_len)
assert data is not None
packet.setContent(msg_id, data) packet.setContent(msg_id, data)
return packet return packet
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment