docs: def parse_content_range_header(value, on_update=None):
      """Parses a range header into a
      :class:`~werkzeug.datastructures.ContentRange` object or `None` if
      parsing is not possible.
  
      .. versionadded:: 0.7
  
      :param value: a content range header to be parsed.
      :param on_update: an optional callable that is called every time a value
                        on the :class:`~werkzeug.datastructures.ContentRange`
                        object is changed.
      """
      if value is None:
          return None
      try:
          units, rangedef = (value or '').strip().split(None, 1)
      except ValueError:
          return None
  
      if '/' not in rangedef:
          return None
      rng, length = rangedef.split('/', 1)
      if length == '*':
          length = None
      elif length.isdigit():
          length = int(length)
      else:
          return None
  
      if rng == '*':
          return ContentRange(units, None, None, length, on_update=on_update)
      elif '-' not in rng:
          return None
  
      start, stop = rng.split('-', 1)
      try:
          start = int(start)
          stop = int(stop) + 1
      except ValueError:
          return None
  
      if is_byte_range_valid(start, stop, length):
          return ContentRange(units, start, stop, length, on_update=on_update)