# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
#
# SPDX-License-Identifier: MPL-2.0
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0.  If a copy of the MPL was not distributed with this
# file, you can obtain one at https://mozilla.org/MPL/2.0/.
#
# See the COPYRIGHT file distributed with this work for additional
# information regarding copyright ownership.

import socket
import ssl

from h2.config import H2Configuration
from h2.connection import H2Connection
from h2.settings import SettingCodes

import dns.message

import isctest.mark

pytestmark = [
    isctest.mark.with_libnghttp2,
    isctest.mark.with_fips_dh,
]


def test_settings_frame_flood(ns1, named_httpsport):
    msg = dns.message.make_query(".", "SOA")
    wire = msg.to_wire()

    with socket.create_connection((ns1.ip, named_httpsport), timeout=10) as sock:
        ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
        ctx.check_hostname = False
        ctx.verify_mode = ssl.CERT_NONE
        ctx.set_alpn_protocols(["h2"])

        with ctx.wrap_socket(sock, server_hostname=ns1.ip) as tls:
            config = H2Configuration(client_side=True, header_encoding="utf-8")
            conn = H2Connection(config=config)
            conn.initiate_connection()
            tls.sendall(conn.data_to_send())

            stream_id = conn.get_next_available_stream_id()
            conn.send_headers(
                stream_id,
                [
                    (":method", "POST"),
                    (":path", "/dns-query"),
                    (":scheme", "https"),
                    (":authority", f"{ns1.ip}:{named_httpsport}"),
                    ("content-type", "application/dns-message"),
                    ("accept", "application/dns-message"),
                    ("content-length", str(len(wire))),
                ],
            )
            conn.send_data(stream_id, wire, end_stream=True)
            tls.sendall(conn.data_to_send())

            for i in range(4096):
                try:
                    conn.update_settings(
                        {
                            SettingCodes.MAX_CONCURRENT_STREAMS: (i % 100) + 1,
                            SettingCodes.INITIAL_WINDOW_SIZE: i + 1,
                        }
                    )
                    tls.sendall(conn.data_to_send())
                except Exception:  # pylint: disable=broad-except
                    break

                if i % 500 == 0:
                    tls.settimeout(0.05)
                    try:
                        while (data := tls.recv(65535)) != b"":
                            conn.receive_data(data)
                            tls.sendall(conn.data_to_send())
                    except Exception:  # pylint: disable=broad-except
                        pass
