From d227bec0fffd3e8f89d0e20209b8ffe00c9f8242 Mon Sep 17 00:00:00 2001 From: Matthew Holt Date: Thu, 29 Oct 2015 10:34:47 -0600 Subject: [PATCH] Move common function into existing file --- middleware/header.go | 33 ----------------- middleware/header_test.go | 70 ----------------------------------- middleware/middleware.go | 28 ++++++++++++++ middleware/middleware_test.go | 64 ++++++++++++++++++++++++++++++++ 4 files changed, 92 insertions(+), 103 deletions(-) delete mode 100644 middleware/header.go delete mode 100644 middleware/header_test.go diff --git a/middleware/header.go b/middleware/header.go deleted file mode 100644 index 56749b554..000000000 --- a/middleware/header.go +++ /dev/null @@ -1,33 +0,0 @@ -package middleware - -import ( - "net/http" - "time" -) - -// currentTime returns time.Now() everytime it's called. It's used for mocking in tests. -var currentTime = func() time.Time { - return time.Now() -} - -// SetLastModifiedHeader checks if the provided modTime is valid and if it is sets it -// as a Last-Modified header to the ResponseWriter. If the modTime is in the future -// the current time is used instead. -func SetLastModifiedHeader(w http.ResponseWriter, modTime time.Time) { - if modTime.IsZero() || modTime.Equal(time.Unix(0, 0)) { - // the time does not appear to be valid. Don't put it in the response - return - } - - // RFC 2616 - Section 14.29 - Last-Modified: - // An origin server MUST NOT send a Last-Modified date which is later than the - // server's time of message origination. In such cases, where the resource's last - // modification would indicate some time in the future, the server MUST replace - // that date with the message origination date. - now := currentTime() - if modTime.After(now) { - modTime = now - } - - w.Header().Set("Last-Modified", modTime.UTC().Format(http.TimeFormat)) -} diff --git a/middleware/header_test.go b/middleware/header_test.go deleted file mode 100644 index c76d8e631..000000000 --- a/middleware/header_test.go +++ /dev/null @@ -1,70 +0,0 @@ -package middleware - -import ( - "fmt" - "net/http" - "net/http/httptest" - "testing" - "time" -) - -func TestSetLastModified(t *testing.T) { - nowTime := time.Now() - - // ovewrite the function to return reliable time - originalGetCurrentTimeFunc := currentTime - currentTime = func() time.Time { - return nowTime - } - defer func() { - currentTime = originalGetCurrentTimeFunc - }() - - pastTime := nowTime.Truncate(1 * time.Hour) - futureTime := nowTime.Add(1 * time.Hour) - - tests := []struct { - inputModTime time.Time - expectedIsHeaderSet bool - expectedLastModified string - }{ - { - inputModTime: pastTime, - expectedIsHeaderSet: true, - expectedLastModified: pastTime.UTC().Format(http.TimeFormat), - }, - { - inputModTime: nowTime, - expectedIsHeaderSet: true, - expectedLastModified: nowTime.UTC().Format(http.TimeFormat), - }, - { - inputModTime: futureTime, - expectedIsHeaderSet: true, - expectedLastModified: nowTime.UTC().Format(http.TimeFormat), - }, - { - inputModTime: time.Time{}, - expectedIsHeaderSet: false, - }, - } - - for i, test := range tests { - responseRecorder := httptest.NewRecorder() - errorPrefix := fmt.Sprintf("Test [%d]: ", i) - SetLastModifiedHeader(responseRecorder, test.inputModTime) - actualLastModifiedHeader := responseRecorder.Header().Get("Last-Modified") - - if test.expectedIsHeaderSet && actualLastModifiedHeader == "" { - t.Fatalf(errorPrefix + "Expected to find Last-Modified header, but found nothing") - } - - if !test.expectedIsHeaderSet && actualLastModifiedHeader != "" { - t.Fatalf(errorPrefix+"Did not expect to find Last-Modified header, but found one [%s].", actualLastModifiedHeader) - } - - if test.expectedLastModified != actualLastModifiedHeader { - t.Errorf(errorPrefix+"Expected Last-Modified content [%s], found [%s}", test.expectedLastModified, actualLastModifiedHeader) - } - } -} diff --git a/middleware/middleware.go b/middleware/middleware.go index ba7699ce4..b88b24474 100644 --- a/middleware/middleware.go +++ b/middleware/middleware.go @@ -4,6 +4,7 @@ package middleware import ( "net/http" "path" + "time" ) type ( @@ -78,3 +79,30 @@ func IndexFile(root http.FileSystem, fpath string, indexFiles []string) (string, } return "", false } + +// SetLastModifiedHeader checks if the provided modTime is valid and if it is sets it +// as a Last-Modified header to the ResponseWriter. If the modTime is in the future +// the current time is used instead. +func SetLastModifiedHeader(w http.ResponseWriter, modTime time.Time) { + if modTime.IsZero() || modTime.Equal(time.Unix(0, 0)) { + // the time does not appear to be valid. Don't put it in the response + return + } + + // RFC 2616 - Section 14.29 - Last-Modified: + // An origin server MUST NOT send a Last-Modified date which is later than the + // server's time of message origination. In such cases, where the resource's last + // modification would indicate some time in the future, the server MUST replace + // that date with the message origination date. + now := currentTime() + if modTime.After(now) { + modTime = now + } + + w.Header().Set("Last-Modified", modTime.UTC().Format(http.TimeFormat)) +} + +// currentTime returns time.Now() everytime it's called. It's used for mocking in tests. +var currentTime = func() time.Time { + return time.Now() +} diff --git a/middleware/middleware_test.go b/middleware/middleware_test.go index 700beed84..62fa4e250 100644 --- a/middleware/middleware_test.go +++ b/middleware/middleware_test.go @@ -1,8 +1,11 @@ package middleware import ( + "fmt" "net/http" + "net/http/httptest" "testing" + "time" ) func TestIndexfile(t *testing.T) { @@ -42,3 +45,64 @@ func TestIndexfile(t *testing.T) { } } } + +func TestSetLastModified(t *testing.T) { + nowTime := time.Now() + + // ovewrite the function to return reliable time + originalGetCurrentTimeFunc := currentTime + currentTime = func() time.Time { + return nowTime + } + defer func() { + currentTime = originalGetCurrentTimeFunc + }() + + pastTime := nowTime.Truncate(1 * time.Hour) + futureTime := nowTime.Add(1 * time.Hour) + + tests := []struct { + inputModTime time.Time + expectedIsHeaderSet bool + expectedLastModified string + }{ + { + inputModTime: pastTime, + expectedIsHeaderSet: true, + expectedLastModified: pastTime.UTC().Format(http.TimeFormat), + }, + { + inputModTime: nowTime, + expectedIsHeaderSet: true, + expectedLastModified: nowTime.UTC().Format(http.TimeFormat), + }, + { + inputModTime: futureTime, + expectedIsHeaderSet: true, + expectedLastModified: nowTime.UTC().Format(http.TimeFormat), + }, + { + inputModTime: time.Time{}, + expectedIsHeaderSet: false, + }, + } + + for i, test := range tests { + responseRecorder := httptest.NewRecorder() + errorPrefix := fmt.Sprintf("Test [%d]: ", i) + SetLastModifiedHeader(responseRecorder, test.inputModTime) + actualLastModifiedHeader := responseRecorder.Header().Get("Last-Modified") + + if test.expectedIsHeaderSet && actualLastModifiedHeader == "" { + t.Fatalf(errorPrefix + "Expected to find Last-Modified header, but found nothing") + } + + if !test.expectedIsHeaderSet && actualLastModifiedHeader != "" { + t.Fatalf(errorPrefix+"Did not expect to find Last-Modified header, but found one [%s].", actualLastModifiedHeader) + } + + if test.expectedLastModified != actualLastModifiedHeader { + t.Errorf(errorPrefix+"Expected Last-Modified content [%s], found [%s}", test.expectedLastModified, actualLastModifiedHeader) + } + } +}