Temporary workaround or middleware for HTTP header case preservation (#466, #11307)

Context

I'm fully aware of the discussions in issues like #466 and #11307. I completely understand that Traefik follows Go's standard net/http canonical MIME header formatting and that per HTTP RFC specifications, headers are strictly case-insensitive. Technically, this is not a bug in Traefik.

The Problem / Use Case

We are currently in a critical operational bottleneck. We have a legacy backend application that strictly requires case-sensitive headers (e.g., SOAPAction or custom mixed-case headers) to function.
While a permanent fix has already been implemented in our application's codebase, our internal deployment pipeline cannot roll out the updated backend fast enough to prevent immediate production blocking.

Question

Since the commercial version of Traefik provides a native Force Case middleware to solve exactly this constraint, I would like to ask the maintainers and the community if there are any known workarounds or plugins.
Has there been any reconsideration regarding response/request header casing?

Thank you!

There's no Traefik option for this I think, but a small local plugin can work around it. Go canonicalizes keys when it parses the request, but http.Header is just a map and Go's HTTP/1.1 transport writes keys exactly as stored. So assigning the map entry directly (not via Header.Set) keeps your casing on the request to the backend:

func (h *HeaderCase) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	for canon, want := range h.names { // e.g. "Soapaction" -> "SOAPAction"
		if v, ok := req.Header[canon]; ok {
			delete(req.Header, canon)
			req.Header[want] = v
		}
	}
	h.next.ServeHTTP(rw, req)
}

Load it as a local plugin (source mounted at /plugins-local/src/<moduleName> with its .traefik.yml, plus --experimental.localPlugins.headercase.moduleName=<moduleName>) and put it last in the router's middleware list so nothing calls Header.Set after it.

Things worth checking: this only helps when Traefik talks HTTP/1.1 to the backend (HTTP/2 lowercases everything anyway), and I wouldn't expect it to survive the experimental fastProxy, since that uses a different client. Response headers can be handled the same way by wrapping the ResponseWriter and renaming keys in rw.Header() before WriteHeader.