提交 b3c20aad 作者: Jeromy Johnson 提交者: GitHub

Merge pull request #3869 from Recmo/fix/gateway/3868-etag

gateway: use CID as an ETag strong validator
...@@ -164,26 +164,36 @@ func (i *gatewayHandler) getOrHeadHandler(ctx context.Context, w http.ResponseWr ...@@ -164,26 +164,36 @@ func (i *gatewayHandler) getOrHeadHandler(ctx context.Context, w http.ResponseWr
return return
} }
dr, err := i.api.Unixfs().Cat(ctx, parsedPath) // Resolve path to the final DAG node for the ETag
dir := false resolvedPath, err := i.api.ResolvePath(ctx, parsedPath)
switch err { switch err {
case nil: case nil:
// Cat() worked
defer dr.Close()
case coreiface.ErrIsDir:
dir = true
case coreiface.ErrOffline: case coreiface.ErrOffline:
if !i.node.OnlineMode() { if !i.node.OnlineMode() {
webError(w, "ipfs cat "+urlPath, err, http.StatusServiceUnavailable) webError(w, "ipfs resolve -r "+urlPath, err, http.StatusServiceUnavailable)
return return
} }
fallthrough fallthrough
default: default:
webError(w, "ipfs resolve -r "+urlPath, err, http.StatusNotFound)
return
}
dr, err := i.api.Unixfs().Cat(ctx, resolvedPath)
dir := false
switch err {
case nil:
// Cat() worked
defer dr.Close()
case coreiface.ErrIsDir:
dir = true
default:
webError(w, "ipfs cat "+urlPath, err, http.StatusNotFound) webError(w, "ipfs cat "+urlPath, err, http.StatusNotFound)
return return
} }
etag := gopath.Base(urlPath) // Check etag send back to us
etag := "\"" + resolvedPath.Cid().String() + "\""
if r.Header.Get("If-None-Match") == etag { if r.Header.Get("If-None-Match") == etag {
w.WriteHeader(http.StatusNotModified) w.WriteHeader(http.StatusNotModified)
return return
...@@ -191,6 +201,7 @@ func (i *gatewayHandler) getOrHeadHandler(ctx context.Context, w http.ResponseWr ...@@ -191,6 +201,7 @@ func (i *gatewayHandler) getOrHeadHandler(ctx context.Context, w http.ResponseWr
i.addUserHeaders(w) // ok, _now_ write user's headers. i.addUserHeaders(w) // ok, _now_ write user's headers.
w.Header().Set("X-IPFS-Path", urlPath) w.Header().Set("X-IPFS-Path", urlPath)
w.Header().Set("Etag", etag)
// set 'allowed' headers // set 'allowed' headers
w.Header().Set("Access-Control-Allow-Headers", "X-Stream-Output, X-Chunked-Output") w.Header().Set("Access-Control-Allow-Headers", "X-Stream-Output, X-Chunked-Output")
...@@ -202,8 +213,8 @@ func (i *gatewayHandler) getOrHeadHandler(ctx context.Context, w http.ResponseWr ...@@ -202,8 +213,8 @@ func (i *gatewayHandler) getOrHeadHandler(ctx context.Context, w http.ResponseWr
// and only if it's /ipfs! // and only if it's /ipfs!
// TODO: break this out when we split /ipfs /ipns routes. // TODO: break this out when we split /ipfs /ipns routes.
modtime := time.Now() modtime := time.Now()
if strings.HasPrefix(urlPath, ipfsPathPrefix) && !dir { if strings.HasPrefix(urlPath, ipfsPathPrefix) && !dir {
w.Header().Set("Etag", etag)
w.Header().Set("Cache-Control", "public, max-age=29030400, immutable") w.Header().Set("Cache-Control", "public, max-age=29030400, immutable")
// set modtime to a really long time ago, since files are immutable and should stay cached // set modtime to a really long time ago, since files are immutable and should stay cached
...@@ -216,7 +227,7 @@ func (i *gatewayHandler) getOrHeadHandler(ctx context.Context, w http.ResponseWr ...@@ -216,7 +227,7 @@ func (i *gatewayHandler) getOrHeadHandler(ctx context.Context, w http.ResponseWr
return return
} }
links, err := i.api.Unixfs().Ls(ctx, parsedPath) links, err := i.api.Unixfs().Ls(ctx, resolvedPath)
if err != nil { if err != nil {
internalWebError(w, err) internalWebError(w, err)
return return
......
...@@ -139,7 +139,7 @@ func TestGatewayGet(t *testing.T) { ...@@ -139,7 +139,7 @@ func TestGatewayGet(t *testing.T) {
{"localhost:5001", "/", http.StatusNotFound, "404 page not found\n"}, {"localhost:5001", "/", http.StatusNotFound, "404 page not found\n"},
{"localhost:5001", "/" + k, http.StatusNotFound, "404 page not found\n"}, {"localhost:5001", "/" + k, http.StatusNotFound, "404 page not found\n"},
{"localhost:5001", "/ipfs/" + k, http.StatusOK, "fnord"}, {"localhost:5001", "/ipfs/" + k, http.StatusOK, "fnord"},
{"localhost:5001", "/ipns/nxdomain.example.com", http.StatusNotFound, "ipfs cat /ipns/nxdomain.example.com: " + namesys.ErrResolveFailed.Error() + "\n"}, {"localhost:5001", "/ipns/nxdomain.example.com", http.StatusNotFound, "ipfs resolve -r /ipns/nxdomain.example.com: " + namesys.ErrResolveFailed.Error() + "\n"},
{"localhost:5001", "/ipns/example.com", http.StatusOK, "fnord"}, {"localhost:5001", "/ipns/example.com", http.StatusOK, "fnord"},
{"example.com", "/", http.StatusOK, "fnord"}, {"example.com", "/", http.StatusOK, "fnord"},
} { } {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论