Skip to content

Commit 176d30e

Browse files
authored
Support HTTP headers with a size up to 8k (#36)
By default cowboy accepts request headers for a max size of [4k](https://ninenines.eu/docs/en/cowboy/2.12/manual/cowboy_http/) (It is not clear if is the max size of each http header, or the max size for the sum of all headers). With the default configuration, Neurow returns 431 HTTP errors when the requests also contains very long cookies. This PR extends the max value to 8k and make it customizable by an environment variable.
1 parent e38269e commit 176d30e

File tree

4 files changed

+30
-2
lines changed

4 files changed

+30
-2
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ Available environment variables are:
3535
| `PREFLIGHT_MAX_AGE` | 86400 | Value of the `access-control-max-age` headers on CROS preflight responses on the public API |
3636
| `SSE_TIMEOUT` | 900000 | SSE deconnection delay in ms, after the last received message
3737
| `SSE_KEEPALIVE` | 600000 | Neurow periodically send `ping` events on SSE connections to prevent connections from being closed by network devices. This variable defines the delay between two ping events in milliseconds. |
38+
| `MAX_HEADER_VALUE_LENGTH`| 8192 | Max http request headers size, as expected by the cowboy HTTP server [here](https://ninenines.eu/docs/en/cowboy/2.12/manual/cowboy_http/) |
3839
| `INTERNAL_API_PORT` | 3000 | TCP port fo the internal API |
3940
| `INTERNAL_API_JWT_MAX_LIFETIME` | 1500 | Max lifetime in seconds allowed for JWT tokens issued on the internal API |
4041
| `HISTORY_MIN_DURATION` | 30 | Messages are persisted in the Neurow cluster, so clients can re-fetch recent messages after a short term disconnection by using the `Last-Event-Id` on SSE connections. Messages are only persisted for a limited time. `HISTORY_MIN_DURATION` defines the minimum retention guaranteed by the Neurow server.

neurow/config/runtime.exs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ config :neurow,
2828
public_api_preflight_max_age: String.to_integer(System.get_env("PREFLIGHT_MAX_AGE") || "86400"),
2929
public_api_context_path: System.get_env("PUBLIC_API_CONTEXT_PATH") || "",
3030
sse_timeout: String.to_integer(System.get_env("SSE_TIMEOUT") || "900000"),
31-
sse_keepalive: String.to_integer(System.get_env("SSE_KEEPALIVE") || "600000")
31+
sse_keepalive: String.to_integer(System.get_env("SSE_KEEPALIVE") || "600000"),
32+
max_header_value_length: String.to_integer(System.get_env("MAX_HEADER_VALUE_LENGTH") || "8192")
3233

3334
# Internal API configuration
3435
config :neurow,

neurow/integration_test/sse_livecycle_test.exs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,26 @@ defmodule Neurow.IntegrationTest.SseLifecycleTest do
107107
end
108108
end
109109

110+
describe "header HTTP size" do
111+
test "supports HTTP headers up to 8k with the default configuration", %{
112+
cluster_state: %{
113+
public_api_ports: [first_public_port | _other_ports]
114+
}
115+
} do
116+
fake_cookie = String.duplicate("a", 8_000)
117+
118+
subscribe(
119+
first_public_port,
120+
"test_topic",
121+
fn ->
122+
assert_receive %HTTPoison.AsyncStatus{code: 200}
123+
assert_receive %HTTPoison.AsyncHeaders{}
124+
end,
125+
cookie: fake_cookie
126+
)
127+
end
128+
end
129+
110130
def override_timeout(timeout) do
111131
{:ok, default_timeout} = Application.fetch_env(:neurow, :sse_timeout)
112132
TestCluster.update_sse_timeout(timeout)

neurow/lib/neurow/application.ex

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ defmodule Neurow.Application do
1616
{:ok, ssl_keyfile} = Application.fetch_env(:neurow, :ssl_keyfile)
1717
{:ok, ssl_certfile} = Application.fetch_env(:neurow, :ssl_certfile)
1818
{:ok, history_min_duration} = Application.fetch_env(:neurow, :history_min_duration)
19+
{:ok, max_header_value_length} = Application.fetch_env(:neurow, :max_header_value_length)
1920

2021
cluster_topologies =
2122
Application.get_env(:neurow, :cluster_topologies, cluster_topologies_from_env_variables())
@@ -25,6 +26,7 @@ defmodule Neurow.Application do
2526
internal_api_port: internal_api_port,
2627
ssl_keyfile: ssl_keyfile,
2728
ssl_certfile: ssl_certfile,
29+
max_header_value_length: max_header_value_length,
2830
history_min_duration: history_min_duration,
2931
cluster_topologies: cluster_topologies
3032
})
@@ -35,6 +37,7 @@ defmodule Neurow.Application do
3537
internal_api_port: internal_api_port,
3638
ssl_keyfile: ssl_keyfile,
3739
ssl_certfile: ssl_certfile,
40+
max_header_value_length: max_header_value_length,
3841
history_min_duration: history_min_duration,
3942
cluster_topologies: cluster_topologies
4043
}) do
@@ -43,7 +46,10 @@ defmodule Neurow.Application do
4346

4447
base_public_api_http_config = [
4548
port: public_api_port,
46-
protocol_options: [idle_timeout: :infinity],
49+
protocol_options: [
50+
max_header_value_length: max_header_value_length,
51+
idle_timeout: :infinity
52+
],
4753
transport_options: [max_connections: :infinity]
4854
]
4955

0 commit comments

Comments
 (0)