Skip to content

Commit 1badd5f

Browse files
authored
feat(gateway): add CORS headers if --cors is provided (#13145)
Allows remote access from a browser sandbox if exposed Closes: #6402
1 parent 29a3d42 commit 1badd5f

File tree

3 files changed

+60
-4
lines changed

3 files changed

+60
-4
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
- feat(f3): integrate cached MapReduce from go-hamt-ipld, which improves performance of F3 power table calculation by 6-10x ([filecoin-project/lotus#13134](https://github.com/filecoin-project/lotus/pull/13134))
1616
- fix(spcli): send SettleDealPayments msg to f05 for `lotus-miner actor settle-deal` ([filecoin-project/lotus#13142](https://github.com/filecoin-project/lotus/pull/13142))
1717
- feat: ExpectedRewardForPower builtin utility function and `lotus-shed miner expected-reward` CLI command ([filecoin-project/lotus#13138](https://github.com/filecoin-project/lotus/pull/13138))
18+
- feat(gateway): add CORS headers if --cors is provided ([filecoin-project/lotus#13145](https://github.com/filecoin-project/lotus/pull/13145))
1819

1920
# Node v1.33.0 / 2025-05-08
2021
The Lotus v1.33.0 release introduces experimental v2 APIs with F3 awareness, featuring a new TipSet selection mechanism that significantly enhances how applications interact with the Filecoin blockchain. This release candidate also adds F3-aware Ethereum APIs via the /v2 endpoint. All of the /v2 APIs implement intelligent fallback mechanisms between F3 and Expected Consensus and are exposed through the Lotus Gateway.

cmd/lotus-gateway/main.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,11 @@ var runCmd = &cli.Command{
162162
Usage: "The maximum number of filters plus subscriptions that a single websocket connection can maintain",
163163
Value: gateway.DefaultEthMaxFiltersPerConn,
164164
},
165+
&cli.BoolFlag{
166+
Name: "cors",
167+
Usage: "Enable CORS headers to allow cross-origin requests from web browsers",
168+
Value: false,
169+
},
165170
},
166171
Action: func(cctx *cli.Context) error {
167172
log.Info("Starting lotus gateway")
@@ -196,6 +201,7 @@ var runCmd = &cli.Command{
196201
rateLimitTimeout = cctx.Duration("rate-limit-timeout")
197202
perHostConnectionsPerMinute = cctx.Int("conn-per-minute")
198203
maxFiltersPerConn = cctx.Int("eth-max-filters-per-conn")
204+
enableCORS = cctx.Bool("cors")
199205
)
200206

201207
serverOptions := make([]jsonrpc.ServerOption, 0)
@@ -230,6 +236,7 @@ var runCmd = &cli.Command{
230236
gateway.WithPerConnectionAPIRateLimit(perConnectionRateLimit),
231237
gateway.WithPerHostConnectionsPerMinute(perHostConnectionsPerMinute),
232238
gateway.WithJsonrpcServerOptions(serverOptions...),
239+
gateway.WithCORS(enableCORS),
233240
)
234241
if err != nil {
235242
return xerrors.Errorf("failed to set up gateway HTTP handler")

gateway/handler.go

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,14 @@ type ShutdownHandler interface {
4141

4242
var _ ShutdownHandler = (*statefulCallHandler)(nil)
4343
var _ ShutdownHandler = (*RateLimitHandler)(nil)
44+
var _ ShutdownHandler = (*CORSHandler)(nil)
4445

4546
// handlerOptions holds the options for the Handler function.
4647
type handlerOptions struct {
4748
perConnectionAPIRateLimit int
4849
perHostConnectionsPerMinute int
4950
jsonrpcServerOptions []jsonrpc.ServerOption
51+
enableCORS bool
5052
}
5153

5254
// HandlerOption is a functional option for configuring the Handler.
@@ -81,6 +83,13 @@ func WithJsonrpcServerOptions(options ...jsonrpc.ServerOption) HandlerOption {
8183
}
8284
}
8385

86+
// WithCORS sets whether to enable CORS headers to allow cross-origin requests from web browsers.
87+
func WithCORS(enable bool) HandlerOption {
88+
return func(opts *handlerOptions) {
89+
opts.enableCORS = enable
90+
}
91+
}
92+
8493
// Handler returns a gateway http.Handler, to be mounted as-is on the server. The handler is
8594
// returned as a ShutdownHandler which allows for graceful shutdown of the handler via its
8695
// Shutdown method.
@@ -123,16 +132,24 @@ func Handler(gateway *Node, options ...HandlerOption) (ShutdownHandler, error) {
123132
m.Handle("/health/readyz", node.NewReadyHandler(gateway.v1Proxy.server))
124133
m.PathPrefix("/").Handler(http.DefaultServeMux)
125134

126-
handler := &statefulCallHandler{m}
135+
var handler http.Handler = &statefulCallHandler{m}
136+
137+
// Apply CORS wrapper if enabled
138+
if opts.enableCORS {
139+
handler = NewCORSHandler(handler)
140+
}
141+
142+
// Apply rate limiting wrapper if enabled
127143
if opts.perConnectionAPIRateLimit > 0 || opts.perHostConnectionsPerMinute > 0 {
128-
return NewRateLimitHandler(
144+
handler = NewRateLimitHandler(
129145
handler,
130146
opts.perConnectionAPIRateLimit,
131147
opts.perHostConnectionsPerMinute,
132148
connectionLimiterCleanupInterval,
133-
), nil
149+
)
134150
}
135-
return handler, nil
151+
152+
return handler.(ShutdownHandler), nil
136153
}
137154

138155
type statefulCallHandler struct {
@@ -287,6 +304,37 @@ func (h *RateLimitHandler) Shutdown(ctx context.Context) error {
287304
return shutdown(ctx, h.next)
288305
}
289306

307+
// CORSHandler handles CORS headers for cross-origin requests.
308+
type CORSHandler struct {
309+
next http.Handler
310+
}
311+
312+
// NewCORSHandler creates a new CORSHandler that wraps the provided handler
313+
// and adds appropriate CORS headers to allow cross-origin requests from web browsers.
314+
func NewCORSHandler(next http.Handler) *CORSHandler {
315+
return &CORSHandler{next: next}
316+
}
317+
318+
func (h *CORSHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
319+
// Set CORS headers
320+
w.Header().Set("Access-Control-Allow-Origin", "*")
321+
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
322+
w.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, Authorization, X-Requested-With")
323+
w.Header().Set("Access-Control-Max-Age", "86400") // 24 hours
324+
325+
// Handle preflight OPTIONS requests
326+
if r.Method == http.MethodOptions {
327+
w.WriteHeader(http.StatusOK)
328+
return
329+
}
330+
331+
h.next.ServeHTTP(w, r)
332+
}
333+
334+
func (h *CORSHandler) Shutdown(ctx context.Context) error {
335+
return shutdown(ctx, h.next)
336+
}
337+
290338
func shutdown(ctx context.Context, handler http.Handler) error {
291339
if sh, ok := handler.(ShutdownHandler); ok {
292340
return sh.Shutdown(ctx)

0 commit comments

Comments
 (0)