elixir-mint / mint

Functional HTTP client for Elixir with support for HTTP/1 and HTTP/2 🌱
Apache License 2.0
1.37k stars 112 forks source link

HTTP/2 server settings are handled as client settings #384

Closed hissssst closed 1 year ago

hissssst commented 1 year ago

Overview

Setting server settings with put_settings fails, while the HTTP2 spec describes that all settings are negotiable.

Environment

$ uname -srm
Linux 5.15.90 x86_64

$ elixir --version
Erlang/OTP 25 [erts-13.1.4] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [jit:ns]

Elixir 1.14.3 (compiled with Erlang/OTP 25)

$ git log | head -n5
commit 1e70ccffbcce6f4d601661f22a700e001ce8e475
Author: Andrea leopardi <an.leopardi@gmail.com>
Date:   Mon Jun 13 14:29:25 2022 +0200

    Release v1.4.2

Reproduction

alias Mint.HTTP2

{:ok, conn} = HTTP2.connect(:https, "example.com", 443)
{:ok, conn} = HTTP2.put_settings(conn, initial_window_size: 2097152)
{:ok, conn, request_ref} = HTTP2.request(conn, "GET", "/", [], "")

msg = receive do: (msg -> msg)
{:ok, conn, _} = HTTP2.stream(conn, msg)

msg = receive do: (msg -> msg)
{:ok, conn, _} = HTTP2.stream(conn, msg)

Expected beavior

Option is set, no errors occurred

Actual behavior

** (FunctionClauseError) no function clause matching in anonymous fn/2 in Mint.HTTP2.apply_client_settings/2

    The following arguments were given to anonymous fn/2 in Mint.HTTP2.apply_client_settings/2:

        # 1
        {:initial_window_size, 2097152}

        # 2
        %Mint.HTTP2{
          transport: Mint.Core.Transport.SSL,
          socket: {:sslsocket, {:gen_tcp, #Port<0.7>, :tls_connection, :undefined},
           [#PID<0.276.0>, #PID<0.275.0>]},
          mode: :active,
          hostname: "example.com",
          port: 443,
          scheme: "https",
          state: :open,
          buffer: "",
          window_size: 1048576,
          encode_table: %HPAX.Table{
            max_table_size: 4096,
            entries: [],
            size: 0,
            length: 0
          },
          decode_table: %HPAX.Table{
            max_table_size: 4096,
            entries: [],
            size: 0,
            length: 0
          },
          ping_queue: {[], []},
          client_settings_queue: {[], []},
          next_stream_id: 5,
          streams: %{
            3 => %{
              id: 3,
              received_first_headers?: false,
              ref: #Reference<0.743732487.4142661637.136658>,
              state: :half_closed_local,
              window_size: 1048576
            }
          },
          open_client_stream_count: 1,
          open_server_stream_count: 0,
          ref_to_stream_id: %{#Reference<0.743732487.4142661637.136658> => 3},
          server_settings: %{
            enable_connect_protocol: false,
            enable_push: true,
            initial_window_size: 1048576,
            max_concurrent_streams: 100,
            max_frame_size: 16384,
            max_header_list_size: 16384
          },
          client_settings: %{
            enable_push: true,
            max_concurrent_streams: 100,
            max_frame_size: 16384
          },
          headers_being_processed: nil,
          proxy_headers: [],
          private: %{}
        }

    (mint 1.4.2) lib/mint/http2.ex:1798: anonymous fn/2 in Mint.HTTP2.apply_client_settings/2
    (elixir 1.14.3) lib/enum.ex:2468: Enum."-reduce/3-lists^foldl/2-0-"/3
    (mint 1.4.2) lib/mint/http2.ex:1752: Mint.HTTP2.handle_settings/3
    (mint 1.4.2) lib/mint/http2.ex:1380: Mint.HTTP2.handle_new_data/3
    (mint 1.4.2) lib/mint/http2.ex:1372: Mint.HTTP2.maybe_concat_and_handle_new_data/2
    (mint 1.4.2) lib/mint/http2.ex:793: Mint.HTTP2.stream/2
    iex:11: (file)
whatyouhide commented 1 year ago

lazyweb: can you link to the part of the spec that mentions this? 😄

hissssst commented 1 year ago

@whatyouhide https://httpwg.org/specs/rfc7540.html#SETTINGS

For example, a client might set a high initial flow-control window, whereas a server might set a lower value to conserve resources

And there is no definition of client or server settings in spec. All settings can be set by both client and server

Plus, put_settings function already performs validation of server settings.

astorre88 commented 1 year ago

please note that put_settings/2 support only client settings https://hexdocs.pm/mint/Mint.HTTP2.html#put_settings/2