Skip to content

Parse server iCalendar through vcal.parse_ical() consistently #698

Description

@tobixen

Issue below was AI-generated, the introduction has been hand-edited


vcal.parse_ical() was added to handle CalDAV-noise before it would
cause a ValueError exception coming from the icalendar library.
The "CalDAV-noise" can be a body with no iCalendar in it - an empty
scheduling-inbox object, an HTML error page delivered with a 200, a
notification carrying only headers, etc. parse_ical() raises
error.ResponseError instead, quoting what arrived and the URL where
one is known.

It is currently used at four of the parse sites, and there are others that still
hand data to the parser directly. Anything that can be fed by a server should go
through the guard, so the error is the same everywhere.

Sites still parsing directly

  • caldav/jmap/objects/calendar_object.py:64 -
    icalendar.Calendar.from_ical(jscal_to_ical(self.data)). Server-fed: self.data
    is JSCalendar from a JMAP response, so a server that returns something
    unconvertible lands here. This is the one that matters.
  • caldav/datastate.py:140, :192, :228 and
    caldav/calendarobjectresource.py:1612 - vobject.readOne(...). Same data,
    different parser, same problem: an empty body gives a vobject error that says
    nothing about where it came from. A parse_vobject() counterpart, or one guard
    the two share, would cover it.
  • caldav/lib/vcal.py:243 (inside create_ical()) and
    caldav/jmap/convert/ical_to_jscal.py:306 - both parse iCalendar the caller
    supplied, not a server response. Arguably these should keep raising whatever
    icalendar raises, since a broken fragment there is a client-side bug, not a
    server one. Worth deciding explicitly rather than by omission.

Points worth deciding

  • Should the guard fire on the JSCalendar side too - a JMAP response that
    converts to no components at all - or only once it has become iCalendar?
  • parse_ical() is deliberately narrow: it fires only when the body holds no
    BEGIN: line, and hands anything containing a component to icalendar unchanged.
    That boundary should stay wherever it is applied, so that a genuinely malformed
    calendar is not reclassified as a server error.
  • A test that walks the module tree and fails on a bare
    icalendar.Calendar.from_ical( / vobject.readOne( outside the guard would keep
    this from drifting back. Cheap, and the kind of rule that only holds if it is
    enforced.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions