From 2d5fa7288a48d1c838f8494764527d3cfb43b8a9 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Thu, 30 Mar 2023 18:57:54 +0200 Subject: [PATCH 1/2] ci: enable subdomain conformance tests --- .github/workflows/gateway-conformance.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gateway-conformance.yml b/.github/workflows/gateway-conformance.yml index b44484ce5..899b90f7f 100644 --- a/.github/workflows/gateway-conformance.yml +++ b/.github/workflows/gateway-conformance.yml @@ -47,7 +47,7 @@ jobs: xml: output.xml html: output.html markdown: output.md - specs: -subdomain-gateway + subdomain-url: http://example.net args: -skip 'TestGatewayCar/GET_response_for_application/vnd.ipld.car/Header_Content-Length' # 5. Upload the results From 725a8f4d15dcd80b57eb2b4ddfb63828858258bb Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Thu, 30 Mar 2023 18:59:29 +0200 Subject: [PATCH 2/2] fix: add proper CONNECT support to examples, common http handler --- examples/gateway/car/main.go | 37 +------------ examples/gateway/car/main_test.go | 2 +- examples/gateway/common/blocks.go | 22 -------- examples/gateway/common/handler.go | 81 +++++++++++++++++++++++++++++ examples/gateway/proxy/main.go | 37 +------------ examples/gateway/proxy/main_test.go | 4 +- 6 files changed, 86 insertions(+), 97 deletions(-) delete mode 100644 examples/gateway/common/blocks.go create mode 100644 examples/gateway/common/handler.go diff --git a/examples/gateway/car/main.go b/examples/gateway/car/main.go index 3f8e16b20..fb3c50e2b 100644 --- a/examples/gateway/car/main.go +++ b/examples/gateway/car/main.go @@ -14,8 +14,6 @@ import ( "github.com/ipfs/boxo/gateway" carblockstore "github.com/ipfs/boxo/ipld/car/v2/blockstore" "github.com/ipfs/go-cid" - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/promhttp" ) func main() { @@ -33,41 +31,8 @@ func main() { if err != nil { log.Fatal(err) } - handler := common.NewBlocksHandler(gwAPI, *port) - // Initialize the public gateways that we will want to have available through - // Host header rewritting. This step is optional and only required if you're - // running multiple public gateways and want different settings and support - // for DNSLink and Subdomain Gateways. - noDNSLink := false // If you set DNSLink to point at the CID from CAR, you can load it! - publicGateways := map[string]*gateway.Specification{ - // Support public requests with Host: CID.ipfs.example.net and ID.ipns.example.net - "example.net": { - Paths: []string{"/ipfs", "/ipns"}, - NoDNSLink: noDNSLink, - UseSubdomains: true, - }, - // Support local requests - "localhost": { - Paths: []string{"/ipfs", "/ipns"}, - NoDNSLink: noDNSLink, - UseSubdomains: true, - }, - } - - // Creates a mux to serve the prometheus metrics alongside the gateway. This - // step is optional and only required if you need or want to access the metrics. - // You may also decide to expose the metrics on a different path, or port. - mux := http.NewServeMux() - mux.Handle("/debug/metrics/prometheus", promhttp.HandlerFor(prometheus.DefaultGatherer, promhttp.HandlerOpts{})) - mux.Handle("/", handler) - - // Then wrap the mux with the hostname handler. Please note that the metrics - // will not be available under the previously defined publicGateways. - // You will be able to access the metrics via 127.0.0.1 but not localhost - // or example.net. If you want to expose the metrics on such gateways, - // you will have to add the path "/debug" to the variable Paths. - handler = gateway.WithHostname(mux, gwAPI, publicGateways, noDNSLink) + handler := common.NewHandler(gwAPI) log.Printf("Listening on http://localhost:%d", *port) log.Printf("Metrics available at http://127.0.0.1:%d/debug/metrics/prometheus", *port) diff --git a/examples/gateway/car/main_test.go b/examples/gateway/car/main_test.go index 71bcfbd80..6226c028e 100644 --- a/examples/gateway/car/main_test.go +++ b/examples/gateway/car/main_test.go @@ -29,7 +29,7 @@ func newTestServer() (*httptest.Server, io.Closer, error) { return nil, nil, err } - handler := common.NewBlocksHandler(gateway, 0) + handler := common.NewHandler(gateway) ts := httptest.NewServer(handler) return ts, f, nil } diff --git a/examples/gateway/common/blocks.go b/examples/gateway/common/blocks.go deleted file mode 100644 index e95405de0..000000000 --- a/examples/gateway/common/blocks.go +++ /dev/null @@ -1,22 +0,0 @@ -package common - -import ( - "net/http" - - "github.com/ipfs/boxo/gateway" -) - -func NewBlocksHandler(gw gateway.IPFSBackend, port int) http.Handler { - headers := map[string][]string{} - gateway.AddAccessControlHeaders(headers) - - conf := gateway.Config{ - Headers: headers, - } - - mux := http.NewServeMux() - gwHandler := gateway.NewHandler(conf, gw) - mux.Handle("/ipfs/", gwHandler) - mux.Handle("/ipns/", gwHandler) - return mux -} diff --git a/examples/gateway/common/handler.go b/examples/gateway/common/handler.go new file mode 100644 index 000000000..a6fd42839 --- /dev/null +++ b/examples/gateway/common/handler.go @@ -0,0 +1,81 @@ +package common + +import ( + "net/http" + + "github.com/ipfs/boxo/gateway" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promhttp" +) + +func NewHandler(gwAPI gateway.IPFSBackend) http.Handler { + // Initialize the headers and gateway configuration. For this example, we do + // not add any special headers, but the required ones. + headers := map[string][]string{} + gateway.AddAccessControlHeaders(headers) + conf := gateway.Config{ + Headers: headers, + } + + // Initialize the public gateways that we will want to have available through + // Host header rewriting. This step is optional and only required if you're + // running multiple public gateways and want different settings and support + // for DNSLink and Subdomain Gateways. + noDNSLink := false // If you set DNSLink to point at the CID from CAR, you can load it! + publicGateways := map[string]*gateway.Specification{ + // Support public requests with Host: CID.ipfs.example.net and ID.ipns.example.net + "example.net": { + Paths: []string{"/ipfs", "/ipns"}, + NoDNSLink: noDNSLink, + UseSubdomains: true, + }, + // Support local requests + "localhost": { + Paths: []string{"/ipfs", "/ipns"}, + NoDNSLink: noDNSLink, + UseSubdomains: true, + }, + } + + // Creates a mux to serve the gateway paths. This is not strictly necessary + // and gwHandler could be used directly. However, on the next step we also want + // to add prometheus metrics, hence needing the mux. + gwHandler := gateway.NewHandler(conf, gwAPI) + mux := http.NewServeMux() + mux.Handle("/ipfs/", gwHandler) + mux.Handle("/ipns/", gwHandler) + + // Serves prometheus metrics alongside the gateway. This step is optional and + // only required if you need or want to access the metrics. You may also decide + // to expose the metrics on a different path, or port. + mux.Handle("/debug/metrics/prometheus", promhttp.HandlerFor(prometheus.DefaultGatherer, promhttp.HandlerOpts{})) + + // Then wrap the mux with the hostname handler. Please note that the metrics + // will not be available under the previously defined publicGateways. + // You will be able to access the metrics via 127.0.0.1 but not localhost + // or example.net. If you want to expose the metrics on such gateways, + // you will have to add the path "/debug" to the variable Paths. + var handler http.Handler + handler = gateway.WithHostname(mux, gwAPI, publicGateways, noDNSLink) + + // Finally, wrap with the withConnect middleware. This is required since we use + // http.ServeMux which does not support CONNECT by default. + handler = withConnect(handler) + + return handler +} + +// withConnect provides a middleware that adds support to the HTTP CONNECT method. +// This is required if the implementer is using http.ServeMux, or some other structure +// that does not support the CONNECT method. It should be applied to the top-level handler. +// https://golang.org/src/net/http/request.go#L111 +func withConnect(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Method == http.MethodConnect { + w.WriteHeader(http.StatusOK) + return + } + + next.ServeHTTP(w, r) + }) +} diff --git a/examples/gateway/proxy/main.go b/examples/gateway/proxy/main.go index 60e2a2c06..a6beeed52 100644 --- a/examples/gateway/proxy/main.go +++ b/examples/gateway/proxy/main.go @@ -10,8 +10,6 @@ import ( "github.com/ipfs/boxo/examples/gateway/common" offline "github.com/ipfs/boxo/exchange/offline" "github.com/ipfs/boxo/gateway" - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/promhttp" ) func main() { @@ -31,41 +29,8 @@ func main() { if err != nil { log.Fatal(err) } - handler := common.NewBlocksHandler(gwAPI, *port) - // Initialize the public gateways that we will want to have available through - // Host header rewritting. This step is optional and only required if you're - // running multiple public gateways and want different settings and support - // for DNSLink and Subdomain Gateways. - noDNSLink := false - publicGateways := map[string]*gateway.Specification{ - // Support public requests with Host: CID.ipfs.example.net and ID.ipns.example.net - "example.net": { - Paths: []string{"/ipfs", "/ipns"}, - NoDNSLink: noDNSLink, - UseSubdomains: true, - }, - // Support local requests - "localhost": { - Paths: []string{"/ipfs", "/ipns"}, - NoDNSLink: noDNSLink, - UseSubdomains: true, - }, - } - - // Creates a mux to serve the prometheus metrics alongside the gateway. This - // step is optional and only required if you need or want to access the metrics. - // You may also decide to expose the metrics on a different path, or port. - mux := http.NewServeMux() - mux.Handle("/debug/metrics/prometheus", promhttp.HandlerFor(prometheus.DefaultGatherer, promhttp.HandlerOpts{})) - mux.Handle("/", handler) - - // Then wrap the mux with the hostname handler. Please note that the metrics - // will not be available under the previously defined publicGateways. - // You will be able to access the metrics via 127.0.0.1 but not localhost - // or example.net. If you want to expose the metrics on such gateways, - // you will have to add the path "/debug" to the variable Paths. - handler = gateway.WithHostname(mux, gwAPI, publicGateways, noDNSLink) + handler := common.NewHandler(gwAPI) log.Printf("Listening on http://localhost:%d", *port) log.Printf("Try loading an image: http://localhost:%d/ipfs/bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi", *port) diff --git a/examples/gateway/proxy/main_test.go b/examples/gateway/proxy/main_test.go index 55a113a4c..3e3accc9b 100644 --- a/examples/gateway/proxy/main_test.go +++ b/examples/gateway/proxy/main_test.go @@ -10,7 +10,7 @@ import ( "github.com/ipfs/boxo/examples/gateway/common" offline "github.com/ipfs/boxo/exchange/offline" "github.com/ipfs/boxo/gateway" - "github.com/ipfs/go-block-format" + blocks "github.com/ipfs/go-block-format" "github.com/stretchr/testify/assert" ) @@ -28,7 +28,7 @@ func newProxyGateway(t *testing.T, rs *httptest.Server) *httptest.Server { t.Error(err) } - handler := common.NewBlocksHandler(gw, 0) + handler := common.NewHandler(gw) ts := httptest.NewServer(handler) t.Cleanup(ts.Close)