@@ -93,6 +93,14 @@ type redirectError struct {
93
93
Code int
94
94
}
95
95
96
+ type bytesCloser struct {
97
+ * bytes.Reader
98
+ }
99
+
100
+ func (r * bytesCloser ) Close () error {
101
+ return nil
102
+ }
103
+
96
104
func (e redirectError ) Error () string { return fmt .Sprintf ("redirecting (%d): %s" , e .Code , e .Location ) }
97
105
98
106
// errNotFound represents an error locating the blob.
@@ -115,6 +123,7 @@ func (m *memHandler) Stat(_ context.Context, _ string, h v1.Hash) (int64, error)
115
123
}
116
124
return int64 (len (b )), nil
117
125
}
126
+
118
127
func (m * memHandler ) Get (_ context.Context , _ string , h v1.Hash ) (io.ReadCloser , error ) {
119
128
m .lock .Lock ()
120
129
defer m .lock .Unlock ()
@@ -123,8 +132,9 @@ func (m *memHandler) Get(_ context.Context, _ string, h v1.Hash) (io.ReadCloser,
123
132
if ! found {
124
133
return nil , errNotFound
125
134
}
126
- return io . NopCloser ( bytes .NewReader (b )) , nil
135
+ return & bytesCloser { bytes .NewReader (b )} , nil
127
136
}
137
+
128
138
func (m * memHandler ) Put (_ context.Context , _ string , h v1.Hash , rc io.ReadCloser ) error {
129
139
m .lock .Lock ()
130
140
defer m .lock .Unlock ()
@@ -137,6 +147,7 @@ func (m *memHandler) Put(_ context.Context, _ string, h v1.Hash, rc io.ReadClose
137
147
m .m [h .String ()] = all
138
148
return nil
139
149
}
150
+
140
151
func (m * memHandler ) Delete (_ context.Context , _ string , h v1.Hash ) error {
141
152
m .lock .Lock ()
142
153
defer m .lock .Unlock ()
@@ -177,6 +188,7 @@ func (b *blobs) handle(resp http.ResponseWriter, req *http.Request) *regError {
177
188
service := elem [len (elem )- 2 ]
178
189
digest := req .URL .Query ().Get ("digest" )
179
190
contentRange := req .Header .Get ("Content-Range" )
191
+ rangeHeader := req .Header .Get ("Range" )
180
192
181
193
repo := req .URL .Host + path .Join (elem [1 :len (elem )- 2 ]... )
182
194
@@ -265,8 +277,10 @@ func (b *blobs) handle(resp http.ResponseWriter, req *http.Request) *regError {
265
277
266
278
return regErrInternal (err )
267
279
}
280
+
268
281
defer rc .Close ()
269
282
r = rc
283
+
270
284
} else {
271
285
tmp , err := b .blobHandler .Get (req .Context (), repo , h )
272
286
if errors .Is (err , errNotFound ) {
@@ -287,9 +301,48 @@ func (b *blobs) handle(resp http.ResponseWriter, req *http.Request) *regError {
287
301
r = & buf
288
302
}
289
303
290
- resp .Header ().Set ("Content-Length" , fmt .Sprint (size ))
291
- resp .Header ().Set ("Docker-Content-Digest" , h .String ())
292
- resp .WriteHeader (http .StatusOK )
304
+ if rangeHeader != "" {
305
+ start , end := int64 (0 ), int64 (0 )
306
+ if _ , err := fmt .Sscanf (rangeHeader , "bytes=%d-%d" , & start , & end ); err != nil {
307
+ return & regError {
308
+ Status : http .StatusRequestedRangeNotSatisfiable ,
309
+ Code : "BLOB_UNKNOWN" ,
310
+ Message : "We don't understand your Range" ,
311
+ }
312
+ }
313
+
314
+ n := (end + 1 ) - start
315
+ if ra , ok := r .(io.ReaderAt ); ok {
316
+ if end + 1 > size {
317
+ return & regError {
318
+ Status : http .StatusRequestedRangeNotSatisfiable ,
319
+ Code : "BLOB_UNKNOWN" ,
320
+ Message : fmt .Sprintf ("range end %d > %d size" , end + 1 , size ),
321
+ }
322
+ }
323
+ r = io .NewSectionReader (ra , start , n )
324
+ } else {
325
+ if _ , err := io .CopyN (io .Discard , r , start ); err != nil {
326
+ return & regError {
327
+ Status : http .StatusRequestedRangeNotSatisfiable ,
328
+ Code : "BLOB_UNKNOWN" ,
329
+ Message : fmt .Sprintf ("Failed to discard %d bytes" , start ),
330
+ }
331
+ }
332
+
333
+ r = io .LimitReader (r , n )
334
+ }
335
+
336
+ resp .Header ().Set ("Content-Range" , fmt .Sprintf ("bytes %d-%d/%d" , start , end , size ))
337
+ resp .Header ().Set ("Content-Length" , fmt .Sprint (n ))
338
+ resp .Header ().Set ("Docker-Content-Digest" , h .String ())
339
+ resp .WriteHeader (http .StatusPartialContent )
340
+ } else {
341
+ resp .Header ().Set ("Content-Length" , fmt .Sprint (size ))
342
+ resp .Header ().Set ("Docker-Content-Digest" , h .String ())
343
+ resp .WriteHeader (http .StatusOK )
344
+ }
345
+
293
346
io .Copy (resp , r )
294
347
return nil
295
348
0 commit comments