Skip to content

fix server pagination #171

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 2 additions & 35 deletions ldaptor/protocols/ldap/ldapclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ def send(self, op, controls=None):
self.transport.write(msg.toWire())
return d

def send_multiResponse(self, op, handler, *args, **kwargs):
def send_multiResponse(self, op, controls=None, handler=None, *args, **kwargs):
"""
Send an LDAP operation to the server, expecting one or more
responses.
Expand All @@ -133,46 +133,13 @@ def send_multiResponse(self, op, handler, *args, **kwargs):
completes when the first response has been received
@rtype: Deferred LDAPProtocolResponse
"""
msg = self._send(op)
assert op.needs_answer
d = defer.Deferred()
self.onwire[msg.id] = (d, False, handler, args, kwargs)
self.transport.write(msg.toWire())
return d

def send_multiResponse_ex(self, op, controls=None, handler=None, *args, **kwargs):
"""
Send an LDAP operation to the server, expecting one or more
responses.

If `handler` is provided, it will receive a LDAP response *and*
response controls as its first 2 arguments. The Deferred returned
by this function will never fire.

If `handler` is not provided, the Deferred returned by this
function will fire with a tuple of the first LDAP response
and any associated response controls.

@param op: the operation to send
@type op: LDAPProtocolRequest
@param controls: LDAP controls to send with the message.
@type controls: LDAPControls
@param handler: a callable that will be called for each
response. It should return a boolean, whether this was the
final response.
@param args: positional arguments to pass to handler
@param kwargs: keyword arguments to pass to handler
@return: the result from the last handler as a deferred that
completes when the last response has been received
@rtype: Deferred LDAPProtocolResponse
"""
msg = self._send(op, controls=controls)
assert op.needs_answer
d = defer.Deferred()
self.onwire[msg.id] = (d, True, handler, args, kwargs)
self.transport.write(msg.toWire())
return d

def send_noResponse(self, op, controls=None):
"""
Send an LDAP operation to the server, with no response
Expand Down
15 changes: 10 additions & 5 deletions ldaptor/protocols/ldap/ldapserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,10 @@ def connectionLost(self, reason=protocol.connectionDone):
"""Called when TCP connection has been lost"""
self.connected = 0

def queue(self, id, op):
def queue(self, id, op, controls):
if not self.connected:
raise LDAPServerConnectionLostException()
msg = pureldap.LDAPMessage(op, id=id)
msg = pureldap.LDAPMessage(op, controls=controls, id=id)
Copy link
Author

@fastrde fastrde Apr 26, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

controls=None is handled in pureldap so no need to handle it here. so just pass it.

if self.debug:
log.msg('S->C %s' % repr(msg), debug=True)
self.transport.write(msg.toWire())
Expand Down Expand Up @@ -94,9 +94,14 @@ def _cbLDAPError(self, reason, name):
resultCode=reason.value.resultCode,
errorMessage=reason.value.message)

def _cbHandle(self, response, id):
if response is not None:
self.queue(id, response)
def _cbHandle(self, responseAndControls, id):
if (responseAndControls.__class__.__name__ == 'tuple'):
response, controls = responseAndControls
else:
response = responseAndControls
controls = None
if response is not None:
self.queue(id, response, controls)

def failDefault(self, resultCode, errorMessage):
return pureldap.LDAPExtendedResponse(
Expand Down
2 changes: 1 addition & 1 deletion ldaptor/protocols/ldap/ldapsyntax.py
Original file line number Diff line number Diff line change
Expand Up @@ -718,7 +718,7 @@ def search(self,
typesOnly=typesOnly,
filter=filterObject,
attributes=attributes)
dsend = self.client.send_multiResponse_ex(
dsend = self.client.send_multiResponse(
op,
controls,
self._cbSearchMsg,
Expand Down
2 changes: 1 addition & 1 deletion ldaptor/protocols/ldap/merger.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def _clientQueue(self, request, controls, reply):
# Controls are ignored.
for c in self.clients:
if request.needs_answer:
d = c.send_multiResponse(request, self._gotResponse, reply)
d = c.send_multiResponse(request, None, self._gotResponse, reply)
d.addErrback(defer.logError)
else:
c.send_noResponse(request)
Expand Down
2 changes: 1 addition & 1 deletion ldaptor/protocols/ldap/proxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def _cbConnectionMade(self, proto):
def _clientQueue(self, request, controls, reply):
# TODO controls
if request.needs_answer:
self.client.send_multiResponse(request, self._gotResponse, reply)
self.client.send_multiResponse(request, None, self._gotResponse, reply)
# TODO handle errbacks from the deferred above
else:
self.client.send_noResponse(request)
Expand Down
5 changes: 3 additions & 2 deletions ldaptor/protocols/ldap/proxybase.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ def forwardit(result, reply):
dseq = []
d2 = self.client.send_multiResponse(
request,
controls,
self._gotResponseFromProxiedServer,
reply,
request,
Expand All @@ -147,7 +148,7 @@ def handleBeforeForwardRequest(self, request, controls, reply):
"""
return defer.succeed((request, controls))

