Repository: valyala/fasthttp
Pull request #758 (2020-03-09 14:18:26)

Add support for `NoDefaultDate` option that excludes the sending of the `Date` header
same as https://github.com/valyala/fasthttp/pull/629  but with tests.

phuslu: For changes in https://github.com/valyala/fasthttp/pull/758/files#diff-34c6b408d72845d076d47126c29948d1R919-R928 , just make GoSec happy.
phuslu: Hi @erikdubbelboer, I amended the commit. please have a look.

Patch:
diff --git a/header.go b/header.go
index b7a12ee..81d2eba 100644
--- a/header.go
+++ b/header.go
@@ -25,6 +25,7 @@ type ResponseHeader struct {
 	noHTTP11             bool
 	connectionClose      bool
 	noDefaultContentType bool
+	noDefaultDate        bool
 
 	statusCode         int
 	contentLength      int
@@ -641,6 +642,7 @@ func (h *ResponseHeader) DisableNormalizing() {
 func (h *ResponseHeader) Reset() {
 	h.disableNormalizing = false
 	h.noDefaultContentType = false
+	h.noDefaultDate = false
 	h.resetSkipNormalize()
 }
 
@@ -694,6 +696,7 @@ func (h *ResponseHeader) CopyTo(dst *ResponseHeader) {
 	dst.noHTTP11 = h.noHTTP11
 	dst.connectionClose = h.connectionClose
 	dst.noDefaultContentType = h.noDefaultContentType
+	dst.noDefaultDate = h.noDefaultDate
 
 	dst.statusCode = h.statusCode
 	dst.contentLength = h.contentLength
@@ -1499,8 +1502,10 @@ func (h *ResponseHeader) AppendBytes(dst []byte) []byte {
 		dst = appendHeaderLine(dst, strServer, server)
 	}
 
-	serverDateOnce.Do(updateServerDate)
-	dst = appendHeaderLine(dst, strDate, serverDate.Load().([]byte))
+	if !h.noDefaultDate {
+		serverDateOnce.Do(updateServerDate)
+		dst = appendHeaderLine(dst, strDate, serverDate.Load().([]byte))
+	}
 
 	// Append Content-Type only for non-zero responses
 	// or if it is explicitly set.
@@ -1518,7 +1523,7 @@ func (h *ResponseHeader) AppendBytes(dst []byte) []byte {
 
 	for i, n := 0, len(h.h); i < n; i++ {
 		kv := &h.h[i]
-		if !bytes.Equal(kv.key, strDate) {
+		if h.noDefaultDate || !bytes.Equal(kv.key, strDate) {
 			dst = appendHeaderLine(dst, kv.key, kv.value)
 		}
 	}
diff --git a/server.go b/server.go
index 5e2c75f..6ea26fd 100644
--- a/server.go
+++ b/server.go
@@ -322,6 +322,13 @@ type Server struct {
 	// value is explicitly provided during a request.
 	NoDefaultServerHeader bool
 
+	// NoDefaultDate, when set to true, causes the default Date
+	// header to be excluded from the Response.
+	//
+	// The default Date header value is the current date value. When
+	// set to true, the Date will not be present.
+	NoDefaultDate bool
+
 	// NoDefaultContentType, when set to true, causes the default Content-Type
 	// header to be excluded from the Response.
 	//
@@ -907,7 +914,7 @@ func SaveMultipartFile(fh *multipart.FileHeader, path string) error {
 	if err != nil {
 		return err
 	}
-	defer ff.Close()
+	defer ff.Close() // #nosec G307
 	_, err = copyZeroAlloc(ff, f)
 	return err
 }
@@ -1938,6 +1945,7 @@ func (s *Server) serveConn(c net.Conn) (err error) {
 
 		ctx.Request.isTLS = isTLS
 		ctx.Response.Header.noDefaultContentType = s.NoDefaultContentType
+		ctx.Response.Header.noDefaultDate = s.NoDefaultDate
 
 		if err == nil {
 			if s.ReadTimeout > 0 {
@@ -2500,16 +2508,20 @@ func (s *Server) writeFastError(w io.Writer, statusCode int, msg string) {
 		server = fmt.Sprintf("Server: %s\r\n", s.getServerName())
 	}
 
-	serverDateOnce.Do(updateServerDate)
+	date := ""
+	if !s.NoDefaultDate {
+		serverDateOnce.Do(updateServerDate)
+		date = fmt.Sprintf("Date: %s\r\n", serverDate.Load())
+	}
 
 	fmt.Fprintf(w, "Connection: close\r\n"+
 		server+
-		"Date: %s\r\n"+
+		date+
 		"Content-Type: text/plain\r\n"+
 		"Content-Length: %d\r\n"+
 		"\r\n"+
 		"%s",
-		serverDate.Load(), len(msg), msg)
+		len(msg), msg)
 }
 
 func defaultErrorHandler(ctx *RequestCtx, err error) {


Test patch:
diff --git a/header_test.go b/header_test.go
index 7f84a63..b9b6f46 100644
--- a/header_test.go
+++ b/header_test.go
@@ -1250,6 +1250,20 @@ func TestResponseContentTypeNoDefaultNotEmpty(t *testing.T) {
 	}
 }
 
+func TestResponseDateNoDefaultNotEmpty(t *testing.T) {
+	t.Parallel()
+
+	var h ResponseHeader
+
+	h.noDefaultDate = true
+
+	headers := h.String()
+
+	if strings.Contains(headers, "\r\nDate: ") {
+		t.Fatalf("ResponseDateNoDefaultNotEmpty fail, response: \n%+v\noutcome: \n%q\n", h, headers) //nolint:govet
+	}
+}
+
 func TestRequestHeaderConnectionClose(t *testing.T) {
 	t.Parallel()
 
diff --git a/server_test.go b/server_test.go
index d8b265b..0386f53 100644
--- a/server_test.go
+++ b/server_test.go
@@ -271,6 +271,7 @@ func TestServerName(t *testing.T) {
 		},
 		NoDefaultServerHeader: true,
 		NoDefaultContentType:  true,
+		NoDefaultDate:         true,
 	}
 
 	resp = getReponse()
@@ -281,6 +282,10 @@ func TestServerName(t *testing.T) {
 	if bytes.Contains(resp, []byte("\r\nContent-Type: ")) {
 		t.Fatalf("Unexpected response %q expected no Content-Type header", resp)
 	}
+
+	if bytes.Contains(resp, []byte("\r\nDate: ")) {
+		t.Fatalf("Unexpected response %q expected no Date header", resp)
+	}
 }
 
 func TestRequestCtxString(t *testing.T) {