-
Notifications
You must be signed in to change notification settings - Fork 12
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
feat: add header for skipping the blockcache #152
Changes from 5 commits
2dc6bed
a0b0290
9f87182
c0447ab
ec34d2e
103335f
511492a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,21 @@ | ||
## `Authorization` | ||
|
||
Optional request header that guards per-request tracing features. | ||
Optional request header that guards per-request tracing and debugging features. | ||
|
||
See [`RAINBOW_TRACING_AUTH`](./environment-variables.md#rainbow_tracing_auth) | ||
|
||
## `Traceparent` | ||
|
||
See [`RAINBOW_TRACING_AUTH`](./environment-variables.md#rainbow_tracing_auth) | ||
|
||
## `Tracestate` | ||
|
||
See [`RAINBOW_TRACING_AUTH`](./environment-variables.md#rainbow_tracing_auth) | ||
|
||
## Rainbow-No-Blockcache | ||
|
||
If the value is `true` the associated request will skip the local block cache and leverage a separate in-memory block cache for the request. | ||
|
||
This header is not respected unless the request has a valid `Authorization` header | ||
|
||
See [`RAINBOW_TRACING_AUTH`](./environment-variables.md#rainbow_tracing_auth) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,17 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"fmt" | ||
"net/http" | ||
"os" | ||
"runtime" | ||
"strconv" | ||
|
||
"github.com/ipfs/boxo/blockstore" | ||
leveldb "github.com/ipfs/go-ds-leveldb" | ||
|
||
_ "embed" | ||
_ "net/http/pprof" | ||
|
||
|
@@ -84,7 +88,7 @@ | |
}) | ||
} | ||
|
||
func setupGatewayHandler(cfg Config, nd *Node, tracingAuth string) (http.Handler, error) { | ||
func setupGatewayHandler(cfg Config, nd *Node) (http.Handler, error) { | ||
var ( | ||
backend gateway.IPFSBackend | ||
err error | ||
|
@@ -175,8 +179,15 @@ | |
NoDNSLink: noDNSLink, | ||
} | ||
gwHandler := gateway.NewHandler(gwConf, backend) | ||
ipfsHandler := withHTTPMetrics(gwHandler, "ipfs") | ||
ipnsHandler := withHTTPMetrics(gwHandler, "ipns") | ||
|
||
var ipfsHandler, ipnsHandler http.Handler | ||
if cfg.disableMetrics { | ||
ipfsHandler = gwHandler | ||
ipnsHandler = gwHandler | ||
} else { | ||
ipfsHandler = withHTTPMetrics(gwHandler, "ipfs") | ||
ipnsHandler = withHTTPMetrics(gwHandler, "ipns") | ||
} | ||
|
||
topMux := http.NewServeMux() | ||
topMux.Handle("/ipfs/", ipfsHandler) | ||
|
@@ -206,25 +217,50 @@ | |
handler = withRequestLogger(handler) | ||
|
||
// Add tracing. | ||
handler = otelhttp.NewHandler(handler, "Gateway") | ||
handler = withTracingAndDebug(handler, cfg) | ||
|
||
// Remove tracing headers if not authorized | ||
prevHandler := handler | ||
handler = http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { | ||
if request.Header.Get("Authorization") != tracingAuth { | ||
return handler, nil | ||
} | ||
|
||
func withTracingAndDebug(next http.Handler, cfg Config) http.Handler { | ||
next = otelhttp.NewHandler(next, "Gateway") | ||
authToken := cfg.TracingAuthToken | ||
|
||
// Remove tracing and cache skipping headers if not authorized | ||
return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { | ||
// Disable tracing/debug headers if auth token missing or invalid | ||
if authToken == "" || request.Header.Get("Authorization") != authToken { | ||
if request.Header.Get("Traceparent") != "" { | ||
request.Header.Del("Traceparent") | ||
} | ||
if request.Header.Get("Tracestate") != "" { | ||
request.Header.Del("Tracestate") | ||
} | ||
if request.Header.Get(NoBlockcacheHeader) != "" { | ||
request.Header.Del(NoBlockcacheHeader) | ||
} | ||
} | ||
prevHandler.ServeHTTP(writer, request) | ||
}) | ||
|
||
return handler, nil | ||
// Process cache skipping header | ||
if noBlockCache := request.Header.Get(NoBlockcacheHeader); noBlockCache == "true" { | ||
ds, err := leveldb.NewDatastore("", nil) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This bring in leveldb as a dependency, but IIRC the levelDB memory datastore behaves a bunch better under parallel block writing/fetching load compared to the mapdatastore + sync datastore wrapper. I don't expect this to be used a ton either way, so if people disagree I'm ok switching to the more basic datastore. |
||
if err != nil { | ||
writer.WriteHeader(http.StatusInternalServerError) | ||
_, _ = writer.Write([]byte(err.Error())) | ||
return | ||
} | ||
newCtx := context.WithValue(request.Context(), NoBlockcache{}, blockstore.NewBlockstore(ds)) | ||
request = request.WithContext(newCtx) | ||
} | ||
|
||
next.ServeHTTP(writer, request) | ||
}) | ||
} | ||
|
||
const NoBlockcacheHeader = "Rainbow-No-Blockcache" | ||
lidel marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
type NoBlockcache struct{} | ||
|
||
// MutexFractionOption allows to set runtime.SetMutexProfileFraction via HTTP | ||
// using POST request with parameter 'fraction'. | ||
func MutexFractionOption(path string, mux *http.ServeMux) *http.ServeMux { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -71,7 +71,7 @@ func mustTestNodeWithKey(t *testing.T, cfg Config, sk ic.PrivKey) *Node { | |
func mustTestServer(t *testing.T, cfg Config) (*httptest.Server, *Node) { | ||
nd := mustTestNode(t, cfg) | ||
|
||
handler, err := setupGatewayHandler(cfg, nd, "") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ℹ️ I've moved the token to |
||
handler, err := setupGatewayHandler(cfg, nd) | ||
if err != nil { | ||
require.NoError(t, err) | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ℹ️ First check ensures tracing and debug is disabled by default when
Authorization
is missing ANDRAINBOW_TRACING_AUTH
being empty/unset.Added a test too, just as a precaution, we don't want to have tracing enabled by default config. We may relax that in the future, but for now better to guard it behind the token, always.