def _gotResponseFromProxiedServer(self, response, reply, request, controls, dseq):
def _gotResponseFromProxiedServer(self, response, response_controls, reply, request, controls, dseq):
"""
Returns True if this is the last response to the request.
"""
Expand All @@ -156,7 +157,7 @@ def _gotResponseFromProxiedServer(self, response, reply, request, controls, dseq

def replyAndLinkToNextEntry(result):
dseq.pop(0)
reply(result)
reply((result, response_controls))
if len(dseq) > 0:
dseq[0].addCallback(replyAndLinkToNextEntry)

Expand Down
8 changes: 4 additions & 4 deletions ldaptor/test/test_ldapclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ def test_send_not_connected(self):
def test_send_multiResponse(self):
client, transport = self.create_test_client()
op = self.create_test_search_req()
d = client.send_multiResponse(op, None)
d = client.send_multiResponse(op, None, None)
expected_value = pureldap.LDAPMessage(op)
expected_value.id -= 1
expected_bytestring = expected_value.toWire()
Expand Down Expand Up @@ -209,7 +209,7 @@ def collect_result_(result):
return True
return False

client.send_multiResponse(op, collect_result_)
client.send_multiResponse(op, None, collect_result_)
expected_value = pureldap.LDAPMessage(op)
expected_value.id -= 1
expected_bytestring = expected_value.toWire()
Expand All @@ -230,11 +230,11 @@ def collect_result_(result):
response.value,
results[1])

def test_send_multiResponse_ex(self):
def test_send_multiResponse_with_controls(self):
client, transport = self.create_test_client()
op = self.create_test_search_req()
controls = self.create_paged_search_controls()
d = client.send_multiResponse_ex(op, controls)
d = client.send_multiResponse(op, controls)
expected_value = pureldap.LDAPMessage(op, controls)
expected_value.id -= 1
expected_bytestring = expected_value.toWire()
Expand Down
16 changes: 5 additions & 11 deletions ldaptor/testutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,17 +92,11 @@ def send_multiResponse_(self, op, controls, return_controls, handler, *args, **k
assert ret, msg
return d

def send_multiResponse(self, op, handler, *args, **kwargs):
return self.send_multiResponse_(op, None, False, handler, *args, **kwargs)

def send_multiResponse_ex(self, op, controls, handler, *args, **kwargs):
return self.send_multiResponse_(
op,
controls,
True,
handler,
*args,
**kwargs)
def send_multiResponse(self, op, controls, handler, *args, **kwargs):
if controls == None:
return self.send_multiResponse_(op, None, False, handler, *args, **kwargs)
else:
return self.send_multiResponse_(op, controls, True, handler, *args, **kwargs)

def send_noResponse(self, op):
if len(self.responses) == 0:
Expand Down