swarm/api: url scheme bzz-hash to get hashes of swarm content (#15238) (#15715)

* swarm/api: url scheme bzz-hash to get hashes of swarm content (#15238)

Update URI to support bzz-hash scheme and handle such HTTP requests by
responding with hash of the content as a text/plain response.

* swarm/api: return hash of the content for bzz-hash:// requests

* swarm/api: revert "return hash of the content for bzz-hash:// requests"

Return hashes of the content that would be returned by bzz-raw
request.

* swarm/api/http: handle error in TestBzzGetPath

* swarm/api: remove extra blank line in comment
This commit is contained in:
Janoš Guljaš 2017-12-21 13:47:10 +01:00 committed by Péter Szilágyi
parent 5258785c81
commit 542d51895f
4 changed files with 80 additions and 16 deletions

@ -290,9 +290,12 @@ func (s *Server) HandleDelete(w http.ResponseWriter, r *Request) {
fmt.Fprint(w, newKey) fmt.Fprint(w, newKey)
} }
// HandleGetRaw handles a GET request to bzz-raw://<key> and responds with // HandleGet handles a GET request to
// the raw content stored at the given storage key // - bzz-raw://<key> and responds with the raw content stored at the
func (s *Server) HandleGetRaw(w http.ResponseWriter, r *Request) { // given storage key
// - bzz-hash://<key> and responds with the hash of the content stored
// at the given storage key as a text/plain response
func (s *Server) HandleGet(w http.ResponseWriter, r *Request) {
key, err := s.api.Resolve(r.uri) key, err := s.api.Resolve(r.uri)
if err != nil { if err != nil {
s.Error(w, r, fmt.Errorf("error resolving %s: %s", r.uri.Addr, err)) s.Error(w, r, fmt.Errorf("error resolving %s: %s", r.uri.Addr, err))
@ -345,6 +348,8 @@ func (s *Server) HandleGetRaw(w http.ResponseWriter, r *Request) {
return return
} }
switch {
case r.uri.Raw():
// allow the request to overwrite the content type using a query // allow the request to overwrite the content type using a query
// parameter // parameter
contentType := "application/octet-stream" contentType := "application/octet-stream"
@ -354,6 +359,11 @@ func (s *Server) HandleGetRaw(w http.ResponseWriter, r *Request) {
w.Header().Set("Content-Type", contentType) w.Header().Set("Content-Type", contentType)
http.ServeContent(w, &r.Request, "", time.Now(), reader) http.ServeContent(w, &r.Request, "", time.Now(), reader)
case r.uri.Hash():
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK)
fmt.Fprint(w, key)
}
} }
// HandleGetFiles handles a GET request to bzz:/<manifest> with an Accept // HandleGetFiles handles a GET request to bzz:/<manifest> with an Accept
@ -619,8 +629,8 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
s.HandleDelete(w, req) s.HandleDelete(w, req)
case "GET": case "GET":
if uri.Raw() || uri.DeprecatedRaw() { if uri.Raw() || uri.Hash() || uri.DeprecatedRaw() {
s.HandleGetRaw(w, req) s.HandleGet(w, req)
return return
} }

@ -33,7 +33,7 @@ import (
"github.com/ethereum/go-ethereum/swarm/testutil" "github.com/ethereum/go-ethereum/swarm/testutil"
) )
func TestBzzrGetPath(t *testing.T) { func TestBzzGetPath(t *testing.T) {
var err error var err error
@ -104,6 +104,38 @@ func TestBzzrGetPath(t *testing.T) {
} }
} }
for k, v := range testrequests {
var resp *http.Response
var respbody []byte
url := srv.URL + "/bzz-hash:/"
if k[:] != "" {
url += common.ToHex(key[0])[2:] + "/" + k[1:]
}
resp, err = http.Get(url)
if err != nil {
t.Fatalf("Request failed: %v", err)
}
defer resp.Body.Close()
respbody, err = ioutil.ReadAll(resp.Body)
if err != nil {
t.Fatalf("Read request body: %v", err)
}
if string(respbody) != key[v].String() {
isexpectedfailrequest := false
for _, r := range expectedfailrequests {
if k[:] == r {
isexpectedfailrequest = true
}
}
if !isexpectedfailrequest {
t.Fatalf("Response body does not match, expected: %v, got %v", key[v], string(respbody))
}
}
}
for _, c := range []struct { for _, c := range []struct {
path string path string
json string json string
@ -197,6 +229,7 @@ func TestBzzrGetPath(t *testing.T) {
srv.URL + "/bzz-immutable:/nonhash", srv.URL + "/bzz-immutable:/nonhash",
srv.URL + "/bzz-raw:/nonhash", srv.URL + "/bzz-raw:/nonhash",
srv.URL + "/bzz-list:/nonhash", srv.URL + "/bzz-list:/nonhash",
srv.URL + "/bzz-hash:/nonhash",
} }
nonhashresponses := []string{ nonhashresponses := []string{
@ -204,6 +237,7 @@ func TestBzzrGetPath(t *testing.T) {
"error resolving nonhash: immutable address not a content hash: &#34;nonhash&#34;", "error resolving nonhash: immutable address not a content hash: &#34;nonhash&#34;",
"error resolving nonhash: no DNS to resolve name: &#34;nonhash&#34;", "error resolving nonhash: no DNS to resolve name: &#34;nonhash&#34;",
"error resolving nonhash: no DNS to resolve name: &#34;nonhash&#34;", "error resolving nonhash: no DNS to resolve name: &#34;nonhash&#34;",
"error resolving nonhash: no DNS to resolve name: &#34;nonhash&#34;",
} }
for i, url := range nonhashtests { for i, url := range nonhashtests {

@ -36,6 +36,8 @@ type URI struct {
// * bzzr - raw swarm content // * bzzr - raw swarm content
// * bzzi - immutable URI of an entry in a swarm manifest // * bzzi - immutable URI of an entry in a swarm manifest
// (address is not resolved) // (address is not resolved)
// * bzz-hash - hash of swarm content
//
Scheme string Scheme string
// Addr is either a hexadecimal storage key or it an address which // Addr is either a hexadecimal storage key or it an address which
@ -56,7 +58,7 @@ type URI struct {
// * <scheme>://<addr> // * <scheme>://<addr>
// * <scheme>://<addr>/<path> // * <scheme>://<addr>/<path>
// //
// with scheme one of bzz, bzz-raw, bzz-immutable or bzz-list // with scheme one of bzz, bzz-raw, bzz-immutable, bzz-list or bzz-hash
// or deprecated ones bzzr and bzzi // or deprecated ones bzzr and bzzi
func Parse(rawuri string) (*URI, error) { func Parse(rawuri string) (*URI, error) {
u, err := url.Parse(rawuri) u, err := url.Parse(rawuri)
@ -67,7 +69,7 @@ func Parse(rawuri string) (*URI, error) {
// check the scheme is valid // check the scheme is valid
switch uri.Scheme { switch uri.Scheme {
case "bzz", "bzz-raw", "bzz-immutable", "bzz-list", "bzzr", "bzzi": case "bzz", "bzz-raw", "bzz-immutable", "bzz-list", "bzz-hash", "bzzr", "bzzi":
default: default:
return nil, fmt.Errorf("unknown scheme %q", u.Scheme) return nil, fmt.Errorf("unknown scheme %q", u.Scheme)
} }
@ -110,6 +112,10 @@ func (u *URI) DeprecatedImmutable() bool {
return u.Scheme == "bzzi" return u.Scheme == "bzzi"
} }
func (u *URI) Hash() bool {
return u.Scheme == "bzz-hash"
}
func (u *URI) String() string { func (u *URI) String() string {
return u.Scheme + ":/" + u.Addr + "/" + u.Path return u.Scheme + ":/" + u.Addr + "/" + u.Path
} }

@ -29,6 +29,7 @@ func TestParseURI(t *testing.T) {
expectRaw bool expectRaw bool
expectImmutable bool expectImmutable bool
expectList bool expectList bool
expectHash bool
expectDeprecatedRaw bool expectDeprecatedRaw bool
expectDeprecatedImmutable bool expectDeprecatedImmutable bool
} }
@ -98,6 +99,16 @@ func TestParseURI(t *testing.T) {
uri: "bzz://abc123/path/to/entry", uri: "bzz://abc123/path/to/entry",
expectURI: &URI{Scheme: "bzz", Addr: "abc123", Path: "path/to/entry"}, expectURI: &URI{Scheme: "bzz", Addr: "abc123", Path: "path/to/entry"},
}, },
{
uri: "bzz-hash:",
expectURI: &URI{Scheme: "bzz-hash"},
expectHash: true,
},
{
uri: "bzz-hash:/",
expectURI: &URI{Scheme: "bzz-hash"},
expectHash: true,
},
{ {
uri: "bzz-list:", uri: "bzz-list:",
expectURI: &URI{Scheme: "bzz-list"}, expectURI: &URI{Scheme: "bzz-list"},
@ -152,6 +163,9 @@ func TestParseURI(t *testing.T) {
if actual.List() != x.expectList { if actual.List() != x.expectList {
t.Fatalf("expected %s list to be %t, got %t", x.uri, x.expectList, actual.List()) t.Fatalf("expected %s list to be %t, got %t", x.uri, x.expectList, actual.List())
} }
if actual.Hash() != x.expectHash {
t.Fatalf("expected %s hash to be %t, got %t", x.uri, x.expectHash, actual.Hash())
}
if actual.DeprecatedRaw() != x.expectDeprecatedRaw { if actual.DeprecatedRaw() != x.expectDeprecatedRaw {
t.Fatalf("expected %s deprecated raw to be %t, got %t", x.uri, x.expectDeprecatedRaw, actual.DeprecatedRaw()) t.Fatalf("expected %s deprecated raw to be %t, got %t", x.uri, x.expectDeprecatedRaw, actual.DeprecatedRaw())
} }