OSingh commented on code in PR #1090:
URL: https://github.com/apache/yunikorn-core/pull/1090#discussion_r3380158360


##########
pkg/webservice/gzip.go:
##########
@@ -0,0 +1,170 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package webservice
+
+import (
+       "bytes"
+       "compress/gzip"
+       "net/http"
+       "strings"
+
+       "go.uber.org/zap"
+
+       "github.com/apache/yunikorn-core/pkg/log"
+)
+
+// minCompressionSize is the minimum response body size in bytes required 
before gzip
+// compression is applied. Responses smaller than this threshold are sent 
uncompressed
+// because the gzip framing overhead would exceed any size savings. The value 
is set
+// below the typical Ethernet MTU (1500 bytes) to account for TCP/IP and HTTP 
header
+// overhead, ensuring a small response body fits within a single network 
packet.
+var minCompressionSize = 1400
+
+// deferredGzipResponseWriter buffers the first minCompressionSize bytes of the
+// response body and defers the compression decision until either the buffer 
is full
+// (switch to gzip streaming) or the handler returns (send raw if still under 
threshold).
+// This avoids the memory cost of buffering the entire response while still 
skipping
+// gzip for small payloads where the overhead outweighs the savings.
+type deferredGzipResponseWriter struct {
+       http.ResponseWriter
+       buf        bytes.Buffer
+       gz         *gzip.Writer
+       statusCode int
+       decided    bool
+       useGzip    bool
+}
+
+// WriteHeader captures the status code until the compression decision is 
made, then
+// forwards it to the underlying ResponseWriter.
+func (d *deferredGzipResponseWriter) WriteHeader(code int) {
+       if d.decided {
+               d.ResponseWriter.WriteHeader(code)
+               return
+       }
+       d.statusCode = code
+}
+
+// Write buffers incoming bytes until the threshold is reached, at which point 
it
+// commits to gzip streaming. After the decision is made, writes go directly 
to the
+// chosen writer.
+func (d *deferredGzipResponseWriter) Write(b []byte) (int, error) {
+       if d.decided {
+               if d.useGzip {
+                       return d.gz.Write(b)
+               }
+               return d.ResponseWriter.Write(b)
+       }
+
+       n, err := d.buf.Write(b)
+       if d.buf.Len() >= minCompressionSize {
+               d.switchToGzip()
+       }
+       return n, err
+}
+
+// switchToGzip commits to gzip encoding: sets response headers, flushes the 
buffered
+// bytes through the gzip writer, and marks the decision as final.
+func (d *deferredGzipResponseWriter) switchToGzip() {
+       d.decided = true
+       d.useGzip = true
+       d.ResponseWriter.Header().Set("Content-Encoding", "gzip")
+       d.ResponseWriter.Header().Add("Vary", "Accept-Encoding")
+       if d.statusCode != 0 {
+               d.ResponseWriter.WriteHeader(d.statusCode)
+       }
+       _, _ = d.gz.Write(d.buf.Bytes())

Review Comment:
   Now I have logged the error message for this.



##########
pkg/webservice/gzip.go:
##########
@@ -0,0 +1,170 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package webservice
+
+import (
+       "bytes"
+       "compress/gzip"
+       "net/http"
+       "strings"
+
+       "go.uber.org/zap"
+
+       "github.com/apache/yunikorn-core/pkg/log"
+)
+
+// minCompressionSize is the minimum response body size in bytes required 
before gzip
+// compression is applied. Responses smaller than this threshold are sent 
uncompressed
+// because the gzip framing overhead would exceed any size savings. The value 
is set
+// below the typical Ethernet MTU (1500 bytes) to account for TCP/IP and HTTP 
header
+// overhead, ensuring a small response body fits within a single network 
packet.
+var minCompressionSize = 1400
+
+// deferredGzipResponseWriter buffers the first minCompressionSize bytes of the
+// response body and defers the compression decision until either the buffer 
is full
+// (switch to gzip streaming) or the handler returns (send raw if still under 
threshold).
+// This avoids the memory cost of buffering the entire response while still 
skipping
+// gzip for small payloads where the overhead outweighs the savings.
+type deferredGzipResponseWriter struct {
+       http.ResponseWriter
+       buf        bytes.Buffer
+       gz         *gzip.Writer
+       statusCode int
+       decided    bool
+       useGzip    bool
+}
+
+// WriteHeader captures the status code until the compression decision is 
made, then
+// forwards it to the underlying ResponseWriter.
+func (d *deferredGzipResponseWriter) WriteHeader(code int) {
+       if d.decided {
+               d.ResponseWriter.WriteHeader(code)
+               return
+       }
+       d.statusCode = code
+}
+
+// Write buffers incoming bytes until the threshold is reached, at which point 
it
+// commits to gzip streaming. After the decision is made, writes go directly 
to the
+// chosen writer.
+func (d *deferredGzipResponseWriter) Write(b []byte) (int, error) {
+       if d.decided {
+               if d.useGzip {
+                       return d.gz.Write(b)
+               }
+               return d.ResponseWriter.Write(b)
+       }
+
+       n, err := d.buf.Write(b)
+       if d.buf.Len() >= minCompressionSize {
+               d.switchToGzip()
+       }
+       return n, err
+}
+
+// switchToGzip commits to gzip encoding: sets response headers, flushes the 
buffered
+// bytes through the gzip writer, and marks the decision as final.
+func (d *deferredGzipResponseWriter) switchToGzip() {
+       d.decided = true
+       d.useGzip = true
+       d.ResponseWriter.Header().Set("Content-Encoding", "gzip")
+       d.ResponseWriter.Header().Add("Vary", "Accept-Encoding")
+       if d.statusCode != 0 {
+               d.ResponseWriter.WriteHeader(d.statusCode)
+       }
+       _, _ = d.gz.Write(d.buf.Bytes())
+       d.buf.Reset()
+}
+
+// finalize is called via defer after the handler returns. If no compression 
decision
+// was made yet (response stayed below threshold), the buffered bytes are 
written raw.
+// The gzip writer is closed if compression was used.
+func (d *deferredGzipResponseWriter) finalize() {
+       if !d.decided {
+               d.decided = true
+               if d.statusCode != 0 {
+                       d.ResponseWriter.WriteHeader(d.statusCode)
+               }
+               _, _ = d.ResponseWriter.Write(d.buf.Bytes())

Review Comment:
   Now I have logged the error message for this.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to