1
1
import { Hono } from '../../hono'
2
- import { etag } from '.'
2
+ import { etag , RETAINED_304_HEADERS } from '.'
3
3
4
4
describe ( 'Etag Middleware' , ( ) => {
5
- let app : Hono
6
-
7
- beforeEach ( ( ) => {
8
- app = new Hono ( )
5
+ it ( 'Should return etag header' , async ( ) => {
6
+ const app = new Hono ( )
9
7
app . use ( '/etag/*' , etag ( ) )
10
8
app . get ( '/etag/abc' , ( c ) => {
11
9
return c . text ( 'Hono is cool' )
12
10
} )
13
11
app . get ( '/etag/def' , ( c ) => {
14
12
return c . json ( { message : 'Hono is cool' } )
15
13
} )
16
- } )
17
-
18
- it ( 'Should return etag header' , async ( ) => {
19
14
let res = await app . request ( 'http://localhost/etag/abc' )
20
15
expect ( res . headers . get ( 'ETag' ) ) . not . toBeFalsy ( )
21
16
expect ( res . headers . get ( 'ETag' ) ) . toBe ( '"4e32298b1cb4edc595237405e5b696e105c2399a"' )
@@ -26,18 +21,21 @@ describe('Etag Middleware', () => {
26
21
} )
27
22
28
23
it ( 'Should return etag header - binary' , async ( ) => {
29
- app . use ( '/etag-binary/*' , etag ( ) )
30
- app . get ( '/etag-binary' , async ( c ) => {
24
+ const app = new Hono ( )
25
+ app . use ( '/etag/*' , etag ( ) )
26
+ app . get ( '/etag' , async ( c ) => {
31
27
return c . body ( new Uint8Array ( 1 ) )
32
28
} )
33
29
34
- const res = await app . request ( 'http://localhost/etag-binary ' )
30
+ const res = await app . request ( 'http://localhost/etag' )
35
31
expect ( res . headers . get ( 'ETag' ) ) . not . toBeFalsy ( )
36
32
const etagHeader = res . headers . get ( 'ETag' )
37
33
expect ( etagHeader ) . toBe ( '"5ba93c9db0cff93f52b521d7420e43f6eda2784f"' )
38
34
} )
39
35
40
36
it ( 'Should not be the same etag - arrayBuffer' , async ( ) => {
37
+ const app = new Hono ( )
38
+ app . use ( '/etag/*' , etag ( ) )
41
39
app . get ( '/etag/ab1' , ( c ) => {
42
40
return c . body ( new ArrayBuffer ( 1 ) )
43
41
} )
@@ -52,6 +50,8 @@ describe('Etag Middleware', () => {
52
50
} )
53
51
54
52
it ( 'Should not be the same etag - Uint8Array' , async ( ) => {
53
+ const app = new Hono ( )
54
+ app . use ( '/etag/*' , etag ( ) )
55
55
app . get ( '/etag/ui1' , ( c ) => {
56
56
return c . body ( new Uint8Array ( [ 1 , 2 , 3 ] ) )
57
57
} )
@@ -66,17 +66,20 @@ describe('Etag Middleware', () => {
66
66
} )
67
67
68
68
it ( 'Should return etag header - weak' , async ( ) => {
69
- app . use ( '/etag-weak/*' , etag ( { weak : true } ) )
70
- app . get ( '/etag-weak/abc' , ( c ) => {
69
+ const app = new Hono ( )
70
+ app . use ( '/etag/*' , etag ( { weak : true } ) )
71
+ app . get ( '/etag/abc' , ( c ) => {
71
72
return c . text ( 'Hono is cool' )
72
73
} )
73
74
74
- const res = await app . request ( 'http://localhost/etag-weak /abc' )
75
+ const res = await app . request ( 'http://localhost/etag/abc' )
75
76
expect ( res . headers . get ( 'ETag' ) ) . not . toBeFalsy ( )
76
77
expect ( res . headers . get ( 'ETag' ) ) . toBe ( 'W/"4e32298b1cb4edc595237405e5b696e105c2399a"' )
77
78
} )
78
79
79
80
it ( 'Should handle conditional GETs' , async ( ) => {
81
+ const app = new Hono ( )
82
+ app . use ( '/etag/*' , etag ( ) )
80
83
app . get ( '/etag/ghi' , ( c ) =>
81
84
c . text ( 'Hono is great' , 200 , {
82
85
'cache-control' : 'public, max-age=120' ,
@@ -91,7 +94,7 @@ describe('Etag Middleware', () => {
91
94
let res = await app . request ( 'http://localhost/etag/ghi' )
92
95
expect ( res . status ) . toBe ( 200 )
93
96
expect ( res . headers . get ( 'ETag' ) ) . not . toBeFalsy ( )
94
- const etag = res . headers . get ( 'ETag' ) || ''
97
+ const etagHeaderValue = res . headers . get ( 'ETag' ) || ''
95
98
96
99
// conditional GET with the wrong ETag:
97
100
res = await app . request ( 'http://localhost/etag/ghi' , {
@@ -104,11 +107,11 @@ describe('Etag Middleware', () => {
104
107
// conditional GET with matching ETag:
105
108
res = await app . request ( 'http://localhost/etag/ghi' , {
106
109
headers : {
107
- 'If-None-Match' : etag ,
110
+ 'If-None-Match' : etagHeaderValue ,
108
111
} ,
109
112
} )
110
113
expect ( res . status ) . toBe ( 304 )
111
- expect ( res . headers . get ( 'Etag' ) ) . toBe ( etag )
114
+ expect ( res . headers . get ( 'Etag' ) ) . toBe ( etagHeaderValue )
112
115
expect ( await res . text ( ) ) . toBe ( '' )
113
116
expect ( res . headers . get ( 'cache-control' ) ) . toBe ( 'public, max-age=120' )
114
117
expect ( res . headers . get ( 'date' ) ) . toBe ( 'Mon, Feb 27 2023 12:08:36 GMT' )
@@ -119,28 +122,61 @@ describe('Etag Middleware', () => {
119
122
// conditional GET with matching ETag among list:
120
123
res = await app . request ( 'http://localhost/etag/ghi' , {
121
124
headers : {
122
- 'If-None-Match' : `"mismatch 1", ${ etag } , "mismatch 2"` ,
125
+ 'If-None-Match' : `"mismatch 1", ${ etagHeaderValue } , "mismatch 2"` ,
123
126
} ,
124
127
} )
125
128
expect ( res . status ) . toBe ( 304 )
126
129
} )
127
130
128
131
it ( 'Should not return duplicate etag header values' , async ( ) => {
129
- app . use ( '/etag2/*' , etag ( ) )
130
- app . use ( '/etag2/*' , etag ( ) )
131
- app . get ( '/etag2/abc' , ( c ) => c . text ( 'Hono is cool' ) )
132
+ const app = new Hono ( )
133
+ app . use ( '/etag/*' , etag ( ) )
134
+ app . use ( '/etag/*' , etag ( ) )
135
+ app . get ( '/etag/abc' , ( c ) => c . text ( 'Hono is cool' ) )
132
136
133
- const res = await app . request ( 'http://localhost/etag2 /abc' )
137
+ const res = await app . request ( 'http://localhost/etag /abc' )
134
138
expect ( res . headers . get ( 'ETag' ) ) . not . toBeFalsy ( )
135
139
expect ( res . headers . get ( 'ETag' ) ) . toBe ( '"4e32298b1cb4edc595237405e5b696e105c2399a"' )
136
140
} )
137
141
138
142
it ( 'Should not override ETag headers from upstream' , async ( ) => {
143
+ const app = new Hono ( )
144
+ app . use ( '/etag/*' , etag ( ) )
139
145
app . get ( '/etag/predefined' , ( c ) =>
140
146
c . text ( 'This response has an ETag' , 200 , { ETag : '"f-0194-d"' } )
141
147
)
142
148
143
149
const res = await app . request ( 'http://localhost/etag/predefined' )
144
150
expect ( res . headers . get ( 'ETag' ) ) . toBe ( '"f-0194-d"' )
145
151
} )
152
+
153
+ it ( 'Should retain the default and the specified headers' , async ( ) => {
154
+ const cacheControl = 'public, max-age=120'
155
+ const message = 'Hello!'
156
+ const app = new Hono ( )
157
+ app . use (
158
+ '/etag/*' ,
159
+ etag ( {
160
+ retainedHeaders : [ 'x-message-retain' , ...RETAINED_304_HEADERS ] ,
161
+ } )
162
+ )
163
+ app . get ( '/etag' , ( c ) => {
164
+ return c . text ( 'Hono is cool' , 200 , {
165
+ 'cache-control' : cacheControl ,
166
+ 'x-message-retain' : message ,
167
+ 'x-message' : message ,
168
+ } )
169
+ } )
170
+ const res = await app . request ( '/etag' , {
171
+ headers : {
172
+ 'If-None-Match' : '"4e32298b1cb4edc595237405e5b696e105c2399a"' ,
173
+ } ,
174
+ } )
175
+ expect ( res . status ) . toBe ( 304 )
176
+ expect ( res . headers . get ( 'ETag' ) ) . not . toBeFalsy ( )
177
+ expect ( res . headers . get ( 'ETag' ) ) . toBe ( '"4e32298b1cb4edc595237405e5b696e105c2399a"' )
178
+ expect ( res . headers . get ( 'Cache-Control' ) ) . toBe ( cacheControl )
179
+ expect ( res . headers . get ( 'x-message-retain' ) ) . toBe ( message )
180
+ expect ( res . headers . get ( 'x-message' ) ) . toBeFalsy ( )
181
+ } )
146
182
} )
0 commit comments