-
Notifications
You must be signed in to change notification settings - Fork 95
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Gateway: Cache-Control, max-age=ttl, ETag for /ipns requests #329
Comments
It could be determined by the IPNS record -- some will have a calculable |
Until then, we could set |
I’m not sure if I have understood this correctly, but I’m under the impression that |
You're right, thanks -- so that means |
Note that for |
It seems to me that |
DNS lets you say explicitly for how long a record can be cached. Perhaps we should do that with IPNS names? |
It was mentioned on IRC that
Given that the DNS lookup functions in the net package for Go do not seem to provide TTL information at the moment, the DNS If |
Would this be a reasonable starting point? diff --git a/namesys/interface.go b/namesys/interface.go
index 09c296c..b0b740d 100644
--- a/namesys/interface.go
+++ b/namesys/interface.go
@@ -47,6 +47,14 @@ const (
// trust resolution to eventually complete and can't put an upper
// limit on how many steps it will take.
UnlimitedDepth = 0
+
+ // ImmutableTTL is the time-to-live value to be reported for immutable
+ // objects.
+ ImmutableTTL = 10 * 365 * 24 * time.Hour
+
+ // UnknownTTL is the time-to-live value to be reported for mutable
+ // paths when accurate information is not available.
+ UnknownTTL = time.Minute
)
// ErrResolveFailed signals an error when attempting to resolve.
@@ -88,7 +96,10 @@ type Resolver interface {
// There is a default depth-limit to avoid infinite recursion. Most
// users will be fine with this default limit, but if you need to
// adjust the limit you can use ResolveN.
- Resolve(ctx context.Context, name string) (value path.Path, err error)
+ //
+ // Resolve also returns a time-to-live value which indicates the
+ // maximum amount of time the result may be cached.
+ Resolve(ctx context.Context, name string) (value path.Path, ttl time.Duration, err error)
// ResolveN performs a recursive lookup, returning the dereferenced
// path. The only difference from Resolve is that the depth limit
@@ -97,7 +108,7 @@ type Resolver interface {
//
// Most users should use Resolve, since the default limit works well
// in most real-world situations.
- ResolveN(ctx context.Context, name string, depth int) (value path.Path, err error)
+ ResolveN(ctx context.Context, name string, depth int) (value path.Path, ttl time.Duration, err error)
}
// Publisher is an object capable of publishing particular names. diff --git a/namesys/base.go b/namesys/base.go
index e552fce..29ef997 100644
--- a/namesys/base.go
+++ b/namesys/base.go
@@ -2,6 +2,7 @@ package namesys
import (
"strings"
+ "time"
context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
@@ -9,27 +10,36 @@ import (
)
type resolver interface {
- // resolveOnce looks up a name once (without recursion).
- resolveOnce(ctx context.Context, name string) (value path.Path, err error)
+ // resolveOnce looks up a name once (without recursion). It also
+ // returns a time-to-live value which indicates the maximum amount of
+ // time the result may be cached.
+ resolveOnce(ctx context.Context, name string) (value path.Path, ttl time.Duration, err error)
}
// resolve is a helper for implementing Resolver.ResolveN using resolveOnce.
-func resolve(ctx context.Context, r resolver, name string, depth int, prefixes ...string) (path.Path, error) {
+func resolve(ctx context.Context, r resolver, name string, depth int, prefixes ...string) (path.Path, time.Duration, error) {
+ // Start with a long TTL.
+ ttl := ImmutableTTL
+
for {
- p, err := r.resolveOnce(ctx, name)
+ p, ttlOnce, err := r.resolveOnce(ctx, name)
+ // Use the lowest TTL reported by the resolveOnce invocations.
+ if ttlOnce < ttl {
+ ttl = ttlOnce
+ }
if err != nil {
log.Warningf("Could not resolve %s", name)
- return "", err
+ return "", ttl, err
}
- log.Debugf("Resolved %s to %s", name, p.String())
+ log.Debugf("Resolved %s to %s (TTL %v -> %v)", name, p.String(), ttlOnce, ttl)
if strings.HasPrefix(p.String(), "/ipfs/") {
// we've bottomed out with an IPFS path
- return p, nil
+ return p, ttl, nil
}
if depth == 1 {
- return p, ErrResolveRecursion
+ return p, ttl, ErrResolveRecursion
}
matched := false
@@ -44,7 +54,7 @@ func resolve(ctx context.Context, r resolver, name string, depth int, prefixes .
}
if !matched {
- return p, nil
+ return p, ttl, nil
}
if depth > 1 { |
@ion1 yeah, we could return a ttl with every resolution... I'm generally against more return types than 1+error, but this is likely a cleaner approach than others |
I’m going to do that then. |
Closes ipfs/go-ipfs#1818. License: MIT Signed-off-by: Johan Kiviniemi <[email protected]>
Closes ipfs/go-ipfs#1818. License: MIT Signed-off-by: Johan Kiviniemi <[email protected]>
Closes ipfs/go-ipfs#1818. License: MIT Signed-off-by: Johan Kiviniemi <[email protected]>
Closes ipfs/go-ipfs#1818. License: MIT Signed-off-by: Johan Kiviniemi <[email protected]>
Closes ipfs/go-ipfs#1818. License: MIT Signed-off-by: Johan Kiviniemi <[email protected]>
Closes ipfs/go-ipfs#1818. License: MIT Signed-off-by: Johan Kiviniemi <[email protected]>
Closes ipfs/go-ipfs#1818. License: MIT Signed-off-by: Johan Kiviniemi <[email protected]>
Closes ipfs/go-ipfs#1818. License: MIT Signed-off-by: Johan Kiviniemi <[email protected]>
Closes ipfs/go-ipfs#1818. License: MIT Signed-off-by: Johan Kiviniemi <[email protected]>
Closes ipfs/go-ipfs#1818. License: MIT Signed-off-by: Johan Kiviniemi <[email protected]>
Just for the record, this is still an open issue for
AFAIK it could be either:
Why? Due to this we should provide explicit cache expiration headers for |
This will sort-of depend on ipfs/kubo#5884, as ipns supports dns resolution too. 'Real' IPNS records support TTL too, but AFAIK it's currently not used (basically it's set to 0). |
Reopening. We have spec at https://specs.ipfs.tech/http-gateways/path-gateway/#cache-control-response-header, but This is not fixed fully yet. IPNS Records are handled correctly thanks to #459 but we don't set Remaining work here
|
For DNSLink, what would you recommend the |
Good question. Unless there is a better value, I suggest using Amino DHT expiration window (48h) in cases like this, where we need a sensible hard ceiling on caching mutable things. Rationale: DNSLink resolves to some CID. Returning a cached HTTP response body is ok as long the the data behind that CID could be (in theory) retrievable from the public swarm provider. So if we count from the moment we resolved dnslink and successfully retrieved it, 48h is the max window we can assume the retrieval of the same payload would be successful. |
just a precaution, since we still have TTL=0 for many DNSLink responses due to #329 (comment)
) * fix(gateway): Cache-Control header for UnixFS directories * fix: limit static cache-control to /ipfs just a precaution, since we still have TTL=0 for many DNSLink responses due to #329 (comment) --------- Co-authored-by: Joshua Noble <[email protected]>
…pfs#643) * fix(gateway): Cache-Control header for UnixFS directories * fix: limit static cache-control to /ipfs just a precaution, since we still have TTL=0 for many DNSLink responses due to ipfs#329 (comment) --------- Co-authored-by: Joshua Noble <[email protected]>
The gateway does not seem to provide a Cache-Control/max-age header or an ETag for
/ipns
URLs.It might be useful to assume some reasonable non-zero max-age for content on IPNS. A minute? Fifteen seconds?
It would also be good to serve an ETag corresponding to whatever IPFS hash the IPNS path resolved to.
The text was updated successfully, but these errors were encountered: