|
1 | 1 | defmodule HTTP2ProtocolTest do |
2 | 2 | use ExUnit.Case, async: true |
3 | 3 | use ServerHelpers |
| 4 | + use Machete |
4 | 5 |
|
5 | 6 | import Bitwise |
6 | 7 |
|
@@ -233,6 +234,16 @@ defmodule HTTP2ProtocolTest do |
233 | 234 | assert_receive {:log, %{level: :error, msg: {:string, msg}}}, 500 |
234 | 235 | assert msg == "** (Bandit.HTTP2.Errors.ConnectionError) Connection count exceeded" |
235 | 236 | end |
| 237 | + |
| 238 | + @tag :capture_log |
| 239 | + test "max_requests zero does not put a limit", context do |
| 240 | + context = https_server(context, http_2_options: [max_requests: 0]) |
| 241 | + socket = SimpleH2Client.setup_connection(context) |
| 242 | + port = context[:port] |
| 243 | + SimpleH2Client.send_simple_headers(socket, 1, :get, "/body_response", port) |
| 244 | + {:ok, 1, false, _, _} = SimpleH2Client.recv_headers(socket) |
| 245 | + assert SimpleH2Client.recv_body(socket) == {:ok, 1, true, "OK"} |
| 246 | + end |
236 | 247 | end |
237 | 248 |
|
238 | 249 | describe "settings exchange" do |
@@ -3050,4 +3061,99 @@ defmodule HTTP2ProtocolTest do |
3050 | 3061 | echo_components(conn) |
3051 | 3062 | end |
3052 | 3063 | end |
| 3064 | + |
| 3065 | + describe "max_concurrent_streams flag" do |
| 3066 | + test "refuses streams when max_concurrent_streams limit is exceeded", context do |
| 3067 | + context = |
| 3068 | + context |
| 3069 | + |> https_server(http_2_options: [default_local_settings: [max_concurrent_streams: 2]]) |
| 3070 | + |> Enum.into(context) |
| 3071 | + |
| 3072 | + port = context.port |
| 3073 | + |
| 3074 | + socket = setup_connection_with_custom_settings(context) |
| 3075 | + |
| 3076 | + {:ok, send_ctx} = |
| 3077 | + SimpleH2Client.send_simple_headers(socket, 1, :get, "/slow_body_response", port) |
| 3078 | + |
| 3079 | + {:ok, send_ctx} = |
| 3080 | + SimpleH2Client.send_simple_headers(socket, 3, :get, "/slow_body_response", port, send_ctx) |
| 3081 | + |
| 3082 | + {:ok, send_ctx} = |
| 3083 | + SimpleH2Client.send_simple_headers(socket, 5, :get, "/slow_body_response", port, send_ctx) |
| 3084 | + |
| 3085 | + t0 = for _ <- 1..3, do: SimpleH2Client.recv_frame(socket) |
| 3086 | + |
| 3087 | + # Now fourth stream should be accepted since we're below the limit again |
| 3088 | + SimpleH2Client.send_simple_headers(socket, 7, :get, "/echo", context.port, send_ctx) |
| 3089 | + |
| 3090 | + t1 = for _ <- 1..5, do: SimpleH2Client.recv_frame(socket) |
| 3091 | + |
| 3092 | + t0 |
| 3093 | + |> Enum.concat(t1) |
| 3094 | + |> assert |
| 3095 | + ~> in_any_order([ |
| 3096 | + {:ok, :headers, integer(), 1, string()}, |
| 3097 | + {:ok, :data, integer(), 1, "OK"}, |
| 3098 | + {:ok, :headers, integer(), 3, string()}, |
| 3099 | + {:ok, :data, integer(), 3, "OK"}, |
| 3100 | + {:ok, :rst_stream, 0, 5, <<7::32>>}, |
| 3101 | + {:ok, :headers, integer(), 7, string()}, |
| 3102 | + {:ok, :data, integer(), 7, "OK"} |
| 3103 | + ]) |
| 3104 | + |
| 3105 | + assert Transport.recv(socket, 0) == {:error, :closed} |
| 3106 | + end |
| 3107 | + |
| 3108 | + test "allows new streams after previous streams complete", context do |
| 3109 | + context = |
| 3110 | + context |
| 3111 | + |> https_server(http_2_options: [default_local_settings: [max_concurrent_streams: 2]]) |
| 3112 | + |> Enum.into(context) |
| 3113 | + |
| 3114 | + port = context.port |
| 3115 | + |
| 3116 | + socket = setup_connection_with_custom_settings(context) |
| 3117 | + |
| 3118 | + {:ok, send_ctx} = |
| 3119 | + SimpleH2Client.send_simple_headers(socket, 1, :get, "/slow_body_response", port) |
| 3120 | + |
| 3121 | + {:ok, send_ctx} = |
| 3122 | + SimpleH2Client.send_simple_headers(socket, 3, :get, "/slow_body_response", port, send_ctx) |
| 3123 | + |
| 3124 | + t0 = for _ <- 1..2, do: SimpleH2Client.recv_frame(socket) |
| 3125 | + |
| 3126 | + SimpleH2Client.send_simple_headers(socket, 5, :get, "/slow_body_response", port, send_ctx) |
| 3127 | + |
| 3128 | + t1 = for _ <- 1..5, do: SimpleH2Client.recv_frame(socket) |
| 3129 | + |
| 3130 | + t0 |
| 3131 | + |> Enum.concat(t1) |
| 3132 | + |> assert |
| 3133 | + ~> in_any_order([ |
| 3134 | + {:ok, :headers, integer(), 1, string()}, |
| 3135 | + {:ok, :headers, integer(), 3, string()}, |
| 3136 | + {:ok, :headers, integer(), 5, string()}, |
| 3137 | + {:ok, :data, integer(), 1, "OK"}, |
| 3138 | + {:ok, :data, integer(), 3, "OK"}, |
| 3139 | + {:ok, :data, integer(), 5, "OK"}, |
| 3140 | + {:ok, :goaway, 0, 0, <<5::32, 0::32>>} |
| 3141 | + ]) |
| 3142 | + |
| 3143 | + assert Transport.recv(socket, 0) == {:error, :closed} |
| 3144 | + end |
| 3145 | + |
| 3146 | + def slow_body_response(conn) do |
| 3147 | + Process.sleep(50) |
| 3148 | + conn |> send_resp(200, "OK") |
| 3149 | + end |
| 3150 | + |
| 3151 | + # Helper function to set up connection when server has custom settings |
| 3152 | + defp setup_connection_with_custom_settings(context) do |
| 3153 | + socket = SimpleH2Client.tls_client(context) |
| 3154 | + SimpleH2Client.exchange_prefaces(socket, true) |
| 3155 | + SimpleH2Client.exchange_client_settings(socket) |
| 3156 | + socket |
| 3157 | + end |
| 3158 | + end |
3053 | 3159 | end |
0 commit comments