LIST responses and \HasChildren, \HasNoChildren flags

ellie timoney ellie at fastmail.com
Mon Sep 5 22:46:04 EDT 2016


Our handling of the \HasChildren and \HasNoChildren flags in list
responses is currently inconsistent -- though not strictly in violation
of RFC (with the exception of a known bug in 2.5).  

[We pass our Cassandane List tests because they have these
inconsistencies baked into their expected results -- my fault, I wrote
the initial set based on "what Cyrus currently did at the time" and
they've grown from there.]

https://tools.ietf.org/html/rfc5258#section-4 :
>   The CHILDREN return option defines two new attributes that MUST be
>   returned within a LIST response: \HasChildren and \HasNoChildren.
>   Although these attributes MAY be returned in response to any LIST
>   command, the CHILDREN return option is provided to indicate that the
>   client particularly wants this information.  If the CHILDREN return
>   option is present, the server MUST return these attributes even if
>   their computation is expensive.

There's two points in here:

    1. If the client explicitly requests RETURN (CHILDREN), we MUST
    return \HasChildren or \HasNoChildren appropriately for each
    mailbox.

    2. We MAY return \HasChildren or \HasNoChildren in response to any
    other list command.

We handle (1) correctly, so we're in compliance.  The inconsistency is
in the handling of (2):

    a. For non-extended LIST/RLIST/XLIST, we act as if the client had
    requested CHILDREN, and return these attributes appropriately.

    b. For most extended list commands, if the client explicitly does
    not request the CHILDREN return option, we still return these
    attributes.  The RFC doesn't specifically state what to do in this
    case, which I think means (2) applies, and that this is therefore
    okay.  (The aforementioned known bug in 2.5 occurs in this case.)

    c. If the client is listing subscribed folders, using 'LIST
    (SUBSCRIBED) ...' or 'LSUB ...' (or their X/R variants), and does
    not explicitly request RETURN (CHILDREN), then we only return the
    \HasChildren attribute appropriately.  Subscribed mailboxes without
    children do not get the \HasNoChildren attribute in their response.

    d. For 'LIST (RECURSIVEMATCH) ...', I believe we return the child
    attributes only if RETURN (CHILDREN) was explicitly requested. But
    we don't have tests for this yet, so I'm not certain.

With the exception of the 2.5 bug, this inconsistency affects both 2.5
and master.

>From the current implementation, it's ambiguous to me what the intended
behaviour is:

    * (a) shakes out as a combination of cmdloop() explicitly
    initialising listargs.ret with LIST_RET_CHILDREN for these commands
    (intent: always return child attributes?), and list_response()
    ensuring that if LIST_RET_CHILDREN is set, that these attributes are
    included (which is how we successfully handle (1)).
    * for (b), getlistargs() explicitly resets listargs.ret to 0 if it's
    an extended list command, overriding cmdloop()'s initialisation
    (intent: for extended list commands, only return what was
    requested?)... but then list_cb() sets the child attributes
    unconditionally anyway (intent: always return child attributes?)
   * (c) occurs because subscribed_cb() sets the \HasChildren flag in
   the same way list_cb() does, i.e. without regard to the return
   options (intent: always return child attributes?).  but it does not
   set \HasNoChildren at all, so the only way the latter gets set is if
   CHILDREN was requested, in which case list_response() fills it in
   * (d) occurs because recursivematch_cb() does not set the child
   attributes at all, and so it falls to list_response() to fill them in
   later, which, because of getlistargs()'s extended list command
   behaviour, it only does if CHILDREN was explicitly requested.

Generally it looks like the intent is to just always return the child
attributes, whether they were requested or not (in which case
subscribed_cb() has a bug whereby it omits the \HasNoChildren flag, and
recursivematch_cb() whereby it omits both).

But getlistargs()'s behaviour looks like we wanted to make an exception
for extended list commands, such that we'd only return what was asked
for (in which case list_cb() and subscribed_cb() both have a bug,
because they ignore this intent).

I think I understand these code paths well enough now to tidy this up
fairly easily (and knock off that 2.5 bug along the way), I just need
clarification on how we want it to work.

So I guess my questions here are:

    * do we intend to generally return \HasChildren or \HasNoChildren,
    regardless of whether they were requested? (I think "yes")

    * do we intend to make an exception to this for extended list
    commands, such that we only return what was asked for? (I'm not
    sure)

[There's interactions with \NoInferiors here too, but that's dealt with
separately, so can be set aside for now.]

Cheers,

ellie


More information about the Cyrus-devel mailing list