Skip to content

Commit d654141

Browse files
author
Michal Witkowski
committed
update README
1 parent f457856 commit d654141

File tree

2 files changed

+46
-40
lines changed

2 files changed

+46
-40
lines changed

README.md

Lines changed: 45 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,59 @@
11
# gRPC Proxy
22

3-
This is an implementation of a [gRPC](http://www.grpc.io/) Proxying Server in Golang, based on [grpc-go](https://github.com/grpc/grpc-go). Features:
4-
5-
* full support for all Streams: Unitary RPCs and Streams: One-Many, Many-One, Many-Many
6-
* pass-through mode: no overhead of encoding/decoding messages
7-
* customizable `StreamDirector` routing based on `context.Context` of the `Stream`, allowing users to return
8-
a `grpc.ClientConn` after dialing the backend of choice based on:
9-
- inspection of service and method name
10-
- inspection of user credentials in `authorization` header
11-
- inspection of custom user-features
12-
- inspection of TLS client cert credentials
13-
* integration tests
14-
15-
## Example Use
16-
17-
```go
3+
[![Travis Build](https://travis-ci.org/mwitkow/go-proxy.svg?branch=master)](https://travis-ci.org/mwitkow/go-proxy)
4+
[![Go Report Card](https://goreportcard.com/badge/github.com/mwitkow/go-proxy)](https://goreportcard.com/report/github.com/mwitkow/go-proxy)
5+
[![GoDoc](http://img.shields.io/badge/GoDoc-Reference-blue.svg)](https://godoc.org/github.com/mwitkow/go-proxy)
6+
[![Apache 2.0 License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)
187

19-
director := func(ctx context.Context) (*grpc.ClientConn, error) {
20-
if err := CheckBearerToken(ctx); err != nil {
21-
return nil, grpc.Errorf(codes.PermissionDenied, "unauthorized access: %v", err)
22-
}
23-
stream, _ := transport.StreamFromContext(ctx)
24-
backend, found := PreDialledBackends[stream.Method()];
25-
if !found {
26-
return nil, grpc.Errorf(codes.Unimplemented, "the service %v is not implemented", stream.Method)
27-
}
28-
return backend, nil
29-
}
8+
[gRPC Go](https://github.com/grpc/grpc-go) Proxy server
309

31-
proxy := grpcproxy.NewProxy(director)
32-
proxy.Server(boundListener)
33-
```
10+
## Project Goal
3411

35-
## Status
12+
Build a transparent reverse proxy for gRPC targets that will make it easy to expose gRPC services
13+
over the internet. This includes:
14+
* no needed knowledge of the semantics of requests exchanged in the call (independent rollouts)
15+
* easy, declarative definition of backends and their mappings to frontends
16+
* simple round-robin load balancing of inbound requests from a single connection to multiple backends
3617

37-
This is *alpha* software, written as a proof of concept. It has been integration-tested, but please expect bugs.
18+
The project now exists as a **proof of concept**, with the key piece being the `proxy` package that
19+
is a generic gRPC reverse proxy handler.
3820

39-
The current implementation depends on a public interface to `ClientConn.Picker()`, which hopefully will be upstreamed in [grpc-go#397](https://github.com/grpc/grpc-go/pull/397).
40-
21+
## Proxy Handler
4122

42-
## Contributors
23+
The package [`proxy`](proxy/) contains a generic gRPC reverse proxy handler that allows a gRPC server to
24+
not know about registered handlers or their data types. Please consult the docs, here's an exaple usage.
4325

44-
Names in no particular order:
26+
Defining a `StreamDirector` that decides where (if at all) to send the request
27+
```go
28+
director = func(ctx context.Context, fullMethodName string) (*grpc.ClientConn, error) {
29+
// Make sure we never forward internal services.
30+
if strings.HasPrefix(fullMethodName, "/com.example.internal.") {
31+
return nil, grpc.Errorf(codes.Unimplemented, "Unknown method")
32+
}
33+
md, ok := metadata.FromContext(ctx)
34+
if ok {
35+
// Decide on which backend to dial
36+
if val, exists := md[":authority"]; exists && val[0] == "staging.api.example.com" {
37+
// Make sure we use DialContext so the dialing can be cancelled/time out together with the context.
38+
return grpc.DialContext(ctx, "api-service.staging.svc.local", grpc.WithCodec(proxy.Codec()))
39+
} else if val, exists := md[":authority"]; exists && val[0] == "api.example.com" {
40+
return grpc.DialContext(ctx, "api-service.prod.svc.local", grpc.WithCodec(proxy.Codec()))
41+
}
42+
}
43+
return nil, grpc.Errorf(codes.Unimplemented, "Unknown method")
44+
}
45+
```
46+
Then you need to register it with a `grpc.Server`. The server may have other handlers that will be served
47+
locally:
4548

46-
* [mwitkow](https://github.com/mwitkow)
49+
```go
50+
server := grpc.NewServer(
51+
grpc.CustomCodec(proxy.Codec()),
52+
grpc.UnknownServiceHandler(proxy.TransparentHandler(director)))
53+
pb_test.RegisterTestServiceServer(server, &testImpl{})
54+
```
4755

4856
## License
4957

50-
`grpc-proxy` is released under the Apache 2.0 license. See [LICENSE.txt](https://github.com/spf13/mwitkow-io/blob/grpcproxy/LICENSE.txt).
51-
58+
`grpc-proxy` is released under the Apache 2.0 license. See [LICENSE.txt](LICENSE.txt).
5259

53-
Part of the main server loop are lifted from the [grpc-go](https://github.com/grpc/grpc-go) `Server`, which is copyrighted Google Inc. and licensed under MIT license.

proxy/handler_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ func (s *ProxyHappySuite) SetupSuite() {
162162
pb.RegisterTestServiceServer(s.server, &assertingService{t: s.T()})
163163

164164
// Setup of the proxy's Director.
165-
proxyClientConn, err := grpc.Dial(s.serverListener.Addr().String(), grpc.WithInsecure(), grpc.WithCodec(proxy))
165+
proxyClientConn, err := grpc.Dial(s.serverListener.Addr().String(), grpc.WithInsecure(), grpc.WithCodec(proxy.Codec()))
166166
require.NoError(s.T(), err, "must not error on deferred client Dial")
167167
director := func(ctx context.Context, fullName string) (*grpc.ClientConn, error) {
168168
md, ok := metadata.FromContext(ctx)

0 commit comments

Comments
 (0)