Skip to content

Commit

Permalink
fix: add proper CONNECT support to examples, common http handler
Browse files Browse the repository at this point in the history
  • Loading branch information
hacdias committed Mar 31, 2023
1 parent 6278e83 commit 2835752
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 97 deletions.
37 changes: 1 addition & 36 deletions examples/gateway/car/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion examples/gateway/car/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
22 changes: 0 additions & 22 deletions examples/gateway/common/blocks.go

This file was deleted.

81 changes: 81 additions & 0 deletions examples/gateway/common/handler.go
Original file line number Diff line number Diff line change
@@ -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)
})
}
37 changes: 1 addition & 36 deletions examples/gateway/proxy/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions examples/gateway/proxy/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand All @@ -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)

Expand Down

0 comments on commit 2835752

Please sign in to comment.