1
1
import { FastifyReply , FastifyRequest } from 'fastify'
2
2
import { ObjectMetadata } from '../backend'
3
3
import { Readable } from 'stream'
4
+ import { getConfig } from '../../config'
4
5
5
6
export interface RenderOptions {
6
7
bucket : string
@@ -16,12 +17,16 @@ export interface AssetResponse {
16
17
transformations ?: string [ ]
17
18
}
18
19
20
+ const { requestEtagHeaders, responseSMaxAge } = getConfig ( )
21
+
19
22
/**
20
23
* Renderer
21
24
* a generic renderer that respond to a request with an asset content
22
25
* and all the important headers
23
26
*/
24
27
export abstract class Renderer {
28
+ protected sMaxAge = responseSMaxAge
29
+
25
30
abstract getAsset ( request : FastifyRequest , options : RenderOptions ) : Promise < AssetResponse >
26
31
27
32
/**
@@ -34,7 +39,7 @@ export abstract class Renderer {
34
39
try {
35
40
const data = await this . getAsset ( request , options )
36
41
37
- await this . setHeaders ( response , data , options )
42
+ this . setHeaders ( request , response , data , options )
38
43
39
44
return response . send ( data . body )
40
45
} catch ( err : any ) {
@@ -55,7 +60,12 @@ export abstract class Renderer {
55
60
}
56
61
}
57
62
58
- protected setHeaders ( response : FastifyReply < any > , data : AssetResponse , options : RenderOptions ) {
63
+ protected setHeaders (
64
+ request : FastifyRequest < any > ,
65
+ response : FastifyReply < any > ,
66
+ data : AssetResponse ,
67
+ options : RenderOptions
68
+ ) {
59
69
response
60
70
. status ( data . metadata . httpStatusCode ?? 200 )
61
71
. header ( 'Accept-Ranges' , 'bytes' )
@@ -67,7 +77,7 @@ export abstract class Renderer {
67
77
if ( options . expires ) {
68
78
response . header ( 'Expires' , options . expires )
69
79
} else {
70
- response . header ( 'Cache-Control' , data . metadata . cacheControl )
80
+ this . handleCacheControl ( request , response , data . metadata )
71
81
}
72
82
73
83
if ( data . metadata . contentRange ) {
@@ -95,6 +105,40 @@ export abstract class Renderer {
95
105
}
96
106
}
97
107
}
108
+
109
+ protected handleCacheControl (
110
+ request : FastifyRequest < any > ,
111
+ response : FastifyReply < any > ,
112
+ metadata : ObjectMetadata
113
+ ) {
114
+ const etag = this . findEtagHeader ( request )
115
+
116
+ const cacheControl = [ metadata . cacheControl ]
117
+
118
+ if ( ! etag ) {
119
+ response . header ( 'Cache-Control' , cacheControl . join ( ', ' ) )
120
+ return
121
+ }
122
+
123
+ if ( this . sMaxAge > 0 ) {
124
+ cacheControl . push ( `s-maxage=${ this . sMaxAge } ` )
125
+ }
126
+
127
+ if ( etag !== metadata . eTag ) {
128
+ cacheControl . push ( 'stale-while-revalidate=30' )
129
+ }
130
+
131
+ response . header ( 'Cache-Control' , cacheControl . join ( ', ' ) )
132
+ }
133
+
134
+ protected findEtagHeader ( request : FastifyRequest < any > ) {
135
+ for ( const header of requestEtagHeaders ) {
136
+ const etag = request . headers [ header ]
137
+ if ( etag ) {
138
+ return etag
139
+ }
140
+ }
141
+ }
98
142
}
99
143
100
144
function normalizeContentType ( contentType : string | undefined ) : string | undefined {
0 commit comments