1
0
mirror of https://github.com/ipfs/kubo.git synced 2025-05-21 00:47:22 +08:00
Files
kubo/core/corehttp/gateway.go
Gus Eggert f855bfe6ef feat: add basic gateway tracing (#8595)
* add deprecation warning when tracer plugins are loaded
* add response format attribute to span in gateway handler
* add note about tracing's experimental status in godoc
* add nil check for TTL when adding name span attrs
* add basic sharness test for integration with otel collector
* add nil check in UnixFSAPI.processLink
* test: sharness check all json objs for swarm span
* add env var docs to docs/environment-variables.md
* chore: pin the otel collector version
* add tracing spans per response type (#8841)
* docs: tracing with jaeger-ui

Co-authored-by: Marcin Rataj <lidel@lidel.org>
2022-04-04 19:24:05 +02:00

116 lines
2.9 KiB
Go

package corehttp
import (
"fmt"
"net"
"net/http"
"sort"
version "github.com/ipfs/go-ipfs"
core "github.com/ipfs/go-ipfs/core"
coreapi "github.com/ipfs/go-ipfs/core/coreapi"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
options "github.com/ipfs/interface-go-ipfs-core/options"
id "github.com/libp2p/go-libp2p/p2p/protocol/identify"
)
type GatewayConfig struct {
Headers map[string][]string
Writable bool
PathPrefixes []string
}
// A helper function to clean up a set of headers:
// 1. Canonicalizes.
// 2. Deduplicates.
// 3. Sorts.
func cleanHeaderSet(headers []string) []string {
// Deduplicate and canonicalize.
m := make(map[string]struct{}, len(headers))
for _, h := range headers {
m[http.CanonicalHeaderKey(h)] = struct{}{}
}
result := make([]string, 0, len(m))
for k := range m {
result = append(result, k)
}
// Sort
sort.Strings(result)
return result
}
func GatewayOption(writable bool, paths ...string) ServeOption {
return func(n *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
cfg, err := n.Repo.Config()
if err != nil {
return nil, err
}
api, err := coreapi.NewCoreAPI(n, options.Api.FetchBlocks(!cfg.Gateway.NoFetch))
if err != nil {
return nil, err
}
headers := make(map[string][]string, len(cfg.Gateway.HTTPHeaders))
for h, v := range cfg.Gateway.HTTPHeaders {
headers[http.CanonicalHeaderKey(h)] = v
}
// Hard-coded headers.
const ACAHeadersName = "Access-Control-Allow-Headers"
const ACEHeadersName = "Access-Control-Expose-Headers"
const ACAOriginName = "Access-Control-Allow-Origin"
const ACAMethodsName = "Access-Control-Allow-Methods"
if _, ok := headers[ACAOriginName]; !ok {
// Default to *all*
headers[ACAOriginName] = []string{"*"}
}
if _, ok := headers[ACAMethodsName]; !ok {
// Default to GET
headers[ACAMethodsName] = []string{http.MethodGet}
}
headers[ACAHeadersName] = cleanHeaderSet(
append([]string{
"Content-Type",
"User-Agent",
"Range",
"X-Requested-With",
}, headers[ACAHeadersName]...))
headers[ACEHeadersName] = cleanHeaderSet(
append([]string{
"Content-Range",
"X-Chunked-Output",
"X-Stream-Output",
}, headers[ACEHeadersName]...))
var gateway http.Handler = newGatewayHandler(GatewayConfig{
Headers: headers,
Writable: writable,
PathPrefixes: cfg.Gateway.PathPrefixes,
}, api)
gateway = otelhttp.NewHandler(gateway, "Gateway.Request")
for _, p := range paths {
mux.Handle(p+"/", gateway)
}
return mux, nil
}
}
func VersionOption() ServeOption {
return func(_ *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
mux.HandleFunc("/version", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Commit: %s\n", version.CurrentCommit)
fmt.Fprintf(w, "Client Version: %s\n", version.GetUserAgentVersion())
fmt.Fprintf(w, "Protocol Version: %s\n", id.LibP2PVersion)
})
return mux, nil
}
}