Implement Repository ServeBlob

Signed-off-by: Damien Mathieu <dmathieu@salesforce.com>
This commit is contained in:
Damien Mathieu 2019-05-10 12:07:50 +02:00
parent 79f6bcbe16
commit 3800c47fd2
2 changed files with 71 additions and 1 deletions

View file

@ -667,7 +667,24 @@ func (bs *blobs) Open(ctx context.Context, dgst digest.Digest) (distribution.Rea
}
func (bs *blobs) ServeBlob(ctx context.Context, w http.ResponseWriter, r *http.Request, dgst digest.Digest) error {
panic("not implemented")
desc, err := bs.statter.Stat(ctx, dgst)
if err != nil {
return err
}
blob, err := bs.Open(ctx, dgst)
if err != nil {
return err
}
defer blob.Close()
w.Header().Set("Content-Length", strconv.FormatInt(desc.Size, 10))
w.Header().Set("Content-Type", desc.MediaType)
w.Header().Set("Docker-Content-Digest", dgst.String())
w.Header().Set("Etag", dgst.String())
_, err = io.CopyN(w, blob, desc.Size)
return err
}
func (bs *blobs) Put(ctx context.Context, mediaType string, p []byte) (distribution.Descriptor, error) {

View file

@ -6,6 +6,7 @@ import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"net/http/httptest"
@ -57,6 +58,7 @@ func addTestFetch(repo string, dgst digest.Digest, content []byte, m *testutil.R
Body: content,
Headers: http.Header(map[string][]string{
"Content-Length": {fmt.Sprint(len(content))},
"Content-Type": {"application/octet-stream"},
"Last-Modified": {time.Now().Add(-1 * time.Second).Format(time.ANSIC)},
}),
},
@ -71,6 +73,7 @@ func addTestFetch(repo string, dgst digest.Digest, content []byte, m *testutil.R
StatusCode: http.StatusOK,
Headers: http.Header(map[string][]string{
"Content-Length": {fmt.Sprint(len(content))},
"Content-Type": {"application/octet-stream"},
"Last-Modified": {time.Now().Add(-1 * time.Second).Format(time.ANSIC)},
}),
},
@ -99,6 +102,56 @@ func addTestCatalog(route string, content []byte, link string, m *testutil.Reque
})
}
func TestBlobServeBlob(t *testing.T) {
dgst, blob := newRandomBlob(1024)
var m testutil.RequestResponseMap
addTestFetch("test.example.com/repo1", dgst, blob, &m)
e, c := testServer(m)
defer c()
ctx := context.Background()
repo, _ := reference.WithName("test.example.com/repo1")
r, err := NewRepository(repo, e, nil)
if err != nil {
t.Fatal(err)
}
l := r.Blobs(ctx)
resp := httptest.NewRecorder()
req := httptest.NewRequest("GET", "/", nil)
err = l.ServeBlob(ctx, resp, req, dgst)
if err != nil {
t.Errorf("Error serving blob: %s", err.Error())
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
t.Errorf("Error reading response body: %s", err.Error())
}
if string(body) != string(blob) {
t.Errorf("Unexpected response body. Got %q, expected %q", string(body), string(blob))
}
expectedHeaders := []struct {
Name string
Value string
}{
{Name: "Content-Length", Value: "1024"},
{Name: "Content-Type", Value: "application/octet-stream"},
{Name: "Docker-Content-Digest", Value: dgst.String()},
{Name: "Etag", Value: dgst.String()},
}
for _, h := range expectedHeaders {
if resp.Header().Get(h.Name) != h.Value {
t.Errorf("Unexpected %s. Got %s, expected %s", h.Name, resp.Header().Get(h.Name), h.Value)
}
}
}
func TestBlobDelete(t *testing.T) {
dgst, _ := newRandomBlob(1024)
var m testutil.RequestResponseMap