docs: def make_line_iter(stream, limit=None, buffer_size=10 * 1024, cap_at_buffer=False):
      """Safely iterates line-based over an input stream.  If the input stream
      is not a :class:`LimitedStream` the `limit` parameter is mandatory.
  
      This uses the stream's :meth:`~file.read` method internally as opposite
      to the :meth:`~file.readline` method that is unsafe and can only be used
      in violation of the WSGI specification.  The same problem applies to the
      `__iter__` function of the input stream which calls :meth:`~file.readline`
      without arguments.
  
      If you need line-by-line processing it's strongly recommended to iterate
      over the input stream using this helper function.
  
      .. versionchanged:: 0.8
         This function now ensures that the limit was reached.
  
      .. versionadded:: 0.9
         added support for iterators as input stream.
  
      .. versionadded:: 0.11.10
         added support for the `cap_at_buffer` parameter.
  
      :param stream: the stream or iterate to iterate over.
      :param limit: the limit in bytes for the stream.  (Usually
                    content length.  Not necessary if the `stream`
                    is a :class:`LimitedStream`.
      :param buffer_size: The optional buffer size.
      :param cap_at_buffer: if this is set chunks are split if they are longer
                            than the buffer size.  Internally this is implemented
                            that the buffer size might be exhausted by a factor
                            of two however.
      """
      _iter = _make_chunk_iter(stream, limit, buffer_size)
  
      first_item = next(_iter, "")
      if not first_item:
          return
  
      s = make_literal_wrapper(first_item)
      empty = s("")
      cr = s("\r")
      lf = s("\n")
      crlf = s("\r\n")
  
      _iter = chain((first_item,), _iter)
  
      def _iter_basic_lines():
          _join = empty.join
          buffer = []
          while 1:
              new_data = next(_iter, "")
              if not new_data:
                  break
              new_buf = []
              buf_size = 0
              for item in chain(buffer, new_data.splitlines(True)):
                  new_buf.append(item)
                  buf_size += len(item)
                  if item and item[-1:] in crlf:
                      yield _join(new_buf)
                      new_buf = []
                  elif cap_at_buffer and buf_size >= buffer_size:
                      rv = _join(new_buf)
                      while len(rv) >= buffer_size:
                          yield rv[:buffer_size]
                          rv = rv[buffer_size:]
                      new_buf = [rv]
              buffer = new_buf
          if buffer:
              yield _join(buffer)
  
      # This hackery is necessary to merge 'foo\r' and '\n' into one item
      # of 'foo\r\n' if we were unlucky and we hit a chunk boundary.
      previous = empty
      for item in _iter_basic_lines():
          if item == lf and previous[-1:] == cr:
              previous += item
              item = empty
          if previous:
              yield previous
          previous = item
      if previous:
          yield previous