| 
									
										
										
										
											2015-01-22 03:07:45 +08:00
										 |  |  | // Copyright 2013 The Prometheus Authors
 | 
					
						
							| 
									
										
										
										
											2013-06-28 16:19:16 +08:00
										 |  |  | // Licensed 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.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-29 03:11:48 +08:00
										 |  |  | package httputil | 
					
						
							| 
									
										
										
										
											2013-06-28 16:19:16 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2023-06-20 19:39:32 +08:00
										 |  |  | 	"io" | 
					
						
							| 
									
										
										
										
											2013-06-28 16:19:16 +08:00
										 |  |  | 	"net/http" | 
					
						
							|  |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2022-05-31 17:46:49 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/klauspost/compress/gzip" | 
					
						
							|  |  |  | 	"github.com/klauspost/compress/zlib" | 
					
						
							| 
									
										
										
										
											2013-06-28 16:19:16 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const ( | 
					
						
							|  |  |  | 	acceptEncodingHeader  = "Accept-Encoding" | 
					
						
							|  |  |  | 	contentEncodingHeader = "Content-Encoding" | 
					
						
							|  |  |  | 	gzipEncoding          = "gzip" | 
					
						
							|  |  |  | 	deflateEncoding       = "deflate" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-20 19:39:32 +08:00
										 |  |  | // Wrapper around http.Handler which adds suitable response compression based
 | 
					
						
							|  |  |  | // on the client's Accept-Encoding headers.
 | 
					
						
							|  |  |  | type compressedResponseWriter struct { | 
					
						
							| 
									
										
										
										
											2013-06-28 16:19:16 +08:00
										 |  |  | 	http.ResponseWriter | 
					
						
							| 
									
										
										
										
											2023-06-20 19:39:32 +08:00
										 |  |  | 	writer io.Writer | 
					
						
							| 
									
										
										
										
											2013-06-28 16:19:16 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Writes HTTP response content data.
 | 
					
						
							| 
									
										
										
										
											2023-06-20 19:39:32 +08:00
										 |  |  | func (c *compressedResponseWriter) Write(p []byte) (int, error) { | 
					
						
							| 
									
										
										
										
											2013-06-28 16:19:16 +08:00
										 |  |  | 	return c.writer.Write(p) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-20 19:39:32 +08:00
										 |  |  | // Closes the compressedResponseWriter and ensures to flush all data before.
 | 
					
						
							|  |  |  | func (c *compressedResponseWriter) Close() { | 
					
						
							|  |  |  | 	if zlibWriter, ok := c.writer.(*zlib.Writer); ok { | 
					
						
							|  |  |  | 		zlibWriter.Flush() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if gzipWriter, ok := c.writer.(*gzip.Writer); ok { | 
					
						
							|  |  |  | 		gzipWriter.Flush() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if closer, ok := c.writer.(io.Closer); ok { | 
					
						
							|  |  |  | 		defer closer.Close() | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-06-28 16:19:16 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-20 19:39:32 +08:00
										 |  |  | // Constructs a new compressedResponseWriter based on client request headers.
 | 
					
						
							|  |  |  | func newCompressedResponseWriter(writer http.ResponseWriter, req *http.Request) *compressedResponseWriter { | 
					
						
							| 
									
										
										
										
											2025-02-11 21:14:55 +08:00
										 |  |  | 	raw := req.Header.Get(acceptEncodingHeader) | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		encoding   string | 
					
						
							|  |  |  | 		commaFound bool | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	for { | 
					
						
							|  |  |  | 		encoding, raw, commaFound = strings.Cut(raw, ",") | 
					
						
							| 
									
										
										
										
											2023-06-20 19:39:32 +08:00
										 |  |  | 		switch strings.TrimSpace(encoding) { | 
					
						
							|  |  |  | 		case gzipEncoding: | 
					
						
							|  |  |  | 			writer.Header().Set(contentEncodingHeader, gzipEncoding) | 
					
						
							|  |  |  | 			return &compressedResponseWriter{ | 
					
						
							|  |  |  | 				ResponseWriter: writer, | 
					
						
							|  |  |  | 				writer:         gzip.NewWriter(writer), | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		case deflateEncoding: | 
					
						
							|  |  |  | 			writer.Header().Set(contentEncodingHeader, deflateEncoding) | 
					
						
							|  |  |  | 			return &compressedResponseWriter{ | 
					
						
							|  |  |  | 				ResponseWriter: writer, | 
					
						
							|  |  |  | 				writer:         zlib.NewWriter(writer), | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2025-02-11 21:14:55 +08:00
										 |  |  | 		if !commaFound { | 
					
						
							|  |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-06-20 19:39:32 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return &compressedResponseWriter{ | 
					
						
							| 
									
										
										
										
											2013-06-28 16:19:16 +08:00
										 |  |  | 		ResponseWriter: writer, | 
					
						
							| 
									
										
										
										
											2023-06-20 19:39:32 +08:00
										 |  |  | 		writer:         writer, | 
					
						
							| 
									
										
										
										
											2013-06-28 16:19:16 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-10 23:16:49 +08:00
										 |  |  | // CompressionHandler is a wrapper around http.Handler which adds suitable
 | 
					
						
							|  |  |  | // response compression based on the client's Accept-Encoding headers.
 | 
					
						
							| 
									
										
										
										
											2013-10-23 02:31:52 +08:00
										 |  |  | type CompressionHandler struct { | 
					
						
							|  |  |  | 	Handler http.Handler | 
					
						
							| 
									
										
										
										
											2013-06-28 16:19:16 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-10 23:16:49 +08:00
										 |  |  | // ServeHTTP adds compression to the original http.Handler's ServeHTTP() method.
 | 
					
						
							| 
									
										
										
										
											2013-10-23 02:31:52 +08:00
										 |  |  | func (c CompressionHandler) ServeHTTP(writer http.ResponseWriter, req *http.Request) { | 
					
						
							| 
									
										
										
										
											2023-06-20 19:39:32 +08:00
										 |  |  | 	compWriter := newCompressedResponseWriter(writer, req) | 
					
						
							|  |  |  | 	c.Handler.ServeHTTP(compWriter, req) | 
					
						
							|  |  |  | 	compWriter.Close() | 
					
						
							| 
									
										
										
										
											2013-06-28 16:19:16 +08:00
										 |  |  | } |