parse_txt_hdrs parses headers expressed in text and converts them
        into a series of H2Frames with the "correct" flags. A body can be provided  # noqa: E501
        in which case, the data frames are added, bearing the End Stream flag,
        instead of the H2HeadersFrame/H2ContinuationFrame. The generated frames
        may respect max_frm_sz (SETTINGS_MAX_FRAME_SIZE) and
        max_hdr_lst_sz (SETTINGS_MAX_HEADER_LIST_SIZE) if provided. The headers
        are split into multiple headers fragment (and H2Frames) to respect these  # noqa: E501
        limits. Also, a callback can be provided to tell if a header should be
        never indexed (sensitive headers, such as cookies), and another callback  # noqa: E501
        say if the header should be registered into the index table at all.
        For an header to be registered, the is_sensitive callback must return
        False AND the should_index callback should return True. This is the
        default behavior.

        @param str s: the string to parse for headers
        @param int stream_id: the stream id to use in the generated H2Frames
        @param str|None body: the eventual body of the request, that is added to the generated frames  # noqa: E501
        @param int max_frm_sz: the maximum frame size. This is used to split the headers and data frames according to  # noqa: E501
        the maximum frame size negotiated for this connection
        @param int max_hdr_lst_sz: the maximum size of a "header fragment" as defined in RFC7540  # noqa: E501
        @param callable is_sensitive: callback that returns True if the provided header is sensible and must be stored  # noqa: E501
        in a header packet requesting this header never to be indexed
        @param callable should_index: callback that returns True if the provided header should be stored in a header  # noqa: E501
        packet requesting indexation in the dynamic header table.
        @param bool register: whether to register new headers with incremental indexing as we parse them  # noqa: E501
        @raise Exception

def parse_txt_hdrs(self,
                       s,  # type: str
                       stream_id=1,  # type: int
                       body=None,  # type: Optional[str]
                       max_frm_sz=4096,  # type: int
                       max_hdr_lst_sz=0,  # type: int
                       is_sensitive=lambda n, v: False,  # type: Callable[[str, str], bool]  # noqa: E501
                       should_index=lambda x: False,  # type: Callable[[str], bool]  # noqa: E501
                       register=True,  # type: bool
                       ):
        # type: (...) -> H2Seq
        """ parse_txt_hdrs parses headers expressed in text and converts them
        into a series of H2Frames with the "correct" flags. A body can be provided  # noqa: E501
        in which case, the data frames are added, bearing the End Stream flag,
        instead of the H2HeadersFrame/H2ContinuationFrame. The generated frames
        may respect max_frm_sz (SETTINGS_MAX_FRAME_SIZE) and
        max_hdr_lst_sz (SETTINGS_MAX_HEADER_LIST_SIZE) if provided. The headers
        are split into multiple headers fragment (and H2Frames) to respect these  # noqa: E501
        limits. Also, a callback can be provided to tell if a header should be
        never indexed (sensitive headers, such as cookies), and another callback  # noqa: E501
        say if the header should be registered into the index table at all.
        For an header to be registered, the is_sensitive callback must return
        False AND the should_index callback should return True. This is the
        default behavior.

        @param str s: the string to parse for headers
        @param int stream_id: the stream id to use in the generated H2Frames
        @param str|None body: the eventual body of the request, that is added to the generated frames  # noqa: E501
        @param int max_frm_sz: the maximum frame size. This is used to split the headers and data frames according to  # noqa: E501
        the maximum frame size negotiated for this connection
        @param int max_hdr_lst_sz: the maximum size of a "header fragment" as defined in RFC7540  # noqa: E501
        @param callable is_sensitive: callback that returns True if the provided header is sensible and must be stored  # noqa: E501
        in a header packet requesting this header never to be indexed
        @param callable should_index: callback that returns True if the provided header should be stored in a header  # noqa: E501
        packet requesting indexation in the dynamic header table.
        @param bool register: whether to register new headers with incremental indexing as we parse them  # noqa: E501
        @raise Exception
        """

        sio = BytesIO(s)

        base_frm_len = len(raw(H2Frame()))

        ret = H2Seq()
        cur_frm = H2HeadersFrame()  # type: Union[H2HeadersFrame, H2ContinuationFrame]  # noqa: E501
        cur_hdr_sz = 0

        # For each line in the headers str to parse
        for hdr_line in sio:
            hdr_name, hdr_value = self._parse_header_line(hdr_line)
            if hdr_name is None:
                continue

            new_hdr, new_hdr_len = self._convert_a_header_to_a_h2_header(
                hdr_name, hdr_value, is_sensitive, should_index
            )
            new_hdr_bin_len = len(raw(new_hdr))

            if register and isinstance(new_hdr, HPackLitHdrFldWithIncrIndexing):  # noqa: E501
                self.register(new_hdr)

            # The new header binary length (+ base frame size) must not exceed
            # the maximum frame size or it will just never fit. Also, the
            # header entry length (as specified in RFC7540 par6.5.2) must not
            # exceed the maximum length of a header fragment or it will just
            # never fit
            if (new_hdr_bin_len + base_frm_len > max_frm_sz or
                    (max_hdr_lst_sz != 0 and new_hdr_len > max_hdr_lst_sz)):
                raise Exception('Header too long: {}'.format(hdr_name))

            if (max_frm_sz < len(raw(cur_frm)) + base_frm_len + new_hdr_len or
                (
                    max_hdr_lst_sz != 0 and
                    max_hdr_lst_sz < cur_hdr_sz + new_hdr_len
            )
            ):
                flags = set()
                if isinstance(cur_frm, H2HeadersFrame) and not body:
                    flags.add('ES')
                ret.frames.append(H2Frame(stream_id=stream_id, flags=flags) / cur_frm)  # noqa: E501
                cur_frm = H2ContinuationFrame()
                cur_hdr_sz = 0

            hdr_list = cur_frm.hdrs
            hdr_list += new_hdr
            cur_hdr_sz += new_hdr_len

        flags = {'EH'}
        if isinstance(cur_frm, H2HeadersFrame) and not body:
            flags.add('ES')
        ret.frames.append(H2Frame(stream_id=stream_id, flags=flags) / cur_frm)

        if body:
            base_data_frm_len = len(raw(H2DataFrame()))
            sio = BytesIO(body)
            frgmt = sio.read(max_frm_sz - base_data_frm_len - base_frm_len)
            while frgmt:
                nxt_frgmt = sio.read(max_frm_sz - base_data_frm_len - base_frm_len)  # noqa: E501
                flags = set()
                if len(nxt_frgmt) == 0:
                    flags.add('ES')
                ret.frames.append(
                    H2Frame(stream_id=stream_id, flags=flags) / H2DataFrame(data=frgmt)  # noqa: E501
                )
                frgmt = nxt_frgmt
        return ret