Skip to content

Commit 0fc4e2c

Browse files
committed
support header-based routing
Signed-off-by: Joshua Kim <[email protected]>
1 parent f41455f commit 0fc4e2c

File tree

36 files changed

+994
-1001
lines changed

36 files changed

+994
-1001
lines changed

api/connectclient/client.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
2+
// See the file LICENSE for licensing terms.
3+
4+
package connectclient
5+
6+
import (
7+
"context"
8+
9+
"connectrpc.com/connect"
10+
11+
"github.com/ava-labs/avalanchego/api/server"
12+
)
13+
14+
var _ connect.Interceptor = (*SetRouteHeaderInterceptor)(nil)
15+
16+
// SetRouteHeaderInterceptor sets the api routing header for connect-rpc
17+
// requests
18+
type SetRouteHeaderInterceptor struct {
19+
Route string
20+
}
21+
22+
func (s SetRouteHeaderInterceptor) WrapUnary(next connect.UnaryFunc) connect.UnaryFunc {
23+
return func(ctx context.Context, request connect.AnyRequest) (connect.AnyResponse, error) {
24+
request.Header().Set(server.HTTPHeaderRoute, s.Route)
25+
return next(ctx, request)
26+
}
27+
}
28+
29+
func (s SetRouteHeaderInterceptor) WrapStreamingClient(next connect.StreamingClientFunc) connect.StreamingClientFunc {
30+
return func(ctx context.Context, spec connect.Spec) connect.StreamingClientConn {
31+
conn := next(ctx, spec)
32+
conn.RequestHeader().Set(server.HTTPHeaderRoute, s.Route)
33+
return conn
34+
}
35+
}
36+
37+
func (SetRouteHeaderInterceptor) WrapStreamingHandler(next connect.StreamingHandlerFunc) connect.StreamingHandlerFunc {
38+
return func(ctx context.Context, conn connect.StreamingHandlerConn) error {
39+
return next(ctx, conn)
40+
}
41+
}

api/grpcclient/client.go

Lines changed: 0 additions & 71 deletions
This file was deleted.

api/server/http2_router.go

Lines changed: 0 additions & 57 deletions
This file was deleted.

api/server/http2_router_test.go

Lines changed: 0 additions & 71 deletions
This file was deleted.

api/server/router.go

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import (
1414
"github.com/ava-labs/avalanchego/utils/set"
1515
)
1616

17+
const HTTPHeaderRoute = "Avalanche-Api-Route"
18+
1719
var (
1820
errUnknownBaseURL = errors.New("unknown base url")
1921
errUnknownEndpoint = errors.New("unknown endpoint")
@@ -25,16 +27,21 @@ type router struct {
2527
router *mux.Router
2628

2729
routeLock sync.Mutex
28-
reservedRoutes set.Set[string] // Reserves routes so that there can't be alias that conflict
29-
aliases map[string][]string // Maps a route to a set of reserved routes
30-
routes map[string]map[string]http.Handler // Maps routes to a handler
30+
reservedRoutes set.Set[string] // Reserves routes so that there can't be alias that conflict
31+
aliases map[string][]string // Maps a route to a set of reserved routes
32+
// headerRoutes contains routes based on http headers
33+
// aliasing is not currently supported
34+
headerRoutes map[string]http.Handler
35+
// legacy url-based routing
36+
routes map[string]map[string]http.Handler // Maps routes to a handler
3137
}
3238

3339
func newRouter() *router {
3440
return &router{
3541
router: mux.NewRouter(),
3642
reservedRoutes: set.Set[string]{},
3743
aliases: make(map[string][]string),
44+
headerRoutes: make(map[string]http.Handler),
3845
routes: make(map[string]map[string]http.Handler),
3946
}
4047
}
@@ -43,7 +50,28 @@ func (r *router) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
4350
r.lock.RLock()
4451
defer r.lock.RUnlock()
4552

46-
r.router.ServeHTTP(writer, request)
53+
route, ok := request.Header[HTTPHeaderRoute]
54+
if !ok {
55+
// If there is no routing header, fall-back to the legacy path-based
56+
// routing
57+
r.router.ServeHTTP(writer, request)
58+
return
59+
}
60+
61+
// Request specified the routing header key but did not provide a
62+
// corresponding value
63+
if len(route) != 1 {
64+
writer.WriteHeader(http.StatusBadRequest)
65+
return
66+
}
67+
68+
handler, ok := r.headerRoutes[route[0]]
69+
if !ok {
70+
writer.WriteHeader(http.StatusNotFound)
71+
return
72+
}
73+
74+
handler.ServeHTTP(writer, request)
4775
}
4876

4977
func (r *router) GetHandler(base, endpoint string) (http.Handler, error) {
@@ -61,6 +89,16 @@ func (r *router) GetHandler(base, endpoint string) (http.Handler, error) {
6189
return handler, nil
6290
}
6391

92+
func (r *router) AddHeaderRoute(route string, handler http.Handler) bool {
93+
_, ok := r.headerRoutes[route]
94+
if ok {
95+
return false
96+
}
97+
98+
r.headerRoutes[route] = handler
99+
return true
100+
}
101+
64102
func (r *router) AddRouter(base, endpoint string, handler http.Handler) error {
65103
r.lock.Lock()
66104
defer r.lock.Unlock()

0 commit comments

Comments
 (0)