提交 4af104ba 作者: Steven Allen

gateway: initial hostname-based routing

Replace IPNSHostname based routing with general-purpose hostname-based routing
that also supports handling requests to "known gateways".

TODO: I'll break KnownGateways out into a config option in a later commit.

License: MIT
Signed-off-by: 's avatarSteven Allen <steven@stebalien.com>
上级 8f2c4405
......@@ -588,7 +588,7 @@ func serveHTTPGateway(req *cmds.Request, cctx *oldcmds.Context) (<-chan error, e
var opts = []corehttp.ServeOption{
corehttp.ProxyOption(), // Proxies all CONNECT requests to self. Always put this first.
corehttp.MetricsCollectionOption("gateway"),
corehttp.IPNSHostnameOption(),
corehttp.HostnameOption(),
corehttp.GatewayOption(writable, "/ipfs", "/ipns"),
corehttp.VersionOption(),
corehttp.CheckVersionOption(),
......
......@@ -34,6 +34,28 @@ const (
ipnsPathPrefix = "/ipns/"
)
type GatewaySpec struct {
// PathPrefixes list the set of path prefixes that should be handled by
// the gateway logic.
PathPrefixes []string
// SupportsSubdomains indicates whether or not this gateway supports
// requests of the form http://CID.ipfs.GATEWAY/...
SupportsSubdomains bool
}
var DefaultGatewaySpec = GatewaySpec{
PathPrefixes: []string{ipfsPathPrefix, ipnsPathPrefix, "/api/"},
SupportsSubdomains: true,
}
// TODO(steb): Configurable
var KnownGateways = map[string]GatewaySpec{
"ipfs.io": DefaultGatewaySpec,
"gateway.ipfs.io": DefaultGatewaySpec,
"localhost:8080": DefaultGatewaySpec,
}
// gatewayHandler is a HTTP handler that serves IPFS objects (accessible by default at /ipfs/<path>)
// (it serves requests like GET /ipfs/QmVRzPKPzNtSrEzBFm2UZfxmPAgnaLke4DMcerbsGGSaFe/link)
type gatewayHandler struct {
......@@ -133,7 +155,7 @@ func (i *gatewayHandler) getOrHeadHandler(ctx context.Context, w http.ResponseWr
}
}
// IPNSHostnameOption might have constructed an IPNS path using the Host header.
// HostnameOption might have constructed an IPNS/IPFS path using the Host header.
// In this case, we need the original path for constructing redirects
// and links that match the requested URL.
// For example, http://example.net would become /ipns/example.net, and
......
......@@ -137,7 +137,7 @@ func newTestServerAndNode(t *testing.T, ns mockNamesys) (*httptest.Server, iface
dh.Handler, err = makeHandler(n,
ts.Listener,
IPNSHostnameOption(),
HostnameOption(),
GatewayOption(false, "/ipfs", "/ipns"),
VersionOption(),
)
......
......@@ -13,26 +13,66 @@ import (
isd "github.com/jbenet/go-is-domain"
)
// IPNSHostnameOption rewrites an incoming request if its Host: header contains
// an IPNS name.
// The rewritten request points at the resolved name on the gateway handler.
func IPNSHostnameOption() ServeOption {
// HostnameOption rewrites an incoming request based on the Host header.
func HostnameOption() ServeOption {
return func(n *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
childMux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithCancel(n.Context())
defer cancel()
host := strings.SplitN(r.Host, ":", 2)[0]
if len(host) > 0 && isd.IsDomain(host) {
name := "/ipns/" + host
_, err := n.Namesys.Resolve(ctx, name, nsopts.Depth(1))
if err == nil || err == namesys.ErrResolveRecursion {
r.URL.Path = name + r.URL.Path
// Is this one of our "known gateways"?
if gw, ok := KnownGateways[r.Host]; ok {
if hasPrefix(r.URL.Path, gw.PathPrefixes...) {
childMux.ServeHTTP(w, r)
return
}
} else if host, pathPrefix, ok := parseSubdomains(r.Host); ok {
if gw, ok := KnownGateways[host]; ok && gw.SupportsSubdomains {
// Always handle this with the gateway.
// We don't care if it's one of the
// valid path-prefixes.
r.URL.Path = pathPrefix + r.URL.Path
childMux.ServeHTTP(w, r)
return
}
}
host := strings.SplitN(r.Host, ":", 2)[0]
if len(host) == 0 || !isd.IsDomain(host) {
childMux.ServeHTTP(w, r)
return
}
name := "/ipns/" + host
_, err := n.Namesys.Resolve(ctx, name, nsopts.Depth(1))
if err == nil || err == namesys.ErrResolveRecursion {
r.URL.Path = name + r.URL.Path
}
childMux.ServeHTTP(w, r)
})
return childMux, nil
}
}
func parseSubdomains(host string) (newHost, pathPrefix string, ok bool) {
parts := strings.SplitN(host, ".", 3)
if len(parts) < 3 {
return "", "", false
}
switch parts[1] {
case "ipfs", "ipns", "p2p":
return parts[2], "/" + parts[1] + "/" + parts[0], true
}
return "", "", false
}
func hasPrefix(s string, prefixes ...string) bool {
for _, prefix := range prefixes {
if strings.HasPrefix(s, prefix) {
return true
}
}
return false
}
......@@ -143,8 +143,6 @@ github.com/ipfs/go-ipfs-chunker v0.0.1 h1:cHUUxKFQ99pozdahi+uSC/3Y6HeRpi9oTeUHbE
github.com/ipfs/go-ipfs-chunker v0.0.1/go.mod h1:tWewYK0we3+rMbOh7pPFGDyypCtvGcBFymgY4rSDLAw=
github.com/ipfs/go-ipfs-cmdkit v0.0.1 h1:X6YXEAjUljTzevE6DPUKXSqcgf+4FXzcn5B957F5MXo=
github.com/ipfs/go-ipfs-cmdkit v0.0.1/go.mod h1:9FtbMdUabcSqv/G4/8WCxSLxkZxn/aZEFrxxqnVcRbg=
github.com/ipfs/go-ipfs-cmds v0.0.3 h1:QvNUE8lslNQghxXf6vzV1ZoMQCDDAtKG8f2oINiRew4=
github.com/ipfs/go-ipfs-cmds v0.0.3/go.mod h1:1QVgxSgenZvOMGVC/XUTC7tJxRBGPLxYvpgPpCi3DUk=
github.com/ipfs/go-ipfs-cmds v0.0.4 h1:Iq4I8irWw5TmHe/4pjSyYJLbYkkdMOgHVe8ofJmPa4k=
github.com/ipfs/go-ipfs-cmds v0.0.4/go.mod h1:1QVgxSgenZvOMGVC/XUTC7tJxRBGPLxYvpgPpCi3DUk=
github.com/ipfs/go-ipfs-config v0.0.1 h1:6ED08emzI1imdsAjixFi2pEyZxTVD5ECKtCOxLBx+Uc=
......@@ -220,8 +218,6 @@ github.com/jbenet/go-cienv v0.0.0-20150120210510-1bb1476777ec h1:DQqZhhDvrTrEQ3Q
github.com/jbenet/go-cienv v0.0.0-20150120210510-1bb1476777ec/go.mod h1:rGaEvXB4uRSZMmzKNLoXvTu1sfx+1kv/DojUlPrSZGs=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/jbenet/go-is-domain v0.0.0-20160119110217-ba9815c809e0 h1:qxMncUW0TzViA3REiN3/YgVOoekVtUtEY0O/j/Qlctg=
github.com/jbenet/go-is-domain v0.0.0-20160119110217-ba9815c809e0/go.mod h1:I9DYFcJAixF5f9iOu/9oC451/bq+QDTaLGznkcJPWgg=
github.com/jbenet/go-is-domain v1.0.2 h1:11r5MSptcNFZyBoqubBQnVMUKRWLuRjL1banaIk+iYo=
github.com/jbenet/go-is-domain v1.0.2/go.mod h1:xbRLRb0S7FgzDBTJlguhDVwLYM/5yNtvktxj2Ttfy7Q=
github.com/jbenet/go-random v0.0.0-20190219211222-123a90aedc0c h1:uUx61FiAa1GI6ZmVd2wf2vULeQZIKG66eybjNXKYCz4=
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论