teach Download() how to follow hypermedia
This commit is contained in:
parent
7728ac274c
commit
2dd5983841
@ -14,15 +14,20 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
// Legacy type
|
||||
gitMediaType = "application/vnd.git-media"
|
||||
|
||||
// The main type, sub type, and suffix. Use this when ensuring the type from
|
||||
// an HTTP response is correct.
|
||||
gitMediaMetaTypePrefix = gitMediaType + "+json"
|
||||
|
||||
// Adds the extra mime params. Use this when sending the type in an HTTP
|
||||
// request.
|
||||
gitMediaMetaType = gitMediaType + "+json; charset=utf-8"
|
||||
gitMediaMetaType = gitMediaMetaTypePrefix + "; charset=utf-8"
|
||||
)
|
||||
|
||||
func Download(oidPath string) (io.ReadCloser, int64, *WrappedError) {
|
||||
@ -46,6 +51,47 @@ func Download(oidPath string) (io.ReadCloser, int64, *WrappedError) {
|
||||
return nil, 0, wErr
|
||||
}
|
||||
|
||||
if strings.HasPrefix(contentType, gitMediaMetaTypePrefix) {
|
||||
obj := &objectResource{}
|
||||
err := json.NewDecoder(res.Body).Decode(obj)
|
||||
res.Body.Close()
|
||||
if err != nil {
|
||||
wErr := Error(err)
|
||||
setErrorResponseContext(wErr, res)
|
||||
return nil, 0, wErr
|
||||
}
|
||||
|
||||
dlReq, err := obj.NewRequest("download", "GET")
|
||||
if err != nil {
|
||||
wErr := Error(err)
|
||||
setErrorResponseContext(wErr, res)
|
||||
return nil, 0, wErr
|
||||
}
|
||||
|
||||
dlCreds, err := setRequestHeaders(dlReq)
|
||||
if err != nil {
|
||||
return nil, 0, Errorf(err, "Error attempting to GET %s", oidPath)
|
||||
}
|
||||
|
||||
dlRes, err := DoHTTP(Config, dlReq)
|
||||
if err != nil {
|
||||
wErr := Error(err)
|
||||
setErrorResponseContext(wErr, res)
|
||||
return nil, 0, wErr
|
||||
}
|
||||
|
||||
saveCredentials(dlCreds, dlRes)
|
||||
|
||||
contentType := dlRes.Header.Get("Content-Type")
|
||||
if contentType == "" {
|
||||
wErr = Error(errors.New("Empty Content-Type"))
|
||||
setErrorResponseContext(wErr, res)
|
||||
return nil, 0, wErr
|
||||
}
|
||||
|
||||
res = dlRes
|
||||
}
|
||||
|
||||
ok, headerSize, wErr := validateMediaHeader(contentType, res.Body)
|
||||
if !ok {
|
||||
setErrorResponseContext(wErr, res)
|
||||
|
@ -1,6 +1,7 @@
|
||||
package hawser
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
@ -49,6 +50,77 @@ func TestDownload(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDownloadFromMeta(t *testing.T) {
|
||||
mux := http.NewServeMux()
|
||||
server := httptest.NewServer(mux)
|
||||
tmp := tempdir(t)
|
||||
defer server.Close()
|
||||
defer os.RemoveAll(tmp)
|
||||
|
||||
// simulates an endpoint that returns the meta data for every request.
|
||||
// this way downloads keep working with the older prototype server during
|
||||
// the pre-release.
|
||||
mux.HandleFunc("/media/objects/oid", func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "GET" {
|
||||
w.WriteHeader(405)
|
||||
return
|
||||
}
|
||||
|
||||
obj := &objectResource{
|
||||
Oid: "oid",
|
||||
Size: 4,
|
||||
Links: map[string]*linkRelation{
|
||||
"download": &linkRelation{
|
||||
Href: server.URL + "/media/download/oid",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
by, err := json.Marshal(obj)
|
||||
if err != nil {
|
||||
t.Errorf("Error marshaling json: %s", err)
|
||||
}
|
||||
|
||||
head := w.Header()
|
||||
head.Set("Content-Type", "application/vnd.git-media+json")
|
||||
w.WriteHeader(200)
|
||||
w.Write(by)
|
||||
})
|
||||
|
||||
mux.HandleFunc("/media/download/oid", func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "GET" {
|
||||
w.WriteHeader(405)
|
||||
return
|
||||
}
|
||||
|
||||
head := w.Header()
|
||||
head.Set("Content-Type", "application/octet-stream")
|
||||
head.Set("Content-Length", "4")
|
||||
w.WriteHeader(200)
|
||||
w.Write([]byte("test"))
|
||||
})
|
||||
|
||||
Config.SetConfig("hawser.url", server.URL+"/media")
|
||||
reader, size, wErr := Download("whatever/oid")
|
||||
if wErr != nil {
|
||||
t.Fatalf("unexpected error: %s", wErr)
|
||||
}
|
||||
defer reader.Close()
|
||||
|
||||
if size != 4 {
|
||||
t.Errorf("unexpected size: %d", size)
|
||||
}
|
||||
|
||||
by, err := ioutil.ReadAll(reader)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
|
||||
if body := string(by); body != "test" {
|
||||
t.Errorf("unexpected body: %s", body)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDownloadWithRedirect(t *testing.T) {
|
||||
mux := http.NewServeMux()
|
||||
server := httptest.NewServer(mux)
|
||||
|
Loading…
Reference in New Issue
Block a user