Lowercase "upgrade" value in Connection header may prevent connection upgrade

Open Beginner friendly
#42 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
74/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Quiet
Tech stack
elixir
Domain
networking

Research direction

Start in Mint.WebSocket.Utils.headers/2, especially the HTTP/1 header list shown in the issue, and review how header casing is handled by Mint. Reproduce the websocket upgrade against the reported server or an equivalent HTTP/1 endpoint, then verify that the generated handshake is accepted without requiring a duplicate custom Connection header.

Written by the indexing model from the issue text.

Description

  1. Description of issue

I wasted several hours today trying to figure out why MintWebSocket.upgrade/5 was failing when connecting to a websocket at wss://demo.rss.chat/

I noted that other websocket clients were succeeding and went to compare the headers that were sent at the upgrade request.

This particular server rejects the standard Mint.WebSocket.upgrade/5 call with a status 400 and a somewhat misleading message:

HTTP/1.1 400 Bad Request
Alt-Svc: h3=":443"; ma=2592000
Content-Type: text/html
Date: Mon, 17 Aug 2026 00:13:04 GMT
Server: Caddy
Transfer-Encoding: chunked

34
This HTTP server can't handle WebSocket connections.

I finally tracked down the issue to the fact that MintWebSocket.upgrade/5 sends a Connection header with the value "upgrade" in lowercase. When that is changed to "Upgrade" (capitalized), the socket is upgraded successfully.

  1. Possible fix

Mint.WebSocket.Utils.headers/2 shows the following:

  # header names are written in their conventional casing: Mint lowercases them
  # unless the connection was opened with `case_sensitive_headers: true`
  def headers({:http1, nonce}, extensions) when is_binary(nonce) do
    [
      {"Upgrade", "websocket"},
      {"Connection", "upgrade"},
      {"Sec-WebSocket-Version", "13"},
      {"Sec-WebSocket-Key", nonce},
      {"Sec-WebSocket-Extensions", extension_string(extensions)}
    ]
    |> Enum.reject(fn {_k, v} -> v == "" end)
  end

When I changed {"Connection", "upgrade"} to {"Connection", "Upgrade"} (capitalized), the connection succeeded. All of the non-normative examples in RFC6445 section 1.1 and 1.2 show the handshake headers using the capitalized "Upgrade" and the lowercase "websocket".

I believe that Mint.WebSocket.Utils.headers/2 should return the capitalized version.

For this particular server I was able to connect by supplying my own {"Connection", "Upgrade"} header (so that both values, "upgrade" and "Upgrade", are sent to the server in that order), but I don't know if that will work generally or not.

Dominant language
Elixir
Stars
151
Forks
17
PR merge metrics
No merged PRs in 30d

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from elixir-mint/mint_web_socket

All issues in elixir-mint/mint_web_socket

Similar issues

More Elixir issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.