Ilia Lazebnik created YUNIKORN-3341:
---------------------------------------

             Summary: gzip middleware double-compresses responses that handlers 
already encoded
                 Key: YUNIKORN-3341
                 URL: https://issues.apache.org/jira/browse/YUNIKORN-3341
             Project: Apache YuniKorn
          Issue Type: Bug
    Affects Versions: 1.9.0
            Reporter: Ilia Lazebnik


The gzip middleware on the REST router compresses any response whose buffered 
body exceeds \{{minCompressionSize}}, without checking whether the wrapped 
handler had already encoded the body itself.

{\{/ws/v1/metrics}} is served by \{{promhttp.Handler()}}, which performs its 
own gzip content negotiation: when the client sends \{{Accept-Encoding: gzip}} 
it compresses the payload and sets \{{Content-Encoding: gzip}}. The middleware 
then sees the same \{{Accept-Encoding}}, buffers promhttp's already-gzipped 
bytes, finds them over the threshold, and compresses a second time. 
\{{switchToGzip}} uses \{{Header().Set}}, so the response still advertises a 
single \{{Content-Encoding: gzip}} while carrying a doubly encoded body.

Clients decode once and get gzip framing instead of the payload. For Prometheus 
this means every scrape of \{{/ws/v1/metrics}} fails to parse and the target is 
marked down, so scheduler metrics are lost entirely for any scraper that 
advertises gzip support — which is the default.

Reproduced against a running 1.9.0 scheduler:

{code}
$ curl -s -D- -o body.bin http://scheduler:9080/ws/v1/metrics
200 OK, 69714 bytes, "# HELP go_gc_duration_seconds ..."

$ curl -s -D- -o body.gz -H 'Accept-Encoding: gzip' 
http://scheduler:9080/ws/v1/metrics
200 OK, Content-Encoding: gzip, 8839 bytes

$ gunzip -c body.gz | file -
/dev/stdin: gzip compressed data          # still gzip after one decode

$ gunzip -c body.gz | gunzip -c | head -1
# HELP go_gc_duration_seconds ...         # payload only after two
{code}

This is a regression in 1.9.0: \{{pkg/webservice/gzip.go}} is new in that 
release and \{{StartWebApp}} changed from \{{Handler: router}} to \{{Handler: 
compressResponse(router)}}. The route itself and port 9080 are unchanged from 
1.8.0.

*Proposed fix*

Treat a \{{Content-Encoding}} set by the handler as a signal that the body is 
already encoded, and pass the response through untouched. Metrics responses 
stay compressed — promhttp still gzips them, just once — and handlers that do 
not set \{{Content-Encoding}} are unaffected.

Fixing \{{getMetrics}} alone (via \{{promhttp.HandlerOpts{DisableCompression: 
true}}}) would patch only the one endpoint that self-encodes today; the 
middleware would still corrupt any future handler that does the same.

PR: https://github.com/apache/yunikorn-core/pull/1115



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to