@@ -2,6 +2,7 @@ package http
2
2
3
3
import (
4
4
"bytes"
5
+ "cmp"
5
6
"context"
6
7
"crypto/sha256"
7
8
"encoding/json"
@@ -13,6 +14,7 @@ import (
13
14
"os"
14
15
"path"
15
16
"path/filepath"
17
+ "slices"
16
18
"strconv"
17
19
"strings"
18
20
"time"
@@ -33,6 +35,13 @@ import (
33
35
"github.com/pkg/errors"
34
36
)
35
37
38
+ // supportedUserHeaders defines supported user-defined header fields. Fields
39
+ // not included here will be silently dropped.
40
+ var supportedUserDefinedHeaders = map [string ]bool {
41
+ http .CanonicalHeaderKey ("accept" ): true ,
42
+ http .CanonicalHeaderKey ("user-agent" ): true ,
43
+ }
44
+
36
45
type Opt struct {
37
46
CacheAccessor cache.Accessor
38
47
Transport http.RoundTripper
@@ -95,9 +104,22 @@ func (hs *httpSource) Identifier(scheme, ref string, attrs map[string]string, pl
95
104
id .GID = int (i )
96
105
case pb .AttrHTTPAuthHeaderSecret :
97
106
id .AuthHeaderSecret = v
107
+ default :
108
+ if name , found := strings .CutPrefix (k , pb .AttrHTTPHeaderPrefix ); found {
109
+ name = http .CanonicalHeaderKey (name )
110
+ if supportedUserDefinedHeaders [name ] {
111
+ id .Header = append (id .Header , HeaderField {Name : name , Value : v })
112
+ }
113
+ }
98
114
}
99
115
}
100
116
117
+ // Sort header fields to ensure consistent hashing (see urlHash() and
118
+ // formatCacheKey())
119
+ slices .SortFunc (id .Header , func (a , b HeaderField ) int {
120
+ return cmp .Compare (a .Name , b .Name )
121
+ })
122
+
101
123
return id , nil
102
124
}
103
125
@@ -133,6 +155,7 @@ func (hs *httpSourceHandler) urlHash() (digest.Digest, error) {
133
155
Filename []byte
134
156
Perm , UID , GID int
135
157
AuthHeaderSecret string `json:",omitempty"`
158
+ Header []HeaderField
136
159
}{
137
160
Filename : bytes .Join ([][]byte {
138
161
[]byte (hs .src .URL ),
@@ -142,6 +165,7 @@ func (hs *httpSourceHandler) urlHash() (digest.Digest, error) {
142
165
UID : hs .src .UID ,
143
166
GID : hs .src .GID ,
144
167
AuthHeaderSecret : hs .src .AuthHeaderSecret ,
168
+ Header : hs .src .Header ,
145
169
})
146
170
if err != nil {
147
171
return "" , err
@@ -154,8 +178,9 @@ func (hs *httpSourceHandler) formatCacheKey(filename string, dgst digest.Digest,
154
178
Filename string
155
179
Perm , UID , GID int
156
180
Checksum digest.Digest
157
- LastModTime string `json:",omitempty"`
158
- AuthHeaderSecret string `json:",omitempty"`
181
+ LastModTime string `json:",omitempty"`
182
+ AuthHeaderSecret string `json:",omitempty"`
183
+ Header []HeaderField `json:",omitempty"`
159
184
}{
160
185
Filename : filename ,
161
186
Perm : hs .src .Perm ,
@@ -164,6 +189,7 @@ func (hs *httpSourceHandler) formatCacheKey(filename string, dgst digest.Digest,
164
189
Checksum : dgst ,
165
190
LastModTime : lastModTime ,
166
191
AuthHeaderSecret : hs .src .AuthHeaderSecret ,
192
+ Header : hs .src .Header ,
167
193
})
168
194
if err != nil {
169
195
return dgst
@@ -219,7 +245,7 @@ func (hs *httpSourceHandler) CacheKey(ctx context.Context, g session.Group, inde
219
245
for t := range m {
220
246
etags = append (etags , t )
221
247
}
222
- req .Header .Add ("If-None-Match" , strings .Join (etags , ", " ))
248
+ req .Header .Set ("If-None-Match" , strings .Join (etags , ", " ))
223
249
224
250
if len (etags ) == 1 {
225
251
onlyETag = etags [0 ]
@@ -236,7 +262,7 @@ func (hs *httpSourceHandler) CacheKey(ctx context.Context, g session.Group, inde
236
262
req .Method = "HEAD"
237
263
// we need to add accept-encoding header manually because stdlib only adds it to GET requests
238
264
// some servers will return different etags if Accept-Encoding header is different
239
- req .Header .Add ("Accept-Encoding" , "gzip" )
265
+ req .Header .Set ("Accept-Encoding" , "gzip" )
240
266
resp , err := client .Do (req )
241
267
if err == nil {
242
268
if resp .StatusCode == http .StatusOK || resp .StatusCode == http .StatusNotModified {
@@ -482,6 +508,9 @@ func (hs *httpSourceHandler) newHTTPRequest(ctx context.Context, g session.Group
482
508
}
483
509
484
510
req .Header .Set ("User-Agent" , version .UserAgent ())
511
+ for _ , field := range hs .src .Header {
512
+ req .Header .Set (field .Name , field .Value )
513
+ }
485
514
486
515
if hs .src .AuthHeaderSecret != "" {
487
516
err := hs .sm .Any (ctx , g , func (ctx context.Context , _ string , caller session.Caller ) error {
0 commit comments