From bfdd169b3c73e0423c6958a66bfc8a8336b3962b Mon Sep 17 00:00:00 2001 From: Benjamin Urban Date: Wed, 19 Jul 2017 16:12:28 +0200 Subject: [PATCH 1/6] Fix typo in in invalid date header tests --- test/fresh.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/fresh.js b/test/fresh.js index cd7f72d..f5e66ac 100644 --- a/test/fresh.js +++ b/test/fresh.js @@ -107,15 +107,15 @@ describe('fresh(reqHeaders, resHeaders)', function () { describe('with invalid If-Modified-Since date', function () { it('should be stale', function () { var reqHeaders = { 'if-modified-since': 'foo' } - var resHeaders = { 'modified-since': 'Sat, 01 Jan 2000 00:00:00 GMT' } + var resHeaders = { 'last-modified': 'Sat, 01 Jan 2000 00:00:00 GMT' } assert.ok(!fresh(reqHeaders, resHeaders)) }) }) - describe('with invalid Modified-Since date', function () { + describe('with invalid Last-Modified date', function () { it('should be stale', function () { var reqHeaders = { 'if-modified-since': 'Sat, 01 Jan 2000 00:00:00 GMT' } - var resHeaders = { 'modified-since': 'foo' } + var resHeaders = { 'last-modified': 'foo' } assert.ok(!fresh(reqHeaders, resHeaders)) }) }) From bbdc335d9958a90d3a528f5563f22ef61fc51c87 Mon Sep 17 00:00:00 2001 From: Benjamin Urban Date: Wed, 19 Jul 2017 16:13:05 +0200 Subject: [PATCH 2/6] Fix handling of invalid if-modified-since/last-modified dates --- index.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index bd9812e..2227388 100644 --- a/index.js +++ b/index.js @@ -69,8 +69,10 @@ function fresh (reqHeaders, resHeaders) { // if-modified-since if (modifiedSince) { - var lastModified = resHeaders['last-modified'] - var modifiedStale = !lastModified || Date.parse(lastModified) > Date.parse(modifiedSince) + var lastModifiedTimestamp = Date.parse(resHeaders['last-modified']) + var modifiedSinceTimestamp = Date.parse(modifiedSince) + var modifiedStale = isNaN(lastModifiedTimestamp) || isNaN(modifiedSinceTimestamp) || + lastModifiedTimestamp > modifiedSinceTimestamp if (modifiedStale) { return false From 3a685f866ca6146ca4276358cfa4adeaa7b95b78 Mon Sep 17 00:00:00 2001 From: Benjamin Urban Date: Fri, 21 Jul 2017 12:26:55 +0200 Subject: [PATCH 3/6] Change date check to be more robust against monkey patched Date.parse --- index.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 2227388..722134f 100644 --- a/index.js +++ b/index.js @@ -71,8 +71,19 @@ function fresh (reqHeaders, resHeaders) { if (modifiedSince) { var lastModifiedTimestamp = Date.parse(resHeaders['last-modified']) var modifiedSinceTimestamp = Date.parse(modifiedSince) - var modifiedStale = isNaN(lastModifiedTimestamp) || isNaN(modifiedSinceTimestamp) || - lastModifiedTimestamp > modifiedSinceTimestamp + + // If-Modified-Since request header has an invalid date value. Every falsy value except 0 is treated as invalid, + // because the default behavior of Date.parse to return NaN on invalid dates might have been monkey patched + if ((!modifiedSinceTimestamp && modifiedSinceTimestamp !== 0) || !isFinite(modifiedSinceTimestamp)) { + return false + } + + // Last-Modified response header has an invalid date value + if ((!lastModifiedTimestamp && lastModifiedTimestamp !== 0) || !isFinite(lastModifiedTimestamp)) { + return false + } + + var modifiedStale = lastModifiedTimestamp > modifiedSinceTimestamp if (modifiedStale) { return false From dbed31dffe9b64429ad9fb9a1a9ee6945d40a820 Mon Sep 17 00:00:00 2001 From: Benjamin Urban Date: Fri, 21 Jul 2017 12:27:08 +0200 Subject: [PATCH 4/6] Add tests for edge cases in date parsing --- test/fresh.js | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/test/fresh.js b/test/fresh.js index f5e66ac..0066656 100644 --- a/test/fresh.js +++ b/test/fresh.js @@ -119,6 +119,61 @@ describe('fresh(reqHeaders, resHeaders)', function () { assert.ok(!fresh(reqHeaders, resHeaders)) }) }) + + describe('with earliest possible If-Modified-Since date', function () { + it('should be stale', function () { + var reqHeaders = { 'if-modified-since': 'Thu, 01 Jan 1970 00:00:00 GMT' } + var resHeaders = { 'last-modified': 'Sat, 01 Jan 2000 00:00:00 GMT' } + assert.ok(!fresh(reqHeaders, resHeaders)) + }) + }) + + describe('with earliest possible Last-Modified date', function () { + it('should be fresh', function () { + var reqHeaders = { 'if-modified-since': 'Sat, 01 Jan 2000 00:00:00 GMT' } + var resHeaders = { 'last-modified': 'Thu, 01 Jan 1970 00:00:00 GMT' } + assert.ok(fresh(reqHeaders, resHeaders)) + }) + }) + + describe('with earliest possible Last-Modified and If-Modified-Since date', function () { + it('should be fresh', function () { + var reqHeaders = { 'if-modified-since': 'Thu, 01 Jan 1970 00:00:00 GMT' } + var resHeaders = { 'last-modified': 'Thu, 01 Jan 1970 00:00:00 GMT' } + assert.ok(fresh(reqHeaders, resHeaders)) + }) + }) + + describe('when Date.parse was monkey patched', function () { + var dateParse = Date.parse + + before(function () { + Date.parse = function (str) { + var date = dateParse(str) + return isNaN(date) ? false : date + } + }) + + after(function () { + Date.parse = dateParse + }) + + describe('with invalid If-Modified-Since date', function () { + it('should be stale', function () { + var reqHeaders = { 'if-modified-since': 'foo' } + var resHeaders = { 'last-modified': 'Sat, 01 Jan 2000 00:00:00 GMT' } + assert.ok(!fresh(reqHeaders, resHeaders)) + }) + }) + + describe('with invalid Last-Modified date', function () { + it('should be stale', function () { + var reqHeaders = { 'if-modified-since': 'Sat, 01 Jan 2000 00:00:00 GMT' } + var resHeaders = { 'last-modified': 'foo' } + assert.ok(!fresh(reqHeaders, resHeaders)) + }) + }) + }) }) describe('when requested with If-Modified-Since and If-None-Match', function () { From a40c886809768f5960939291f8a3dd63df472d7d Mon Sep 17 00:00:00 2001 From: Benjamin Urban Date: Mon, 24 Jul 2017 16:52:43 +0200 Subject: [PATCH 5/6] Update test names for unix timestamp 0 tests --- test/fresh.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/fresh.js b/test/fresh.js index 0066656..2debbfe 100644 --- a/test/fresh.js +++ b/test/fresh.js @@ -120,7 +120,7 @@ describe('fresh(reqHeaders, resHeaders)', function () { }) }) - describe('with earliest possible If-Modified-Since date', function () { + describe('with unix epoch (timestamp 0) in If-Modified-Since header', function () { it('should be stale', function () { var reqHeaders = { 'if-modified-since': 'Thu, 01 Jan 1970 00:00:00 GMT' } var resHeaders = { 'last-modified': 'Sat, 01 Jan 2000 00:00:00 GMT' } @@ -128,7 +128,7 @@ describe('fresh(reqHeaders, resHeaders)', function () { }) }) - describe('with earliest possible Last-Modified date', function () { + describe('with unix epoch (timestamp 0) in Last-Modified header', function () { it('should be fresh', function () { var reqHeaders = { 'if-modified-since': 'Sat, 01 Jan 2000 00:00:00 GMT' } var resHeaders = { 'last-modified': 'Thu, 01 Jan 1970 00:00:00 GMT' } @@ -136,7 +136,7 @@ describe('fresh(reqHeaders, resHeaders)', function () { }) }) - describe('with earliest possible Last-Modified and If-Modified-Since date', function () { + describe('with unix epoch (timestamp 0) in Last-Modified and If-Modified-Since header', function () { it('should be fresh', function () { var reqHeaders = { 'if-modified-since': 'Thu, 01 Jan 1970 00:00:00 GMT' } var resHeaders = { 'last-modified': 'Thu, 01 Jan 1970 00:00:00 GMT' } From 18a72a8f037bcaa4d3e1f234a642996454296ea7 Mon Sep 17 00:00:00 2001 From: Benjamin Urban Date: Mon, 24 Jul 2017 16:54:27 +0200 Subject: [PATCH 6/6] Change monkey patching test to better fit datejs behavior --- test/fresh.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/fresh.js b/test/fresh.js index 2debbfe..fe20e2f 100644 --- a/test/fresh.js +++ b/test/fresh.js @@ -150,7 +150,9 @@ describe('fresh(reqHeaders, resHeaders)', function () { before(function () { Date.parse = function (str) { var date = dateParse(str) - return isNaN(date) ? false : date + // https://www.npmjs.com/package/datejs unconditionally patches Date.parse and returns null instead of NaN + // for invalid dates + return isNaN(date) ? null : date } })